前言
- 正则绕过知识总结
一、换行符绕过
1 | <?php |
二、数组绕过
preg_match只能处理字符串,当传入的subject是数组时会返回false
三、%5c绕过
1 |
|
题目要求我们需要绕过正则才可以任意命令执行
正则的意思:/^[a-z0-9_]*$/isD
1 | /i不区分大小写 |
payload
1 | http://127.0.0.1/test.php?action=\create_function&arg=return%271%27;}phpinfo();/* |
四、PHP利用PCRE回溯次数限制绕过某些安全限制
参考文章Leavesongs
1 |
|
正则表达式是一个可以被“有限状态自动机”接受的语言类。
“有限状态自动机”,其拥有有限数量的状态,每个状态可以迁移到零个或多个状态,输入字串决定执行哪个状态的迁移。
而常见的正则引擎,又被细分为DFA(确定性有限状态自动机)与NFA(非确定性有限状态自动机)。他们匹配输入的过程分别是:
- DFA: 从起始状态开始,一个字符一个字符地读取输入串,并根据正则来一步步确定至下一个转移状态,直到匹配不上或走完整个输入
- NFA:从起始状态开始,一个字符一个字符地读取输入串,并与正则表达式进行匹配,如果匹配不上,则进行回溯,尝试其他状态
由于NFA的执行过程存在回溯,所以其性能会劣于DFA,但它支持更多功能。大多数程序语言都使用了NFA作为正则引擎,其中也包括PHP使用的PCRE库。
回溯的过程
1 | 所以,我们题目中的正则<\?.*[(`;?>].*,假设匹配的输入是<?php phpinfo();//aaaaa,实际执行流程是这样的: |
1 | 见上图,可见第4步的时候,因为第一个.*可以匹配任何字符,所以最终匹配到了输入串的结尾,也就是//aaaaa。但此时显然是不对的,因为正则显示.*后面还应该有一个字符[(`;?>]。 |
PHP的pcre.backtrack_limit限制利用
1 | PHP为了防止正则表达式的拒绝服务攻击(reDOS),给pcre设定了一个回溯次数上限pcre.backtrack_limit。我们可以通过var_dump(ini_get('pcre.backtrack_limit'));的方式查看当前环境下的上限: |
可见,回溯次数上限默认是100万。那么,假设我们的回溯次数超过了100万,会出现什么现象呢?比如:
那么这道题的答案就呼之欲出了,我们通过发送超长字符串的方式,使正则执行失败,最后绕过目标对PHP语言的限制。
对应的POC如下:
1 | import requests |
我的个人博客
孤桜懶契:http://gylq.gitee.io