bypass disable_functions 的一些思路与实践 & tctf 2019 Wallbreaker Easy WP
0x01 Abstract
本文简单描写了tctf的web第二题”Wallbreaker Easy”的解题方法,以此题为出发点,探索一些通过Imagick来bypass disable_functions的方法。通过自动化测试来寻找启动子进程的后缀名处理和API函数,从而寻找可以劫持的程序(通过LD_PRELOAD)和发现可能会存在命令注入的函数(在启动的新进程中执行命令)。
此思路并非原创,只是在前人的基础上提出一点自己的思考和实现。
环境: Ubuntu 18.04 + PHP 7.2.15 + Imagick 3.4.3RC2
通过sudo apt install php php-fpm php-imagick
安装。
0x02 TCTF 2019 Wallbreaker Easy WP
题目描述如图,并且提示ubuntu 18.04/sudo apt install php php-fpm php-imagick
。
主要使用了一个老手法的新利用,这位大佬找到一个扩展修饰符,可以在main函数前执行,这样就省去了使用LD_PRELOAD需要寻找可用函数的问题。详情见此篇文章。
巧用LD_PRELOAD突破disable_functions
如果不了解LD_PRELOAD。见此篇文章。
利用环境变量LD_PRELOAD来绕过php disable_function执行系统命令 – YiYang
既然前提有了,只需要找到可以利用函数就可以了。大佬通过查找ImageMagic的文档发现,在处理ilbm
的文件的时候会启动ilbmtoppm
程序,而这个程序是ubuntu 18.04自带的。
在ubuntu 18.04的环境下使用gcc -shared -fPIC execue_command.c -o execue_command.so
编译下列代码成so。
1 | #define _GNU_SOURCE |
上述代码执行环境变量CMD的值,并且将LD_PRELOAD环境变量置空。
使用python上传so到tmp目录下。
1 | import requests |
url编码后执行如下代码,设置环境变量,调用Imageck,触发恶意so,从而执行命令,将命令执行的结果写入flag文件。
1 | $cmd = "/readflag"; |
最后读flag文件。
0x03 通过Fuzz查找其他可用的文件格式
可以看出,ilbm之所以可用是因为启动了相应的子进程,难道只有ilbm是可以用的吗?
其实并不是的,我用了一个很粗暴的方法,将phpinfo()中的格式复制下来,动态生成相应格式的空白样本文件,并且生成通过Imagick加载样本文件的PHP文件,执行strace命令,并进行筛选。
通过下列命令查看执行此php文件时进程的启动情况。
1 | strace -f php xxx.php 2>&1 |grep -A2 -B2 execve |
有的后缀名在处理的时候虽然会调用外部程序,但是本机并没有这些程序。
这种情况是不可用的,需要筛选掉。
有的后缀名通过sh命令调用相应的程序,虽然调用的程序不存在,但是不会提示文件不存在。
此种情况需要判断该程序是否默认存在。
更正一个错误,此处可以利用。
经过Fuzz,部分结果如图。
1 | .ai .avi .epdf .eps .epsf .epsi .m2v .m4v .mkv .mov .mp4 .mpeg .mpg .pdfa .svg .wmv |
可以测试一下这些格式是不是真的可用。
以.epsi为例。
发送前记得编码。
结果如图
从ImageMagick的代理信息中也可以找到很多可用的后缀名,只要被代理的后缀名启动了外部程序,不管事什么程序,都可以通过LD_PRELOAD进行劫持。
这种做法理论上不仅限于Imagick,可以使用在其他使用了ImageMagick接口的PHP扩展。
0x04 遇见phpt的一些思路
LD_PRELOAD的做法其实是具有一些限制的,考虑一种情况,有远程代码执行,没有读写权限,文件上传到OSS中。这种情况下无法将本机的环境变量设置为远程地址。所以如果能找到一个函数,启动了子进程,并且有部分或者全部参数可控,这样就可以通过子进程来执行命令。就像imap_open这样。
如果Imagick存在一个函数,跟这种情况类似,那么就可以用来绕过disable_functions的限制。如何找到这种函数呢?通过读源码来发现此类函数比较费时费力,能否通过自动化来发现呢?
关于PHPT
Java中单元测试非常常见,但是在PHP中并不是那么普及,PHPT文件就是PHP提供的单元测试功能。还有一些单元测试的库,比如PHPUnit。
关于PHPT请见以下两篇文章,内容上有一些重叠。
浅析 PHP 官方自动化测试方法
附录E phpt测试文件说明
在github上可以看到Imagick的源码,可以看到tests文件夹中的PHPT文件对于Imagick的函数进行单元测试。
在PHP中调用外部的程序,再用PHPT进行单元测试,向下图这样。
设置相应的环境变量,然后运行单元测试(run-tests.php来自于PHP源码)。
通过strace查看进行PHP单元测试时的调用情况。
通过sh -c 执行了相应的命令。
自动化
这一步就比较简单了,跟原来的思路差不多,筛选掉一些干扰的情况就好了,代码不难实现,这里就不赘述了。
很遗憾的是,使用此方法,只筛选出了两个结果,其中一个还是测试结果。inscape在这里不可用,一是因为inscape不是自带的程序,二是因为传入的参数并不可控。
出现此种情况,我猜测一是因为Imagick本身的实现没有过多的依赖外部的程序,二是样本库(单元测试)并无法测试到全部情况,如同一函数的不同参数,不同函数调用的组合等,代码覆盖率不够高。
0x05 Conclusion
TCTF赛题的质量还是非常之高的,其中又很多值得学习并探讨的知识。虽然通过PHPT没有发现可以使用的函数,但是这个思路个人感觉还可以在其他地方使用,比如PHP源码中是自带对于源码的单元测试的,批量对PHP的源码的单元测试进行分析,发现可以利用的函数,当遇到其他的PHP扩展的时候理论上也可以使用此思路来发现可被利用的函数。