在freebuf上看到了一篇新的php反序列化的文章,借此继续分析一下php反序列化。
文章中的代码如下:
1 |
|
有两个小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之前的构造的反序列化数据:
1 | 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出来的结果 |
因为php在反序列化数据时:
protected属性的表示方式是在变量名前加个%00*%00
private表示方式是在变量名前加上%00类名%00
所以次数的两个private
属性都被加上了00阶段符号,于是只能通过python手动编码传输数据了
1 | import requests |
返回的结果如下:
之后如果要读取flag还有几个姿势,但不是本文的重点了
typecho反序列化漏洞
先放出payload
1 |
|
序列化一个数组之后作为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
方法如下:
1 | /** |
继续分析get方法:
1 | public function get($key, $default = NULL) |
如果$this->_filter
,就会调用_applyFilter
方法:
1 | private function _applyFilter($value) |
此时终于看到了call_user_func
方法,函数名是this->_filter
再看一道反序列化
``php
<?php
class Template{
public $cacheFile = ‘/tmp/cachefile’;
public $template = ‘
public function __construct($data=null)
{
$data=$this->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’]);
1 |
|
如果绕过这个if判断,这里需要分析一下php的源码:在’O:’,后面可以增加’+’,用来绕过正则判断。