查看: 92|回复: 0

代码审计与CTF之PHP反序列化 10个案例学习 持续更新中

[复制链接]

2

主题

4

帖子

8

积分

新手上路

Rank: 1

积分
8
发表于 2023-7-6 16:26:52 | 显示全部楼层 |阅读模式
案例一

(访问题目链接直接显示的是如下代码)
<?php
class Demo {
    private $file = 'index.php'; // 定义私有属性$file,初始值为'index.php'
    public function __construct($file) { // 定义构造函数,传入参数$file
        $this->file = $file; // 将传入参数$file赋值给私有属性$file
    }
    function __destruct() { // 定义析构函数
        echo @highlight_file($this->file, true); // 输出参数指定文件的源代码高亮显示
    }
    function __wakeup() { // 定义反序列化魔术方法__wakeup()
        if ($this->file != 'index.php') { // 如果私有属性$file不等于'index.php'
            //the secret is in the fl4g.php
            $this->file = 'index.php'; // 将私有属性$file赋值为'index.php'
        }
    }
}
if (isset($_GET['var'])) { // 判断GET请求中是否存在变量var
    $var = base64_decode($_GET['var']); // 对GET请求中的变量var进行Base64解码
    if (preg_match('/[oc]:\d+:/i', $var)) { // 检查$var是否匹配正则表达式'[oc]:\d+:/i'
        die('stop hacking!'); // 如果$var匹配正则表达式,则输出'stop hacking!'并终止程序
    } else {
        @unserialize($var); // 会对$var执行反序列化操作
    }
} else {
    highlight_file("index.php"); // 在GET请求中没有变量var时,输出参数指定文件的源代码高亮显示
}
?>
代码分析:
这段PHP代码定义了一个名为Demo的类,包含了构造函数、析构函数和反序列化魔术方法__wakeup()。如果在GET请求中存在变量var,则会对该变量进行Base64解码并进行反序列化操作;反之则输出当前PHP文件的源代码。
其中,__wakeup()方法用于在执行反序列化操作时判断类属性$file是否等于'index.php',如果不是,则将其赋值为'index.php'。这个处理机制可能是为了防止类属性被修改而导致攻击。
另外,还使用preg_match()函数对传入的$var变量进行检测,以免出现一些恶意的序列化字符串,保证系统安全。
目标:显示出fl4g.php
1、传入的var变量值在base64解码,
即要绕过正则, 然后进入反序化操作,
在反序列化操作中二还需要绕过__wakeup()方法,才能显示出fl4g.php

__wakeup() //执行unserialize()时,会首先第一个方法调用这个函数
因此,我们要反序列化xctf类的同时还要绕过__wakeup方法的执行(如果不绕过__wakeup()方法,那么将会输出bad requests并退出脚本),__wakeup()函数漏洞原理:当序列化字符串表示对象属性个数的值大于真实个数的属性时就会跳过__wakeup的执行。因此,需要修改序列化字符串中的属性个数:
做题时,先通过serialize()得到序列化字符串,再修改
__sleep() //执行serialize()时,先会调用这个函数
__destruct() //对象被销毁时触发
__call() //在对象上下文中调用不可访问的方法时触发
__callStatic() //在静态上下文中调用不可访问的方法时触发
__get() //用于从不可访问的属性读取数据或者不存在这个键都会调用此方法
__set() //用于将数据写入不可访问的属性
__isset() //在不可访问的属性上调用isset()或empty()触发
__unset() //在不可访问的属性上使用unset()时触发
__toString() //把类当作字符串使用时触发
__invoke() //当尝试将对象调用为函数时触发
代码分析
https://blog.csdn.net/qq_61774705/article/details/126330449
unserialize() 函数用于将通过 serialize() 函数序列化后的对象或数组进行反序列化,并返回原始的对象结构。
isset() 函数用于检测变量是否已设置并且非 NULL。如果已经使用 unset() 释放了一个变量之后,再通过 isset() 判断将返回 FALSE。若使用 isset() 测试一个被设置成 NULL 的变量,将返回 FALSE。
同时要注意的是 null 字符("\0")并不等同于 PHP 的 NULL 常量。
PHP 版本要求: PHP 4, PHP 5, PHP 7
file_get_contents() 把整个文件读入一个字符串中。
该函数是用于把文件的内容读入到一个字符串中的首选方法。如果服务器操作系统支持,还会使用内存映射技术来增强性能。
error_reporting() 函数规定报告哪个错误。
该函数设置当前脚本的错误报告级别。
该函数返回旧的错误报告级别。
同时本题环境不是PHP7.2,是PHP5;查看flag可以是highlight_file也可以是show_source。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表