文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

PCRE回溯次数绕过安全限制的正则实例分析

2023-06-30 00:12

关注

这篇“PCRE回溯次数绕过安全限制的正则实例分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“PCRE回溯次数绕过安全限制的正则实例分析”文章吧。

这次Code-Breaking Puzzles中我出了一道看似很简单的题目,将其代码简化如下:

<?phpfunction is_php($data){      return preg_match('/<\?.*[(`;?>].*/is', $data);  }if(!is_php($input)) {    // fwrite($f, $input); ...}

大意是判断一下用户输入的内容有没有PHP代码,如果没有,则写入文件。这种时候,如何绕过is_php()函数来写入webshell呢?

这道题看似简单,深究其原理,还是值得写一篇文章的。

正则表达式是什么

正则表达式是一个可以被“有限状态自动机”接受的语言类。

“有限状态自动机&rdquo;,其拥有有限数量的状态,每个状态可以迁移到零个或多个状态,输入字串决定执行哪个状态的迁移。

而常见的正则引擎,又被细分为DFA(确定性有限状态自动机)与NFA(非确定性有限状态自动机)。他们匹配输入的过程分别是:

由于NFA的执行过程存在回溯,所以其性能会劣于DFA,但它支持更多功能。大多数程序语言都使用了NFA作为正则引擎,其中也包括PHP使用的PCRE库。

回溯的过程是怎样的

所以,我们题目中的正则<\?.*[(`;?>].*,假设匹配的输入是<?php phpinfo();//aaaaa,实际执行流程是这样的:

PCRE回溯次数绕过安全限制的正则实例分析

见上图,可见第4步的时候,因为第一个.*可以匹配任何字符,所以最终匹配到了输入串的结尾,也就是//aaaaa。但此时显然是不对的,因为正则显示.*后面还应该有一个字符[(`;?>]

所以NFA就开始回溯,先吐出一个a,输入变成第5步显示的//aaaa,但仍然匹配不上正则,继续吐出a,变成//aaa,仍然匹配不上&hellip;&hellip;

最终直到吐出;,输入变成第12步显示的<?php phpinfo(),此时,.*匹配的是php phpinfo(),而后面的;则匹配上[(`;?>],这个结果满足正则表达式的要求,于是不再回溯。13步开始向后匹配;,14步匹配.*,第二个.*匹配到了字符串末尾,最后结束匹配。

在调试正则表达式的时候,我们可以查看当前回溯的次数:

PCRE回溯次数绕过安全限制的正则实例分析

这里回溯了8次。

PHP的pcre.backtrack_limit限制利用

PHP为了防止正则表达式的拒绝服务攻击(reDOS),给pcre设定了一个回溯次数上限pcre.backtrack_limit。我们可以通过var_dump(ini_get('pcre.backtrack_limit'));的方式查看当前环境下的上限:

PCRE回溯次数绕过安全限制的正则实例分析

这里有个有趣的事情,就是PHP文档中,中英文版本的数值是不一样的:

PCRE回溯次数绕过安全限制的正则实例分析

我们应该以英文版为参考。

可见,回溯次数上限默认是100万。那么,假设我们的回溯次数超过了100万,会出现什么现象呢?比如:

PCRE回溯次数绕过安全限制的正则实例分析

可见,preg_match返回的非1和0,而是false。

preg_match函数返回false表示此次执行失败了,我们可以调用var_dump(preg_last_error() === PREG_BACKTRACK_LIMIT_ERROR);发现失败的原因的确是回溯次数超出了限制:

PCRE回溯次数绕过安全限制的正则实例分析

所以,这道题的答案就呼之欲出了。我们通过发送超长字符串的方式,使正则执行失败,最后绕过目标对PHP语言的限制。

对应的POC如下:

import requestsfrom io import BytesIOfiles = {  'file': BytesIO(b'aaa<?php eval($_POST[txt]);//' + b'a' * 1000000)}res = requests.post('http://51.158.75.42:8088/index.php', files=files, allow_redirects=False)print(res.headers)

PCRE另一种错误的用法

延伸一下,很多基于PHP的WAF,如:

if(preg_match('/SELECT.+FROM.+/is', $input)) {    die('SQL Injection');}

均存在上述问题,通过大量回溯可以进行绕过。

另外,我遇到更常见的一种WAF是:

if(preg_match('/UNION.+?SELECT/is', $input)) {    die('SQL Injection');}

这里涉及到了正则表达式的“非贪婪模式”。在NFA中,如果我输入UNIONSELECT,这个正则表达式执行流程如下:

回溯次数随着a的数量增加而增加。所以,我们仍然可以通过发送大量a,来使回溯次数超出pcre.backtrack_limit限制,进而绕过WAF:

PCRE回溯次数绕过安全限制的正则实例分析

修复方法

那么,如何修复这个问题呢?

其实如果我们仔细观察PHP文档,是可以看到preg_match函数下面的警告的:

PCRE回溯次数绕过安全限制的正则实例分析

如果用preg_match对字符串进行匹配,一定要使用===全等号来判断返回值,如:

function is_php($data){      return preg_match('/<\?.*[(`;?>].*/is', $data);  }if(is_php($input) === 0) {    // fwrite($f, $input); ...}

这样,即使正则执行失败返回false,也不会进入if语句。

以上就是关于“PCRE回溯次数绕过安全限制的正则实例分析”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯