FilelessAgentMemShell是一款用于自定义生成用于注入Agent内存马的classFile的小工具
Agent内存马的工作原理是利用Java Instrument API 动态修改 正在JVM中的运行着的类字节码,选择合适的宿主类,就可以在不添加新类的前提下实现内存马逻辑
过去,这项技术需要文件落地才可使用,好在 rebeyond 游望之 提出了无文件落地利用方式,使得通过反序列化漏洞/JNDI注入来一步打入Agent内存马有了可能
本工具对于前人给出的EXP进行了小幅修改,可以根据不同目标环境和应用场景,简单快速地生成用于注入Agent内存马的classFile
有关Agent内存马以及其无文件落地技术的原理,可参考以下文章:
对于Java Agent技术以及其内存马的简单介绍 https://www.freebuf.com/articles/web/323621.html
Java内存攻击技术漫谈 https://xz.aliyun.com/t/10075
论如何优雅的注入Java Agent内存马 https://xz.aliyun.com/t/11640
Linux下无文件Java agent探究 https://tttang.com/archive/1525
Linux下内存马进阶植入技术 https://xz.aliyun.com/t/10186
建议结合无文件落地注入Agent内存马实操食用,完成第一次模拟注入实验
本项目基于Java8
小的更新不会发布release,可以自行编译
也可以在release中直接下载jar包
首先请确保 jar文件的同目录下有MemShellSrc
和out
两个文件夹,前者可以在仓库中找到,后者用于存放工具所生成的class文件,置空即可
请使用 Java8 运行
java -jar FilelessAgentMemShell.jar
Agent内存马的工作原理是利用Java Instrument API 动态修改JVM中运行着的类字节码,从而在不添加新类的前提下实现内存马逻辑
为此,你需要:
一般选择目标请求处理逻辑中的某一环
在Tomcat环境中,这个类可以是
- org.apache.tomcat.websocket.server.WsFilter #doFilter()(推荐,代码少且无lambda表达式)
- org.apache.catalina.core.StandardContextValve #invoke()(推荐,代码少且无lambda表达式)
- org.apache.catalina.core.ApplicationFilterChain #doFilter()(不推荐,代码多且有lambda表达式)
- org.springframework.web.servlet.DispatcherServlet(不推荐,代码多)
- javax.servlet.http.HttpServlet #service()(Tomcat9之后/Weblogic环境下,包前缀是
jakarta
/weblogic
)(不推荐,代码多)
你可以使用Javassist工具方便的生成新字节码,一般来说可以使用insertBefore在目标方法前添加shell逻辑,以在不影响正常逻辑的前提下实现内存马
如需选用包含lambda表达式的宿主类,你必须先使用ASM框架删除包含有lambda表达式的方法的所有内容,再使用Javassist等框架进行二次编辑
有关Javassist框架的使用方法,可参照文档:
Javassist https://www.cnblogs.com/rickiyang/p/11336268.html
至于ASM框架,从未接触过到完全掌握需要较大时间成本,在本项目中其使用场景较为单一,所以也可以直接套用我在**使用指南**中给出的示例代码
如果你完全不想接触这部分工具,也可以直接使用我给出的测试类WsFilter.class;未来或许会给出实战可用的针对常见类的新字节码,详见更新计划
测试完成之后,建议自己编写新类,因为动态替换字节码意味着你几乎可以做到任何事,对抗检测、循环复活、更改硬编码密钥.......
以下是命令行参数
- -c className;eg:
org.apache.catalina.core.StandardContextValve
(宿主类的全限定类名) - -p Path; eg:
/path/test.class
(新类字节码路径) - -o os; eg:
Linux/Windows
(目标操作系统) - -t templatesImpl; eg:
true/false
(是否使用templatesImpl来加载类) - -i ifbeyondJDK8; eg:
true/false
(目标JDK版本是否大于8,仅目标为Windows时需要填写) - -b eg:
32/64
(目标操作系统位数,仅对于Windows目标可指定)
例如,在使用本项目提供的漏洞环境与测试用新类进行模拟测试时,你应该指定如下参数
java -jar .\FilelessAgentMemshellGenerator.jar
-b 64
-c "org.apache.tomcat.websocket.server.WsFilter"
-i false
-o "Windows"
-p .\WsFilter.class
-t false
- 如果帮助信息出现乱码,请使用
chcp 936
修改字符编码后重新运行项目 - 建议使用JDK低版本,以提高生成classFile的兼容性
- -c指定的类名必须是全限定名
内存马仅仅是代码执行的一种效果,并且它只有在动态代码执行上下文中才能发挥作用
什么叫动态代码执行上下文?一个很简单的例子,CC6链(套娃调用invoke,最终执行Runtime.getRuntime().exec())那条,就不属于动态代码执行上下文
详细请看Ruilin师傅的:http://rui0.cn/archives/1408
而那些能动态加载字节码的sink,比如反序列化漏洞中的templatesImpl,低版本JNDI注入,就属于动态代码执行上下文
利用工具生成最终类,其静态代码块中包含自注入逻辑;使用反序列化漏洞/JNDI注入漏洞让目标动态加载类,这就完成了攻击
使用中如遇乱码,可使用chcp 936切换字符编码
JDK8 ~ JDK11
暂未测试 Windows 32bit
暂不支持 Linux 32bit
- 测试所有可用的JDK版本
- 预置在常见宿主类中实现内存马逻辑的成品类
- 提供自动化缩短payload长度的逻辑;提供分割最终字节码的逻辑,以适配分块传输
- 实现msf、ysomap等工具的cli交互模式;提供英文版ReadMe;开发图形化
- 联动其它攻击工具,更方便地一次打入Agent内存马
- 实现 cincly 师傅提出的“借尸还魂”技术
- 提供随机类名,规避类的重复加载问题
- 解决loadLibrary引起的一次攻击失败后续就不能再攻击问题
本人在学习及实操无文件落地注入Agent内存马相关技术时需要经常测试可用的宿主类、不同JDK版本,有时还需要对shell逻辑进行修改,重复的修改、编译十分浪费时间
我意识到可以编写一款简单的小工具来解决这个问题,经过一段时间的工作和反复修改,FilelessAgentMemShell诞生了
未经目标授权使用本项目(FilelessAgentMemShell)给目标植入内存马是非法的,本项目应用于且仅用于授权的安全测试与学习研究目的
任何使用及滥用本项目造成的后果与本人无关