绕过preg_match函数并使用本地命令RCE

发布时间 2023-10-15 18:27:58作者: Eddie_Murphy

来自[FBCTF2019]RCEService

题目本身不难,但这个知识点值得一提。

首先打开是一个输入JSON格式的cmd执行,随便输了输看看回显:

我输了个{"cmd" : "ls"}

嗯?直接出目录了?按道理来说应该有过滤吧。

果然输入ls /就:

显然把斜杠过滤了,试了试其他的语句,发现cat啥的常规的全给ban了,就只有ls能看。

贴一个题目源码:

<?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/>';
    }
}
 
?>

虽然我也不知道咋找到的,好像是那个题给的,但是复现的buu没给。

这个preg_match绕过其实有套路的:

1、%0A绕过

类似于preg_match("/^.*flag.*$/",$cmd)这种的正则匹配,默认只匹配第一行
?cmd=%0acat flag即可绕过

2、PCRE回溯次数限制绕过

当正则匹配回溯次数超过上限时将返回false

3、其他题常规方法: 数组绕过

preg_match只能处理字符串,当传入的是数组时将会返回false。

 

这里我选择的是第一个0a绕过,但是直接写在框中会被二次编码,我就直接url上传参了:

然后一个个查目录直接查到flag了:

但有个:putenv('PATH=/home/rceservice/jail');  设置了环境变量,只能使用当前环境的命令

然后对于linux来说,cat命令就在bin下面:

直接用/bin/cat就是cat的意思,获得flag:

 

PCRE的思路也能做:

用preg_match的回溯限制,长度为一百万,来绕过preg_match,因为当preg_match匹配的字符串太长的时候就会返回false,也就是数据溢出(不知道理解对不对)。

脚本如下: