是否遇到过费劲九牛二虎之力拿了webshell却发现连个scandir都执行不了?拿了webshell确实是一件很欢乐的事情,但有时候却仅仅只是一个小阶段的结束;本文将会以webshell作为起点从头到尾来归纳bypass disable function的各种姿势。 从phpinfo中获取可用信息信息收集是不可缺少的一环;通常的,我们在通过前期各种工作成功执行代码 or 发现了一个phpinfo页面之后,会从该页面中搜集一些可用信息以便后续漏洞的寻找。 我谈谈我个人的几个偏向点: 版本号最直观的就是php版本号(虽然版本号有时候会在响应头中出现),如我的机器上版本号为: 那么找到版本号后就会综合看看是否有什么"版本专享"漏洞可以利用。 DOCUMENT_ROOT接下来就是搜索一下DOCUMENT_ROOT取得网站当前路径,虽然常见的都是在/var/www/html,但难免有例外。 disable_functions这是本文的重点,disable_functions顾名思义函数禁用,以笔者的kali环境为例,默认就禁用了如下函数:
open_basedir该配置限制了当前php程序所能访问到的路径,如笔者设置了: 随后我们能够看到phpinfo中出现如下: 尝试scandir会发现列根目录失败。 opcache如果使用了opcache,那么可能达成getshell,但需要存在文件上传的点,直接看链接: https://www.cnblogs.com/xhds/p/13239331.html others如文件包含时判断协议是否可用的两个配置项: allow_url_include、allow_url_fopen 上传webshell时判断是否可用短标签的配置项: short_open_tag 还有一些会在下文讲到 bypass open_basedir因为有时需要根据题目判断采用哪种bypass方式,同时,能够列目录对于下一步测试有不小帮助,这里列举几种比较常见的bypass方式,均从p神博客摘出,推荐阅读p神博客原文,这里仅作简略总结。 syslinkhttps://www./manual/zh/function.symlink.php
简单来说就是建立软链达成bypass。 代码实现如下: 首先是创建一个link,将tmplink用相对路径指向abc/abc/abc/abc,然后再创建一个link,将exploit指向tmplink/../../../../etc/passwd,此时就相当于exploit指向了abc/abc/abc/abc/../../../../etc/passwd,也就相当于exploit指向了./etc/passwd,此时删除tmplink文件后再创建tmplink目录,此时就变为/etc/passwd成功跨目录。 glob
常用bypass方式如下:但会发现比较神奇的是只能列举根目录下的文件。 chdir()与ini_set()chdir是更改当前工作路径。 利用了ini_set的open_basedir的设计缺陷,可以用如下代码观察一下其bypass过程: bindtextdomain该函数的第二个参数为一个文件路径,先看代码: Realpath同样是基于报错,但realpath在windows下可以使用通配符 other如命令执行事实上是不受open_basedir的影响的。 bypass disable function蚁剑项目仓库中有一个各种disable的测试环境可以复现,需要环境的师傅可以选用蚁剑的环境。 https://github.com/AntSwordProject/AntSword-Labs 黑名单突破这个应该是最简单的方式,就是寻找替代函数来执行,如system可以采用如反引号来替代执行命令。 看几种常见用于执行系统命令的函数 system,passthru,exec,pcntl_exec,shell_exec,popen,proc_open,`` 当然了这些也常常出现在disable function中,那么可以寻找可以比较容易被忽略的函数,通过函数 or 函数组合拳来执行命令。
ShellShock原理本质是利用bash破壳漏洞(CVE-2014-6271)。 影响范围在于bash 1.14 – 4.3 关键在于:
因为是设置环境变量,而在php中存在着putenv可以设置环境变量,配合开启子进程来让其执行命令。 利用https://www./exploits/35146 ImageMagick原理漏洞源于CVE-2016-3714,ImageMagick是一款图片处理程序,但当用户传入一张恶意图片时,会造成命令注入,其中还有其他如ssrf、文件读取等,当然最致命的肯定是命令注入。 而在漏洞出来之后各位师傅联想到php扩展中也使用了 关于更加详细的漏洞分析请看p神的文章:CVE-2016-3714 - ImageMagick 命令执行分析,我直接摘取原文中比较具有概括性的漏洞说明:
漏洞的利用极其简单,只需要构造一张恶意的图片,new一个类即可触发该漏洞: 利用那么依旧以靶场题为例,依旧以拥有一句话马儿为前提,我们首先上传一个图片,如上面所述的我们图片的后缀无需mvg,因此上传一个jpg图片: 那么因为我们看不到回显,所以可以考虑将结果写入到文件中,或者直接执行反弹shell。然后如上上传一个poc.php: 访问即可看到我们写入的文件。那么这一流程颇为繁琐(当我们需要多次执行命令进行测试时就需要多次调整图片内容),因此我们可以写一个php马来动态传入命令: LD_PRELOAD喜闻乐见的LD_PRELOAD,这是我学习web时遇到的第一个bypass disable的方式,个人觉得很有意思。 原理
而我们bypass的关键就是利用LD_PRELOAD加载库优先的特点来让我们自己编写的动态链接库优先于正常的函数库,以此达成执行system命令。 因为id命令比较易于观察,网上文章也大同小异采用了id命令下的getuid/getgid来做测试,为做个试验笔者换成了 我们先看看id命令的调用函数: strace -f /usr/bin/id Resulut: close(3) = 0geteuid32() = 0getuid32() = 0getegid32() = 0getgid32() = 0(省略....)getgroups32(0, NULL) = 1getgroups32(1, [0]) = 1
man getgroups32 看到这一部分: 得到了函数的定义,我们只需要编写其内的getgroups即可,因此我编写一个hack.c:、
gcc -shared -fPIC hack.c -o hack.so 使用LD_PRELOAD加载并执行id命令,我们会得到如下的结果: 再来更改一下uid测试,我们先adduser一个新用户hhhm,执行id命令结果如下: 然后根据上面的步骤取得getuid32的函数定义,据此来编写一个hack.c: gcc编译后,执行,结果如下: 可以看到我们的uid成功变为1,且更改为root了,当然了因为我们的hack.so是root权限编译出来的,在一定条件下也许可以用此种方式来提权,网上也有相关文章,不过我没实际尝试过就不做过分肯定的说法。 下面看看在php中如何配合利用达成bypass disable。 php中的利用php中主要是需要配合putenv函数,如果该函数被ban了那么也就没他什么事了,所以bypass前需要观察disable是否ban掉putenv。 php中的利用根据大师傅们的文章我主要提取出下面几种利用方式,其实质都是大同小异,需要找出一个函数然后采用相同的机制覆盖掉其函数进而执行系统命令。 那么我们受限于disable,system等执行系统命令的函数无法使用,而若想要让php调用外部程序来进一步达成执行系统命令从而达成bypass就只能依赖与php解释器本身。 因此有一个大前提就是需要从php解释器中启动子进程。 老套路之mail先选取一台具有sendmail的机器,笔者是使用kali,先在php中写入如下代码 <?phpmail("","","",""); 同样的可以使用strace来追踪函数的执行过程。 strace -f php phpinfo.php 2>&1 | grep execve 可以看到这里调用了sendmail,与网上的文章同样的我们可以追踪sendmail来查看其调用过程,或者使用readelf可以查看其使用函数: strace sendmail 那么以上面的方式编写并编译一个动态链接库然后利用LD_PRELOAD去执行我们的命令,这就是老套路的利用。 同样的gcc编译后,页面写入如下: 访问页面得到运行效果如下: 再提一个我在利用过程中走错的点,这里为测试,我换用一台没有sendmail的ubuntu: 但如果我们按照上面的步骤直接追踪index的执行而不过滤选取execve会发现同样存在着geteuid,并且但这事实上是sh调用的而非mail调用的,因此如果我们使用php index.php来调用会发现system执行成功,但如果我们通过页面来访问则会发现执行失败,这是一个在利用过程中需要注意的点,这也就是为什么我们会使用管道符来选取execve。 error_log同样的除了mail会调用sendmail之外,还有error_log也会调用,如图: ps:当error_log的type为1时就会调用到sendmail。 因此上面针对于mail函数的套路对于error_log同样适用,however,我们会发现此类劫持都只是针对某一个函数,而前面所做的都是依赖与sendmail,而像目标机器如果不存在sendmail,那么前面的做法就完全无用。 yangyangwithgnu师傅在其文无需sendmail:巧用LD_PRELOAD突破disable_functions提到了我们不要局限于仅劫持某一函数,而应考虑劫持共享对象。 劫持共享对象文中使用到了如下代码编写的库: 那么关于 同样的将LD_PRELOAD指定为gcc编译的共享库,然后访问页面查看,会发现成功将ls写到test下(如果失败请检查写权限问题) 0ctf 2019中Wallbreaker Easy中的出题点就是采用了imagick在处理一些特定后缀文件时,会调用ffmpeg,也就是会开启子进程,从而达成加载共享库执行系统命令bypass disable。 Apache Mod CGI前面的两种利用都需要putenv,如果putenv被ban了那么就需要这种方式,简单介绍一下原理。 原理利用htaccess覆盖apache配置,增加cgi程序达成执行系统命令,事实上同上传htaccess解析png文件为php程序的利用方式大同小异。 mod cgi:
因此我们只需上传一个.htaccess: 利用利用就很简单了:
PHP-FPMphp-fpm相信有读者在配置php环境时会遇到,如使用nginx+php时会在配置文件中配置如下:
那么fastcgi又是什么?Fastcgi 是一种通讯协议,用于Web服务器与后端语言的数据交换。 原理那么我们在配置了php-fpm后如访问http://127.0.0.1/test.php?test=1那么会被解析为如下键值对: 这个数组很眼熟,会发现其实就是 前面笔者留了一个配置,在配置中可以看到fastcgi的端口是9000,监听地址是127.0.0.1,那么如果地址为0.0.0.0,也即是将其暴露到公网中,倘若我们伪造与fastcgi通信,这样就会导致远程代码执行。 那么事实上php-fpm通信方式有tcp也就是9000端口的那个,以及socket的通信,因此也存在着两种攻击方式。 socket方式的话配置文件会有如下: fastcgi_pass unix:/var/run/phpfpm.sock; 那么我们可以稍微了解一下fastcgi的协议组成,其由多个record组成,这里摘抄一下p神原文中的一段结构体: 可以看到record分为header以及body,其中header固定为8字节,而body由其contentLength决定,而paddingData为保留段,不需要时长度置为0。 而type的值从1-7有各种作用,当其type=4时,后端就会将其body解析成key-value,看到key-value可能会很眼熟,没错,就是我们前面看到的那一个键值对数组,也就是环境变量。 那么在学习漏洞利用之前,我们有必要了解两个环境变量,
那么以p神文中的利用方式我们需要满足三个条件:
此时熟悉文件包含漏洞的童鞋就一目了然了,我们可以执行任意代码了。 这里利用的情况为: 利用我们先直接看phpinfo如何标识我们可否利用该漏洞进行攻击。 那么先以攻击tcp为例,倘若我们伪造nginx发送数据(fastcgi封装的数据)给php-fpm,这样就会造成任意代码执行漏洞。 p神已经写好了一个exp,因为开放fastcgi为0.0.0.0的情况事实上同攻击内网相似,所以这里可以尝试一下攻击127.0.0.1也就是攻击内网的情况,那么事实上我们可以配合gopher协议来攻击内网的fpm,因为与本文主题不符就不多讲。 可以看到结果如图所示: 攻击成功后我们去查看一下phpinfo会看到如下: 也就是说我们构造的攻击包为: 很明显的前面所说的都是成立的;然而事实上我这里是没有加入disable的情况,我们往里面加入disable再尝试。 pkill php-fpm/usr/sbin/php-fpm7.0 -c /etc/php/7.0/fpm/php.ini 注意修改了ini文件后重启fpm需要指定ini。 我往disable里压了一个system: 然后再执行一下exp,可以发现被disable了: 因此此种方法还无法达成bypass disable的作用,那么不要忘了我们的两个php_value能够修改的可不仅仅只是auto_prepend_file,并且的我们还可以修改basedir来绕过;在先前的绕过姿势中我们是利用到了so文件执行扩展库来bypass,那么这里同样可以修改extension为我们编写的so库来执行系统命令,具体利用有师傅已经写了利用脚本,事实上蚁剑中的插件已经能实现了该bypass的功能了,那么下面我直接对蚁剑中插件如何实现bypass做一个简要分析。 在执行蚁剑的插件时会发现其在当前目录生成了一个.antproxy.php文件,那么我们后续的bypass都是通过该文件来执行,那么先看一下这个shell的代码: 定位到关键代码: 可以看到它这里向60882端口进行通信,事实上这里蚁剑使用 那么启动了该php server后我们的流量就通过antproxy.php转发到无disabel的php server上,此时就成功达成bypass。 加载so扩展前面虽然解释了其原理,但毕竟理论与实践有所区别,因此我们可以自己打一下extension进行测试。 so文件可以从项目中获取,根据其提示编译即可获取ant.so的库,修改php-fpm的php.ini,加入: extension=/var/www/html/ant.so 然后重启php-fpm,如果使用如下: 成功执行命令时即说明扩展成功加载,那么我们再把ini恢复为先前的样子,我们尝试直接攻击php-fpm来修改其配置项。 以脚本来攻击: 通过修改其内的code即可,效果如下: 漏洞利用成功。 com组件原理&利用需要目标机器满足下列三个条件:
此时com组件开启,我们能够在phpinfo中看到: 要知道原理还是直接从exp看起: 首先,以 然后这个com对象中存在着exec可以用来执行命令,而后续的方法则是将命令输出,该方式的利用还是较为简单的,就不多讲了。 imap_open该bypass方式为CVE-2018-19518 原理imap扩展用于在PHP中执行邮件收发操作,而imap_open是一个imap扩展的函数,在使用时通常以如下形式: $imap = imap_open('{'.$_POST['server'].':993/imap/ssl}INBOX', $_POST['login'], $_POST['password']); 那么该函数在调用时会调用rsh来连接远程shell,而在debian/ubuntu中默认使用ssh来代替rsh的功能,也即是说在这俩系统中调用的实际上是ssh,而ssh中可以通过 那么我们可以先在ubuntu上试验一下: ssh -oProxyCommand="ls>test" 192.168.2.1 利用环境的话vulhub上有,其中给出了poc:
我们可以发现其中使用了%09来绕过空格,以base64的形式来执行我们的命令,那么我这里再验证一下: hostname=x+-oProxyCommand%3decho%09bHM%2BdGVzdAo%3D|base64%09-d|sh}&username=111&password=222//ls>test 会发现成功写入了一个test,漏洞利用成功,那么接下来就是各种肆意妄为了。 三种UAFEXP在:https://github.com/mm0r1/exploits 三种uaf分别是:
关于uaf的利用因为涉及到二进制相关的知识,而笔者是个web狗,因此暂时只会用exp打打,因此这里就不多说,就暂时先稍微提一下三种uaf的利用版本及其概述//其实我就是照搬了exp里面的说明,读者可以看exp作者的说明就行了。 Json Serializer UAF漏洞出现的版本在于:
漏洞利用json在序列化中的堆溢出触发bypass,漏洞为bug #77843 GC UAF漏洞出现的版本在于:
漏洞利用的是php garbage collector(垃圾收集器)程序中的堆溢出达成bypass,漏洞为:bug #72530 Backtrace UAF漏洞出现的版本在于:
漏洞利用的是 debug_backtrace这个函数,可以利用该函数的漏洞返回已经销毁的变量的引用达成堆溢出,漏洞为bug #76047 利用利用的话exp或者蚁剑上都有利用插件了,这里不多讲,可以上ctfhub测试。 SplDoublyLinkedList UAF概述这个UAF是在先知上看到的,引用原文来概述:
expexp同样出自原文。 php部分:
python部分: ffi扩展ffi扩展笔者初见于TCTF/0CTF 2020中的easyphp,当时是因为非预期解拿到flag发现了ffi三个字母才了解到php7.4中多了ffi这种东西。 原理PHP FFI(Foreign Function interface),提供了高级语言直接的互相调用,而对于PHP而言,FFI让我们可以方便的调用C语言写的各种库。 也即是说我们可以通过ffi来调用c语言的函数从而绕过disable的限制,我们可以简单使用一个示例来体会一下: 输出如下: 那么这种利用方式可能出现的场景还不是很多,因此笔者稍微讲解一下。 首先是cdef: 这一行是创建一个ffi对象,默认就会加载标准库,以本行为例是导入system这个函数,而这个函数理所当然是存在于标准库中,那么我们若要导入库时则可以以如下方式: 可以看看其函数原型: 取得了ffi对象后我们就可以直接调用函数了: 之后的代码较为简单就不多讲,那么接下来看看实际应用该从哪里入手。 利用以tctf的题目为例,题目直接把cdef过滤了,并且存在着basedir,但我们可以使用之前说过bypass basedir来列目录,逐一尝试能够发现可以使用glob列根目录目录: 可以发现根目录存在着flag.h跟so: 因为后面环境没有保存,笔者这里简单复述一下当时题目的情况(仅针对预期解)。 发现了flag.h之后查看ffi相关文档能够发现一个load方法可以加载头文件。 于是有了如下: 但当我们想要打印头文件来获取其内存在的函数时会尴尬的发现如下: 我们无法获取到存在的函数结构,因此也就无法使用ffi调用函数,这一步路就断了,并且cdef也被过滤了,无法直接调用system函数,但查看文档能够发现ffi中存在着不少与内存相关的函数,因此存在着内存泄露的可能,这里借用飘零师傅的exp: 获取到函数名后直接调用函数然后把结果打印出来即可: |
|
来自: 昵称73595512 > 《PHP》