WEB前端程序开发程序员信息安全

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

2016-12-31  本文已影响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

上一篇下一篇

猜你喜欢

热点阅读