PCRE绕过正则

本文探讨了PHP的PCRE库在正则表达式匹配中的回溯原理,通过一个CTF挑战题目的解析,展示了如何利用贪婪匹配后的回溯来绕过限制。文中提到,当回溯次数超过预设限制(如100万次)时,正则匹配会失败,从而可以绕过某些安全检查。同时,文章还提及了如何构造输入以达到这一效果,并提到了短标签在PHP中的使用技巧。
摘要由CSDN通过智能技术生成

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示:这里可以添加本文要记录的大概内容:

今天进行CTF刷题的时候,刷到了关于正则表达式贪婪匹配后进行回溯产生的绕过,记录一下。


提示:以下是本篇文章正文内容,下面案例可供参考

一、PCRE绕过的原理

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

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

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

  • DFA: 从起始状态开始,一个字符一个字符地读取输入串,并根据正则来一步步确定至下一个转移状态,直到匹配不上或走完整个输入
  • NFA:从起始状态开始,一个字符一个字符地读取输入串,并与正则表达式进行匹配,如果匹配不上,则进行回溯,尝试其他状态

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

比如说:

<?php
function pcre($data){  
    return preg_match('/<\?.*[;].*/is', $data);  
}

假如传入$data=<?phpinfo();//aiwin 函数pcre进行匹配时,由于.*进行贪婪匹配,所以会匹配掉<?phpinfo();//aiwin 整个字符串,但是此时不对,因为正则表达式显示.*后还有字符; 所以NFA会开始进行回溯,每一步回溯一个字符,即第一步先回溯n,直到回溯匹配到;  一共回溯8步。

问题在于:       PHP为了防止对正则表达式进行拒绝服务攻击,设置了pcre.backtrack_limit的配置,限制正则表达式的回溯次数:

 查看回溯次数,默认上限为100万次,当回溯次数超过100万次,就会使preg_match函数返回false,说明此次正则匹配执行失败。

防御方法:要防御正则表达式的回溯次数溢出,将preg_match的结果使用强等于===匹配即可。

二、例题

1.[NISACTF 2022]middlerce

题目源码:

        

<?php
include "check.php";
if (isset($_REQUEST['letter'])){
    $txw4ever = $_REQUEST['letter'];
    if (preg_match('/^.*([\w]|\^|\*|\(|\~|\`|\?|\/| |\||\&|!|\<|\>|\{|\x09|\x0a|\[).*$/m',$txw4ever)){
        die("再加把油喔");
    }
    else{
        $command = json_decode($txw4ever,true)['cmd'];
        checkdata($command);
        @eval($command);
    }
}
else{
    highlight_file(__FILE__);
}
?>

1,题目从头开始进行正则表达式匹配,.*贪婪匹配后又匹配括号里的字符,最后再.*后结束

checkdata函数进行的是黑名单过滤,可以使用tail以及通配符*进行获取flag,过滤了

/\^|\||\~|assert|print|include|require|\(|echo|flag|data|php|glob|sys|phpinfo|POST|GET|REQUEST|exec|pcntl|popen|proc|socket|link|passthru|file|posix|ftp|\_|disk|tcp|cat|tac/i

2,代码虽然执行了eval函数,但是却不会将结果输出到页面,可以使用短标签代替echo的效果进行输出,<??>和<?=?>。<??>相当于对<?php>的替换。而<?=?>则是相当于<? echo>,<??>写法需要开启short_open_tag,<?=?>则是默认开启。

 

3,关键点在于使回溯次数超过100万次,返回false,利用脚本上传post数据:
 

data = '{"cmd":"?><?= `tail /f*`?>", "#":"' + "#" * 1000000 + '"}'

其中.*会匹配掉整个字符串,但是此时不正确,因为后面括号应该还有字符,会进行回溯,传入一百万个#会使回溯次数上限,返回false绕过正则匹配。
 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

M03-Aiwin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值