zaakir.io | blog

My thoughts

From PHP Upload Bypass to KeePass Cracking

Contents

  1. Preface
  2. Walkthrough

Preface

Opacity teaches two techniques that are easy to overlook when reading defensive code.

First — PHP upload filters that key only on the extension can be bypassed with #. When you upload shell.php#a.png, the server's filesystem resolves the filename verbatim and writes shell.php#a.png, but when you request that file via URL the browser/PHP strips everything after the # (it's the URL fragment) and executes shell.php. The naive filter sees .png and waves the upload through. Always validate uploads by content type or sniffing magic bytes, not the trailing characters of the name.

Second — keepass2john + john --wordlist=rockyou.txt will crack a .kdbx master password in seconds if it's weak. A KeePass database file leaked from a misconfigured directory is effectively a plaintext credential dump. If you're using KeePass, the master password is the only thing standing between an attacker and every credential you've ever saved — choose accordingly.

The privesc chain also reinforces a recurring pattern: a root-owned script that includes a file from a directory the unprivileged user can write to is functionally the same as giving that user a root shell.

Walkthrough

Once connected to the box I started by running an nmap scan to identify any active services on the machine.

nmap -sC -sV 10.10.132.80

-sC : default scripts -sV : enumerate versions

Initial Foothold

We are met with a login page.

After a few attempts at default credentials I switched to directory enumeration with ffuf.

ffuf -w /opt/SecLists/Discovery/DNS/subdomains-top1million-20000.txt:FUZZ -u http://10.10.132.80/FUZZ

That surfaced a /cloud directory. Visiting it presented a file upload.

The earlier login page hinted at PHP (login.php), so I aimed for a PHP reverse shell. Python server up, revshell payload crafted via revshells.com, and a netcat listener on the same port.

python3 -m http.server 80
nc -lvp 7777

The upload form rejected .php outright. Trying various image extensions plus a # fragment got through — the filter sees .png, but PHP executes shell.php because URLs strip everything after #.

Calling the URL triggers the reverse shell.

First habit, shell upgrade:

python3 -c 'import pty; pty.spawn("/bin/bash")'

Poking around the filesystem I found a file worth noting: dataset.kdbx — a KeePass database. Standing up a Python server on the box let me pull it back.

python3 -m http.server 80
wget http://10.10.132.80:80/opt/dataset.kdbx

Hash it with keepass2john and crack it with John against rockyou:

keepass2john dataset.kdbx > dataset-hash.txt
john --wordlist=/usr/share/wordlists/rockyou.txt dataset-hash.txt

Opening the .kdbx in KeePass with the cracked password revealed credentials.

The credentials didn't work on login.php, but nmap had shown port 22 open — SSH worked.

ssh sysadmin@10.10.132.80

User flag obtained ✅

Privilege Escalation

Walking the filesystem I spotted script.php, which calls lib/backup.inc.php. sysadmin can't write inside the script's own directory, but the include path itself is writable — meaning I can create a backup.inc.php there and have it picked up the next time the script runs.

I dropped the same reverse-shell PHP into backup.inc.php, started another listener:

nc -lvp 7777

htop showed script.php was running as root on a schedule.

A few seconds later, root shell on the listener. ⛳

THM, Web, Password Cracking

⬅ Previous post
Hijacking Spring Boot Sessions via /actuator

Next post ➡
Setting up a Bug Bounty VPS