美文网首页WEB前端程序开发程序员信息安全
三个白帽之招聘又开始了,你怕了吗 waf部分的writeup

三个白帽之招聘又开始了,你怕了吗 waf部分的writeup

作者: 烤土豆啦 | 来源:发表于2016-12-31 23:48 被阅读0次

    背景:

    这个题目是今年某一期三个白帽的题目,看过之后很感兴趣,于是便还原出来,题目地址

    https://ctf.f4ck0.com/ctf/index.php

    分析:

    上代码:

    
     <?php
    function waf($str) {   
       if(stripos(strtolower($str),"select")!==false)       
               die("Be a good person!");    
       if(stripos(strtolower($str),"union")!==false)        
                die("Be a good person!");
    }
    function wafArr($arr) { 
       foreach ($arr as $k => $v) {
            waf($k);
            waf($v);    
    }}
    wafArr($_GET);
    wafArr($_POST);
    wafArr($_COOKIE);
    wafArr($_SESSION);
    function stripStr($str) {
        if (get_magic_quotes_gpc())
            $str = stripslashes($str);
        $a=addslashes(htmlspecialchars($str, ENT_QUOTES, 'UTF-8'));
        return $a;
    }
    $uri = explode("?",$_SERVER['REQUEST_URI']);
    if(isset($uri[1])) {
        $parameter = explode("&",$uri[1]);
        foreach ($parameter as $k => $v) {
            $v1 = explode("=",$v);
            if (isset($v1[1])) {
                $_REQUEST[$v1[0]] = stripStr($v1[1]); 
           }    
    }}
    var_dump($_REQUEST);
    $con=mysqli_connect("localhost","root","123","demo");
    $result = mysqli_query($con,"SELECT * FROM ctf where user=".$_REQUEST['id'].";");
    echo "</br>";
    var_dump($row = mysqli_fetch_array($result));
    highlight_file('index.php');?>
    
    

    数据库结构

    CREATE TABLE `ctf` ( 
     `user` int(11) DEFAULT NULL, 
     `pass` varchar(255) DEFAULT NULL)
    
    CREATE TABLE `ctf2` (  
    `user` int(11) DEFAULT NULL, 
     `flag is here` varchar(255) DEFAULT NULL)
    

    下面分析一下waf的代码。首先,检查get,post,cookies,这些参数,在这里我只用了简单的字符串匹配。当然了,这块不是重点,这块我只是想强调get,post这些参数被过滤。

    随后进入if 分支,也就是重组request了。首先使用?去分割url。根据规定,?前面是地址,后面是用户所提交的参数。并且将前面所得到的数组的第二个元素,也即是里面是参数的那个,再使用=分割,获取健值,并且将值使用stripStr函数过滤。过滤完成后,重组在系统的REQUEST数组中。

    全部过滤好参数后,再执行数据库语句。

    这个题主要考查的是http参数污染。也就是说同时提交许多参数一样的值,根据环境的不同,将会产生覆盖等问题。例如在本题中,如果提交的参数是?id=1?&id=2的话,apache默认会使用后面的值去覆盖前面的值。所以在php接收get参数的时候,将会接收到id=2,而不是id=1。

    根据上面讲的,我们可以绕过第一个waf的检测。

    第二个是重点,题目把所接收到的url(http://11.com/index.php?id=1)使用?分割,并且使用分割后数组的第二个元素去执行waf过滤。那么问题来了,如果我提交的字符串里面还有一个?呢?(http://11.com/index.php?id=1?&id=2)很简单,会分割成含有三个元素的数组,第一部分含有url地址,第二部分含有id=1,第三部分含有 &id=2,并且第三部分的数据并不会参与任何运算,而且还可以被识别成get所提交的参数。

    所以我们可以提交url中参数为id=xxxxxx?id=1这样的参数去绕过waf检测,在if分支中,会使用url中的id=xxx这段代码去重组,并放入request数组中。看一下下面的数据库执行语句,使用的request数组。所以呢,我们只需要继续分析if分支的过滤代码即可。

    分支中,值将会被addslashes , htmlspecialchars这两个函数过滤。第二个函数是转义html实体编码的,针对于空格,我们使用mysql的注释符号即可绕过/**/。再看第一个函数。第一个函数会将单引号,双引号,反斜杠注释掉,去防止sql注入。那么是否意味着就没有sql注入了呢?再分析一下数据库和所执行的数据库语句,"SELECT * FROM ctf where user=".$_REQUEST['id'].";",而且ctf表的user字段类型是int,题目也恰好不需要单引号和双引号去闭合(参见绕过intval注入)。于是,直接注入即可,不需要考虑addslashes 函数。注意只要不出现单引号和双引号即可注入成功。

    参见payload

    https://ctf.f4ck0.com/ctf/?id=0/**/union/**/select/**/*/**/from/**/ctf2?&id=1
    

    当然了,这个题要是想load_file怎么办呢,文件的路径名必须的用单引号啊。这里我们可以使用字符串转16进制,即可突破限制。

    参见payload
    https://ctf.f4ck0.com/ctf/?id=-1/**/union/**/select/**/1,LOAD_FILE(0x2f6574632f706173737764)?&id=1

    后记

    我在第一次看参考的那两位的wp时候并没有直接看懂,因为有点问题,说的比较笼统。尤其是这句话

    当然waf不生效了,而在重组$_REQUEST
    时,覆盖并没有发生,所以注入语句顺利的被执行

    所以根本不需要怼waf,uri被处理后,GET
    _REQUEST的值可以不一样,然后直接注入就好了

    尤其困惑,而且看payload,也没说出个所以然来。于是根据博客中提供的代码,还原部分环境去本地测试。结果发现题目中好多巧合,才导致的addslashes的绕过。其实如果这道题稍微做一下改动,两位表哥所分析的可能就不对了。所以我在这里写下详细的分析过程,帮助其他人学习。😄

    参考:

    1. http://0x48.pw/2016/06/17/0x1C/

    2. http://www.firesun.me/san-ge-bai-mao-zhi-zhao-pin-you-kai-shi-liao-ni-pa-liao-ma-writeup/

    3. http://huaidan.org/archives/3047.html

    相关文章

      网友评论

        本文标题:三个白帽之招聘又开始了,你怕了吗 waf部分的writeup

        本文链接:https://www.haomeiwen.com/subject/rnybvttx.html