今天做靶场时遇到了一个情形:拿到了webshell,却不能执行任何命令,如图

后来百度知道了disable_functions功能,这类服务器针对命令执行函数做了防范措施

一般绕过思路是利用漏掉的函数,今天这里介绍的是LD_PRELOAD

0X01 LD_PRELOAD认识

LD_PRELOAD是Linux系统的一个环境变量,可以影响程序的运行时的链接,它允许你定义在程序运行前优先加载的动态链接库。通过这个环境变量,我们可以在主程序和其动态链接库的中间加载别的动态链接库,甚至覆盖正常的函数库。这里在网上找了两张形象的图片来理解

LD_PRELOAD这个环境变量指定路径的文件,会在其他文件被调用前,最先被调用

替换前运作流程:

替换后运作流程:

0X02 绕过条件

了解了LD_PRELOAD,就有了绕过思路,通过加载我们写的动态链接库,执行相关操作

前提条件:

能够上传自己的.so文件

能够控制环境变量的值(设置LD_PRELOAD变量),比如putenv,mail函数

存在可以控制PHP启动外部程序的函数并能执行(因为新进程启动将加载LD_PRELOAD中的.so文件),比如mail()、imap_mail()、mb_send_mail()和error_log()等

0X03  在这里我拷贝了一份文章,仅供学习使用,是工具开发者写的,真的思路太清晰太新奇了,文章链接:https://www.freebuf.com/articles/web/192052.html

无命令执行功能的 webshell 是无意义的,得突破!

通常来说,导致 webshell 不能执行命令的原因大概有三类:一是 php.ini 中用 disable_functions 指示器禁用了 system()、exec() 等等这类命令执行的相关函数;二是 web 进程运行在 rbash 这类受限 shell 环境中;三是 WAF 拦劫。若是一则无法执行任何命令,若是二、三则可以执行少量命令。从当前现象来看,很可能由 disable_functions 所致。为验证,我利用前面的 RCE 漏洞执行 phpinfo(),确认的确如此:


有四种绕过 disable_functions 的手法:第一种,攻击后端组件,寻找存在命令注入的、web 应用常用的后端组件,如,ImageMagick 的魔图漏洞、bash 的破壳漏洞;第二种,寻找未禁用的漏网函数,常见的执行命令的函数有 system()、exec()、shell_exec()、passthru(),偏僻的 popen()、proc_open()、pcntl_exec(),逐一尝试,或许有漏网之鱼;第三种,mod_cgi 模式,尝试修改 .htaccess,调整请求访问路由,绕过 php.ini 中的任何限制;第四种,利用环境变量 LD_PRELOAD 劫持系统函数,让外部程序加载恶意 *.so,达到执行系统命令的效果。

尝试第一种时,我用 phpinfo() 查看 ImageMagick 版本为 v6.9.4-10:

用 searchsploit(exploit-db.com 的本地版)搜索存在命令注入的版本为 v6.9.3-9 或 v7.0.1-0:

显然,当前 ImageMagick 无法利用;尝试第二种时,常见的、不常见的、罕见的(如 dl()),所有可启动进程的函数均被禁用;尝试第三种时,发现并未启用 mod_cgi 模式。所有希望,寄托在 LD_PRELOAD。

设想这样一种思路:利用漏洞控制 web 启动新进程 a.bin(即便进程名无法让我随意指定),a.bin 内部调用系统函数 b(),b() 位于系统共享对象 c.so 中,所以系统为该进程加载共 c.so,我想法在 c.so 前优先加载可控的 c_evil.so,c_evil.so 内含与 b() 同名的恶意函数,由于 c_evil.so 优先级较高,所以,a.bin 将调用到 c_evil.so 内 b() 而非系统的 c.so 内 b(),同时,c_evil.so 可控,达到执行恶意代码的目的。基于这一思路,将突破 disable_functions 限制执行操作系统命令这一目标,大致分解成几步在本地推演:查看进程调用系统函数明细、操作系统环境下劫持系统函数注入代码、找寻内部启动新进程的 PHP 函数、PHP 环境下劫持系统函数注入代码。

查看进程调用系统函数明细。linux 创建新进程的过程较为复杂,我关心进程加载了哪些共享对象、可能调用哪些 API、实际调用了哪些 API。比如,运行 /usr/bin/id,通过 ldd 可查看系统为其加载的共享对象:

由于可执行文件 /usr/bin/id 内含符号表,所以,运行 nm -D /usr/bin/id 2>&1 或 readelf -Ws /usr/bin/id 可查看该程序可能调用的系统 API 明细:

由于程序运行时会根据命令行选项、运行环境作出不同反应,导致真正运行时调用的 API 可能只是 readefl 查看的子集,你可以运行 strace -f /usr/bin/id 2>&1 跟踪实际 API 调用情况,比如,实际调用 open() 的入参、返回值一目了然:

操作系统环境下劫持系统函数注入代码。linux 的环境变量 LD_PRELOAD 是一种类似 win32 API hook 的更优雅的实现,适用于打热补丁、读取进程空间数据、禁止程序调用指定 API、调试程序等等场景,甚至可以在不更改原始可执行文件前提下植入后门(管理员常用的 /bin/ps)。由于被劫持的系统函数得由我们重新实现一次,函数原型必须一致,为减少复杂性,我会选择劫持那些无参数且常用的系统函数,getuid() 就适合,以此为例,完整劫持过程步骤大致如下:首先,用 man 2 getuid 查看函数原型:

然后,编写同原型的 getuid() 函数,保存至 getuid_shadow.c,源码为:

执行 gcc -shared -fPIC getuid_shadow.c -o getuid_shadow.so 将其编译为共享对象:

最后,借助环境变量 LD_PRELOAD 劫持系统函数 getuid(),获取控制权。执行 LD_PRELOAD=/root/getuid_shadow.so /usr/bin/id,注入代码成功执行:

注意,LD_PRELOAD 是进程独占环境变量,类似于命令适配器,它与待执行命令间必须为空白字符,而非命令分隔符(;、&&、||)。

找寻内部启动新进程的 PHP 函数。虽然 LD_PRELOAD 为我提供了劫持系统函数的能力,但前提是我得控制 php 启动外部程序才行(只要有进程启动行为即可,无所谓是谁)。常见的 system() 启动程序方式显然不行,否则就不存在突破 disable_functions 一事了。PHP 脚本中除了调用 system()、exec()、shell_exec() 等等一堆 php 函数外,还有哪种可能启动外部程序呢?php 解释器自身!比如,php 函数 goForward() 实现“前进”的功能,php 函数 goForward() 又由组成 php 解释器的 C 语言模块之一的 move.c 实现,C 模块 move.c 内部又通过调用外部程序 go.bin 实现,那么,我的 php 脚本中调用了函数 goForward(),势必启动外部程序 go.bin。现在,我需要找到类似 goForward() 的真实存在的 PHP 函数。印象中,处理图片、请求网页、发送邮件等三类场景中可能存在我想要的函数,我得逐一验证。处理图片,通常调用 PHP 封装的 ImageMagick 库,新建 image.php,调用 Imagick():

运行 strace -f php image.php 2>&1 | grep -A2 -B2 execve 查看 Imagick() 是否启动新进程:

第一个 execve 是启动 PHP 解释器而已,必须找到第二个 execve,没有则说明并未启动新进程;请求网页,新建 http.php,调用 curl_init():

运行 strace -f php http.php 2>&1 | grep -A2 -B2 execve 查看 curl_init() 是否启动新进程:

仍然不是我要的;发送邮件,新建 mail.php,调用 mail():

运行 strace -f php mail.php 2>&1 | grep -A2 -B2 execve 查看 mail() 是否启动新进程:

bingo!mail() 内部启动了 /usr/sbin/sendmail、/usr/sbin/postdrop 两个新进程,它就是我一直苦寻的函数(用相同的测试方式,还找到一个 imap_mail())。

PHP 环境下劫持系统函数注入代码。mail.php 内增加设置 LD_PRELOAD 的代码:

然后将 mail.php 以及内含 mail() 函数的共享对象 getuid_shadow.so 放入 web 目录 /var/www/:

执行 mail.php 之后,找到 getuid_shadow.so 中 mail() 创建的文件 /tmp/evil,成功在 PHP 环境下不借助任何 PHP 命令执行函数执行命令:

有了前面的分析,看我如何在目标站点绕过 disable_functions 执行系统命令。

首先,基于前面的 mail.php 写了个小马 bypass_disablefunc.php:

bypass_disablefunc.php 提供三个 GET 参数。一是 cmd 参数,待执行的系统命令(如 pwd);二是 outpath 参数,保存命令执行输出结果的文件路径(如 /tmp/xx),便于在页面上显示,另外关于该参数,你应注意 web 是否有读写权限、web 是否可跨目录访问、文件将被覆盖和删除等几点;三是 sopath 参数,指定劫持系统函数的共享对象的绝对路径(如 /var/www/bypass_disablefunc_x64.so),另外关于该参数,你应注意 web 是否可跨目录访问到它。此外,bypass_disablefunc.php 拼接命令和输出路径成为完整的命令行,所以你不用在 cmd 参数中重定向了:

$evil_cmdline = $cmd . " > " . $out_path . " 2>&1";

同时,通过环境变量 EVIL_CMDLINE 向 bypass_disablefunc_x64.so 传递具体执行的命令行信息:
putenv("EVIL_CMDLINE=" . $evil_cmdline);

然后,基于 getuid_shadow.c 编写劫持函数的代码 bypass_disablefunc.c。回想下,先前我之所以劫持 getuid(),是因为 sendmail 程序会调用该函数,在真实环境中,存在两方面问题:一是,某些环境中,web 禁止启用 senmail、甚至系统上根本未安装 sendmail,也就谈不上劫持 getuid(),通常的 www-data 权限又不可能去更改 php.ini 配置、去安装 sendmail 软件;二是,即便目标可以启用 sendmail,由于未将主机名(hostname 输出)添加进 hosts 中,导致每次运行 sendmail 都要耗时半分钟等待域名解析超时返回,www-data 也无法将主机名加入 hosts(如,127.0.0.1    lamp、lamp.、lamp.com)。基于这两个原因,我不得不放弃劫持函数 getuid(),必须找个更普适的方法。回到 LD_PRELOAD 本身,系统通过它预先加载共享对象,如果能找到一个方式,在加载时就执行代码,而不用考虑劫持某一系统函数,那我就完全可以不依赖 sendmail 了。这种场景与 C++ 的构造函数简直神似!几经搜索后了解到,GCC 有个 C 语言扩展修饰符 __attribute__((constructor)),可以让由它修饰的函数在 main() 之前执行,若它出现在共享对象中时,那么一旦共享对象被系统加载,立即将执行 __attribute__((constructor)) 修饰的函数。强调下,这一细节非常重要,很多朋友用 LD_PRELOAD 手法突破 disable_functions 无法做到百分百成功,正因为这个原因,我们不要局限于仅劫持某一函数,而应考虑劫持共享对象。bypass_disablefunc.c 源码如下

从环境变量 EVIL_CMDLINE 中接收 bypass_disablefunc.php 传递过来的待执行的命令行。

接着,用命令 gcc -shared -fPIC bypass_disablefunc.c -o bypass_disablefunc_x64.so 将 bypass_disablefunc.c 编译为共享对象 bypass_disablefunc_x64.so:

你要根据目标架构编译成不同版本,在 x64 的环境中编译,若不带编译选项则默认为 x64,若要编译成 x86 架构需要加上 -m32 选项。

最后,用菜刀将 bypass_disablefunc.php 和 bypass_disablefunc_x64.so 传到目标:

指定好命令输出路径、共享对象路径后,在 bypass_disablefunc.php 上再次执行先前失败的命令 cat /proc/meminfo

啊哈!很酷对不对。

好了,巧用 LD_PRELOAD 突破 disable_functions 的手法就是这样子,唯一条件,PHP 支持putenv()、mail() 即可,甚至无需安装 sendmail。那么,现在的情况是,我知道你很忙,没时间看前面的技术细节,要的只是开箱即用的工具。行,bypass_disablefunc.php、bypass_disablefunc.c、bypass_disablefunc_x64.so 托管在 https://github.com/yangyangwithgnu/bypass_disablefunc_via_LD_PRELOAD,自取。

通过LD_PRELOAD绕过disable_functions的更多相关文章

  1. LD_PRELOAD & putenv() 绕过 disable_functions & open_basedir

    这次TCTF中一道题,给出了一个PHP一句话木马,设置了open_basedir,disable_functions包含所有执行系统命令的函数,然后目标是运行根目录下的/readflag,目标很明确, ...

  2. 无需sendmail:巧用LD_PRELOAD突破disable_functions

    *本文原创作者:yangyangwithgnu,本文属FreeBuf原创奖励计划,未经许可禁止转载 摘要:千辛万苦拿到的 webshell 居然无法执行系统命令,怀疑服务端 disable_funct ...

  3. 绕过disable_functions执行命令实验

    绕过disable_functions执行命令实验 看下disable函数,所有命令函数都被禁用: 编译64位共享库: 命令成功执行: 参考链接: https://www.freebuf.com/ar ...

  4. [转+自]disable_functions之巧用LD_PRELOAD突破

    写在前面: 通过知乎的一篇艰难的渗透提权,引发了一些对于disable_funcionts绕过的思考,虽然在暑假日记中记载了四种绕过disable_functions,比如com组件,pcntl_ex ...

  5. Disable_functions绕过整合

    转载 https://whoamianony.top/2021/03/13/Web安全/Bypass Disable_functions/ https://www.mi1k7ea.com/2019/0 ...

  6. [转+自]关于PHP7的新特性(涉及取反和disabled_functions绕过)

    PHP7和PHP5上的安全区别 preg_replace()不再支持/e修饰符 利用\e修饰符执行代码的后门大家也用了不少了,具体看官方的这段描述: 如果设置了这个被弃用的修饰符, preg_repl ...

  7. PHP绕过disable_function

    PHP绕过disable_function 常规绕过 exec exec执行command命令,但是不会输出全部结果,而是返回结果的最后一行. 想得到全部的结果,可以使用第二个参数,让其输出到一个数组 ...

  8. disable_functions Bypass

    参考文章和poc(文中均有poc下载地址) : https://www.uedbox.com/post/59295/ https://www.uedbox.com/post/59402/ 当然 fre ...

  9. PHP Execute Command Bypass Disable_functions

    先简单说一下php调用mail()函数的过程. 看到源码ext/mail.c 236行: char *sendmail_path = INI_STR("sendmail_path" ...

随机推荐

  1. 「 优质资源20190409 」Java最新精选优质资源!

    资源导读 经过小编精心整理,java最新优质资源出炉 不想看书,可以看视频,比较生动有趣,好的视频教程是一个好老师! 资源来自于网络,请勿用于商业用途 资源目录 1.Java Spring 技术栈构建 ...

  2. 《编写高质量代码:改善C#程序的157个建议》是C#程序员进阶修炼的必读之作

  3. 使用Route Prefix 使用属性路由 精通ASP-NET-MVC-5-弗瑞曼

  4. BZOJ 3691 游行

    题目传送门 分析: 没被访问的点要C费用,跑一次路要C费用 把这两个统一一下试试... 那就是每次不标记起点或者终点 那就是路径覆盖了2333 二分图,x 部 i 号点与 y 部 j 号点连 i 到 ...

  5. AI初探1

    一个典型的机器学习的过程,首先给出一个输入数据,我们的算法会通过一系列的过程得到一个估计的函数,这个函数有能力对没有见过的新数据给出一个新的估计,也被称为构建一个模型.就如同上面的线性回归函数. 在机 ...

  6. SVN: 聚合工程下的子工程无法使用 svn:ignore

    当想将聚合工程manager下子工程没用的一些文件使用svn:ignore,发现该功能不能使用 这是因为SVN 服务器上还没有这些子工程的文件夹,只有聚合工程的文件夹,所以SVN认为在服务器上这些代码 ...

  7. 人生需要Plan B

    天有不测风云,人有祸兮旦福.2020年,刚打开就是地狱模式! 武汉加油,中国加油! 新冠状肺炎的强传播性,让人们不得不乖乖待在家,工地开不了工,白领不能上班,农村封村,城市封小区.人们每天在一个小范围 ...

  8. 85道Java微服务面试题整理(助力2020面试)

    微服务 面试题 1.您对微服务有何了解? 2.微服务架构有哪些优势? 3.微服务有哪些特点? 4.设计微服务的最佳实践是什么? 5.微服务架构如何运作? 6.微服务架构的优缺点是什么? 7.单片,SO ...

  9. gRPC in ASP.NET Core 3.x -- Protocol Buffer(2)Go语言的例子(上)

    上一篇文章(大约半年前写的):https://www.cnblogs.com/cgzl/p/11246324.html 建立Go项目 在GOPATH的src下面建立一个文件夹 protobuf-go, ...

  10. SpringBoot整合ActiveMQ和开启持久化

    一.点对点 1.提供者目录展示 2.导入依赖 <dependency> <groupId>org.springframework.boot</groupId> &l ...