<?php$str,=,"\";$pattern,=,"/\/";if(preg_match($partern,$str,$arr)){,,,,echo,"success";,,,,print_r($arr);}else{,,,,echo,"false";}
看到这段代码的师傅们,思考一下,会输出success还是false
输出false,正则没有被匹配到,为什么呢?
php对转义符的解析
php解析正则时分为了两个步骤,一个是php对字符串的解析,之后才是对正则的解析,那么php在解析字符串时什么时候才会将\解析为转义呢?只有在某一字符会对这一语句产生稠浊时,php才会将\解析为转义。
剖析一个正则匹配
首先php对字符串进行解析:
在这种情形下可以看到str中\并没有被当成转义符
而在pattern中,由于有多个\并且在正则表达式中存在/,会稠浊正则表达式的边界,因此这四个转义符的浸染分别是:
第一个转义符转义第二个转义符第三个转义符转义第四个转义符,第五个转义符转义/因此php终极解析出的str为,\/,pattern为,\\/
到preg_match时,进行正则解析(正则解析只解析正则表达式):
将pattern中的,\\/,解析为\/,(第一个转义符转义了第二个转义符)经由php和正则的解析后,我们可以创造str与pattern是一样的字符串了,以是该当会输出success,并且匹配到的部分为\/
验证成功
这里提出一个问题,如果在pattern中,我的正则内容中不想利用\来转义/,并且还想输出success,那该当怎么修正正则内容呢?
我们刚才提到,转义是为了防止语句中的字符产生稠浊,/与正则边界产生了稠浊,以是我们用其他的字符作为边界就好了,比如#
总结:在一样平常情形下,只有字符串中的某一字符会对该语句产生稠浊,这时该符号前的\才具有转义浸染。
【----帮助网安学习,须要网安学习资料关注我,私信回答“资料”免费获取----】① 网安学习发展路径思维导图② 60+网安经典常用工具包③ 100+SRC漏洞剖析报告④ 150+网安攻防实战技能电子书⑤ 最威信CISSP 认证考试指南+题库⑥ 超1800页CTF实战技巧手册⑦ 最新网安大厂口试题合集(含答案)⑧ APP客户端安全检测指南(安卓+IOS)
这里我在做测试有一个小坑
首先php的字符串解析:可以看到由于字符串中并没有可能会产生稠浊语句的字符,因此\都没有转义浸染。
正则进行解析(只解析正则表达式,不解析其他字符串):pattern中的\/被解析成了/,
因此终极的正则匹配是在字符串\/中匹配/,因此输出了/
这里我一开始以为str中的\也发挥了转义浸染,实在并不是。
回到最初的问题,为什么输出了false
<?php$str,=,"\\";,$pattern,=,"/\\/";,,if(preg_match($partern,$str,$arr)){,,,,echo,"success";,,,,print_r($arr);}else{,,,,echo,"false";}
按照上面的流程剖析,
首先php进行字符串解析:
str被解析为\,pattern被解析为\进行正则表达式解析:
pattern中含有转义符\,现在正则须要这个转义符去发挥转义浸染,但在正则表达式中已经没有其他字符去转义了,导致了正则表达式的解析缺点,pattern终极被解析成了什么我们也不知道以是终极在进行正则匹配时会输出false
那么我们该当怎么让它输出success呢?
php正则如何精确匹配\刚才我们提到在正则解析时只剩下了一个\,导致理解析的缺点,那么如果我们在正则解析这步剩下两个\是不是就可以在正则解析中保留下一个\呢?再往前推,如果想要正则解析这步里保留两个\,那么在定义partern字符串的时候我们是不是要写四个\才可以?
详细的解析过程我就不讲了,跟上面是完备一样的。
总结:php在正则中匹配\时须要在正则表达式中写入四个\
一道ctf题的剖析题目来源:[安洵杯,2019]easy_web,wp移步主页查找,如果没有便是还没写完。
if,(preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i",,$cmd)),{,,,,echo("forbid,~");
在这一段代码中对传入的cmd命令进行了过滤,并且可以看到个中有四个反斜杠,对\做出了过滤,但末了仍旧可以用反斜线逃逸,ca\t,l\s实行命令,这是为什么呢?
按照我们上面所说的进行剖析,首先php对字符串进行解析:
\\被解析为\\\\\,被解析为\\经由字符串解析,原来的|\\|\\\\|,变成了|\|\\|
正则表达式解析:
第一个\|被解析为|\\被解析为\经由两次解析后,终极的正则表达式变成了||\|,以是实际上是对|\进行了过滤,以是就可以利用\进行绕过了。
因此办理的办法是在正则过滤中不要添加\\这一项,会导致全体正则表达式直接变味。
这里随着原帖看创造原帖说的有点问题,自己思考了一下做出了一些猜想,创造是精确的。
还有原帖中提到的一个问题,这里为什么随便一个字符串乃至是空都可以匹配成功,由于在|\\\\|的旁边两边没有东西,为空,以是随便匹配都可以匹配到。
办理方法便是两边加上东西就可以了。
自己的小感想
这道题在网上的wp基本都是直接用\去实行命令,但很少有人能去谈论为什么可以这么绕过,后端代码已经做出了过滤,为什么还是会被绕过,我很幸运能够看到更深的剖析,这也是我第一次自己有独立的想法去不断的调试代码,虽然每一次看到其他大佬wp里不合理的地方觉得很迷茫,但是还找不到情由,但是经由不断的调试创造有些其他大佬的东西也不一定就都是对的,而且自己不断调试后找到问题有一种说不出来的造诣感,总结起来便是看问题要深入,有耐心。引用原帖的一句话便是