PHP反序列化-2020-网鼎杯-青龙组-Web-AreUSerialz

PHP反序列化

序列化(serialize)就是将对象转换为字符串。反序列化(unserialize)则相反,数据的格式的转换对象的序列化利于对象的保存和传输,也可以让多个文件共享对象

访问控制

PHP 对属性或方法的访问控制,是通过在前面添加关键字 public(公有),protected(受保护)或 private(私有)来实现的。
public(公有):公有的类成员可以在任何地方被访问
protected(受保护):受保护的类成员则可以被其自身以及其子类和父类访问
private(私有):私有的类成员则只能被其定义所在的类访问

有类时会触发 魔术方法

那什么时魔术方法呢?PHP中把两个下划线开头的方法称为魔术方法(Magic methods)

serialize() 函数会检查类中是否存在一个魔术方法。如果存在,该方法会先被调用,然后才执行序列化操作。

魔术方法包括:

魔术方法用处
__construct()实例化类时自动调用
__destruct()类对象使用结束时自动调用
__set()在给未定义的属性赋值时自动调用
__get()调用未定义的属性时自动调用
__isset()使用 isset() 或 empty() 函数时自动调用
__unset()使用 unset() 时自动调用
__sleep()使用 serialize 序列化时自动调用
__wakeup()使用 unserialize 反序列化时自动调用
__call()调用一个不存在的方法时自动调用
__callStatic()调用一个不存在的静态方法时自动调用
__toString()把对象转换成字符串时自动调用
__invoke()当尝试把对象当方法调用时自动调用
__set_state()当使用 var_export() 函数时自动调用,接受一个数组参数
__clone()当使用 clone 复制一个对象时自动调用
__debugInfo()使用 var_dump() 打印对象信息时自动调用

简单的序列化:

555

序列化后各个字符串的含义:

556

PHP反序列化漏洞原理

序列化和反序列化本身没有问题,但是如果反序列化的内容是用户可以控制的,且后台不正当的使用了PHP中的魔法函数,就会导致安全问题。当传给unserialize()参数可控时,可以通过传入一个精心构造的序列化字符串,从而控制对象内部的变量甚至是函数。

例子

CTFHub中 2020-网鼎杯-青龙组-Web-AreUSerialz

代码审计

<?php

include("flag.php");

highlight_file(__FILE__);

class FileHandler {

protected $op;
protected $filename;
protected $content;

function __construct() {
    $op = "1";
    $filename = "/tmp/tmpfile";
    $content = "Hello World!";
    $this->process();
}

public function process() {
    if($this->op == "1") {
        $this->write();
    } else if($this->op == "2") {
        $res = $this->read();
        $this->output($res);
    } else {
        $this->output("Bad Hacker!");
    }
}

private function write() {
    if(isset($this->filename) && isset($this->content)) {
        if(strlen((string)$this->content) > 100) {
            $this->output("Too long!");
            die();
        }
        $res = file_put_contents($this->filename, $this->content);
        if($res) $this->output("Successful!");
        else $this->output("Failed!");
    } else {
        $this->output("Failed!");
    }
}

private function read() {
    $res = "";
    if(isset($this->filename)) {
        $res = file_get_contents($this->filename);
    }
    return $res;
}

private function output($s) {
    echo "[Result]: <br>";
    echo $s;
}

function __destruct() {
    if($this->op === "2")
        $this->op = "1";
    $this->content = "";
    $this->process();
}

}

function is_valid($s) {
    for($i = 0; $i < strlen($s); $i++)
        if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
            return false;
    return true;
}

if(isset($_GET{'str'})) {

$str = (string)$_GET['str'];
if(is_valid($str)) {
    $obj = unserialize($str);
}

}

首先代码审计就是看两点,一有无漏洞,二有无可控变量。

我们发现源代码最后76行有可控变量str通过get传参,并且发现有unserialize反序列化。

我们再看到 flag.php 是在这个高亮化文件里面的,并且发现有class(类):

class FileHandler {

protected $op;
protected $filename;
protected $content;

在反序列化后,相当于重新生成了一个对像,这个对象在程序结束时 析构执行­_destruct()//第58行

如果op值为2则强制将op的值变为1,content值为空,调用process函数。//第20行

如果op值为1,则进入“写”函数;如果op值为2,则进入“读”函数

这里我们需要读取到flag.php中的答案所以需要调用“读”函数//第45行

如果filename有值,则file_get_contents()函数把整个文件读入一个字符串中,如果给filename赋值为flag.php 那么我们就能读出flag了。

但是在destruct函数中进行了判断把2强制转换成了1:

function __destruct() {
    if($this->op === "2")
        $this->op = "1";
    $this->content = "";
    $this->process();
}

所以我们这里需要知道,用三个等号时,除了两个变量的值相同外,还必须这两个变量的类型相同,而用两个等号时,只需要两个变量值相同。

我们构造payload时,构造op=‘ 2’字符串,则op=‘2’就不成立,此时op就成了我们自己设置的值。然后通过process()函数调用后:

public function process() {
    if($this->op == "1") {
        $this->write();
    } else if($this->op == "2") {
        $res = $this->read();
        $this->output($res);
    }

因为这里为 op == “2”为弱类型对比只需要值相等就能调用“读”函数。就能读出flag.php文件了。

构造payload

123456789

序列化出来的payload为:

O%3A11%3A%22FileHandler%22%3A3%3A%7Bs%3A2%3A%22op%22%3Bs%3A2%3A%22+2%22%3Bs%3A8%3A%22filename%22%3Bs%3A8%3A%22flag.php%22%3Bs%3A7%3A%22content%22%3BN%3B%7D

注意这里要把protect改为public才是公有的,并且要将FileHandler用new实例化。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值