freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

JNDI注入工具改造
2022-11-17 13:14:55
所属地 北京

源码链接

(修改前的源码,因为feihong师傅的仓库已经不在了,这里使用的是Jeromeyoung师傅的源码进行改造)https://github.com/Jeromeyoung/JNDIExploit-1

0x00 JNDI注入工具代码结构分析

controllers模块:负责LDAP请求的处理

enum模块:负责存储各种模板类型名称,如:反序列化的Gadget、内存马的类型

异常模块:负责处理可能抛出的异常

反序列化模块:各种反序列化链的处理

模板模块:命令执行、回显、DNS、内存马模板

工具类模块:主要是为了方便而编写的一些工具类

协议服务及启动模块:负责LDAP、HTTP协议的具体实现

下面先对启动及协议服务模块进行说明

com.feihong.ldap.Starter类为整个工具的启动入口,从命令行接收参数传参到com.feihong.ldap.utils.Config类

Config类中的@Parameter注解为参数的说明及代表的意思,类似于py中的argparse,命令接收到参数,分别赋值给Config类的几个私有变量。

然后在之后的HTTPServer与LDAPServer中得到应用

关于LDAP服务端的编写和Demo可以参考以下链接:https://www.freebuf.com/vuls/253545.html,HTTPServer则是正常的Java Demo编写即可

第一部分注解的应用

在JNDIEXP中,作者为了可以反射一种类型的类,Controller类,这里的类起到了寻找特定类的作用,而且每个注解类都给定了uri属性

在LDAPServer.start()之前,会先通过new Reflections(this.getClass().getPackage().getName())的方法获取到com.feihong.ldap包下面所有LdapMapping的类,之后将其以键值对(TreeMap<String, LdapController>)放入到Map中,以便于后续调用

比如com.feihong.ldap.controllers.BasicController类,在Map中的存储格式就是(basic=>Object BasicController)

根据发送来的LDAP请求去决定调用哪个类,具体通过com.feihong.ldap.processSearchResult

根据工具运行的实际效果,如果我们的LDAP请求为ldap://192.168.85.1:1389/Basic/123

那么DN为Basic/123,首先根据DN中的开头字符串决定是哪个Controller来处理当前的LDAP的请求

第二部分服务端动态调用类

在LDAP调用LdapController接口实现类之后(以BasicController为例),会先调用process方法,以/为标志分割,获取到相应的模块名称,比如ldap://0.0.0.0:1389/Basic/Command/whoami,那么第一部分Basic用来指定是BasicController,Command指定执行BasicController下的命令执行模块

如果是命令执行模块

通过com.feihong.ldap.utils.Util的getCmdFromBase方法获取到执行命令的内容,如果是base编码的,进行base64解码后返回内容

将其赋值给params,之后再调用BasicController的sendResult方法,如果是command模块,初始化该模块,通过asm码的方法,这里为了避免出现类名重复的情况,使用随机字符命令类名

之后命令执行模块调用cache方法

将其存储在map中,之后开始进行LDAP的步骤

首先LDAP设定好

javaClassName:记录序列化对象的类名,这样应用程序就可以确定类信息,而不必首先反序列化

javaClassNames:关于序列化对象的附加类信息。

javaCodebase:实例化工厂所需的类定义的位置(HTTP地址)

javaFactory:用于存储对象工厂的完全限定类的可选属性(即类名)

一张图说明LDAP请求的过程

wKg0C2I4Qs6AAM4QAABoz1qOh2I020.png

接下来看HTTPServer如何接收HTTP请求并返回

当HTTPServer接收到请求之后,将Cache类中map存储的类写入到响应中,这样避免了class文件落地的情况。

0x01 去除server console内容

在这个JNDI的注入工具中,会在注入内存马的时候,使用系统输出语句,在控制台打印出东西,无关紧要的东西,直接去掉就好。

0x02 冰蝎3.11内存马注入

改造前的filter类,获取session是通过ServletRequest的方式获取的

改造之后的filter类,不再使用自写的classLoader而是直接使用URLClassLoader,同理对其他的组件也进行类似的改造,如:spring的Interceptor,weblogic和jboss的filter

所有回显使用的是header头的WWW-Authenticate字段,而非cmd

0x03 JDK版本匹配及tomcat版本兼容解决

利用JDK向下兼容的特性,这里使用JDK6编译filter class。

tomcat版本兼容,根据先知不久之前提出的,tomcat6-9的通用StandardContext获取方法,获取到StandardContext,接下来的问题就是解决tomcat版本识别与不同版本间filter注入的问题。

tomcat8以下版本FilterDef、FilterMap都在org.apache.catalina.deploy包里,tomcat8以上包括8都在org.apache.tomcat.util.descriptor.web里。

2.识别版本之后,进行不同版本间的filter注入

实现逻辑大概如下:

对各个版本的filter内存马全部转为字节码Base64的编码格式,通过loadClass的办法,根据版本注入到内存中。(class一律使用JDK1.6编译)

为了避免相关类加载不到的问题,这里统一使用反射写所有的filter注入步骤。

tomcat6789的StandardContext先知上已经给出了解决方案:

https://xz.aliyun.com/t/9914

对tomcat特定类进行筛选,来决定FilterDef和FilterMap类加载的使用,最后形成的Demo如下:

getStand的源码如下:

经测试,可用于常规的tomcat6、7(某凌)、8、9版本。

当所有的tomcat版本都测试完毕之后,发现这个通用方法对某远并不适用,原因是致远这里的ServerPort会永远等于-1。

解决方案是使用原版的feihong-jndi将TomcatMemShell2中的filter类替换为自定义的filter类即可。

0x04 spring memShell的改进

在一些版本的测试中,发现原版的JNDIExploit的spring并不适用于所有的spring框架场景,对此做出补充(借鉴自lz2y与microworld师傅的成果)

以ruoyi cms后台的snake yaml为例,lz2y师傅这里已经说了具体的原因(https://xz.aliyun.com/t/10651),直接使用师傅的Demo就好,我这里使用的是Windows的环境,使用比较在Linux和Windows都通用的Demo获取的WebApplicationContext

使用com.ruoyi.common.utils.spring.SpringUtils在windows ruoyi4.6.0的环境中没有成功(POC使用的是com.sun.rowset.JdbcRowSetImpl)

使用com.ruoyi.common.utils.spring.SpringUtils在windows ruoyi4.6.0的环境中成功(POC使用的是javax.script.ScriptEngineManager)

剩下的步骤直接注入内存马即可,实现Demo如下:

将其添加到类的引用处,对于spring的框架添加新增类的引用,需要修改的是四个类:

com.feihong.ldap.enumtypes.PayloadType

com.feihong.ldap.utils.Cache

com.feihong.ldap.controllers.BasicController

com.feihong.ldap.controllers.TomcatBypassController

修改Cache类是为了能够让恶意类能够在内存中加载,具体的原因已经在0.1中分析完毕,修改BasicController和TomcatBypassController是为了能在LDAP在JDK的高低版本中找到引用。

0x05 jetty memShell的改进

对于jetty内存马的改进,主要是log4j对solr的影响,针对于实战的场景,参考Qu3een师傅的文章(https://tttang.com/archive/1386/

实现的Demo如下,直接集成到JNDI注入工具中

修改com.feihong.ldap.enumtypes.PayloadType

修改com.feihong.ldap.utils.Cache

修改com.feihong.ldap.controllers.BasicController

0x06 webSphere memShell的改进

暂缺

0x07 增加resin中间件下的内存马注入

基于pen4uin师傅的通用研究成果直接集成到JNDI注入工具中,原理不再赘述,参考pen4uin师傅的公众号即可,直接给出Demo

同样的,修改com.feihong.ldap.enumtypes.PayloadType

修改com.feihong.ldap.utils.Cache

修改com.feihong.ldap.controllers.BasicController

0x08 增加tomcatValue内存马

在tomcat容器中,有些场景filter内存马并不如valve内存马,所以为了增加兼容性,这里增加valve内存马,实现的Demo大致如下:

同样的修改配置文件,增加到BasicController、TomcatBypassController、Cache、Config中。

参考链接

https://landgrey.me/blog/19/

https://github.com/Mr-xn/JNDIExploit-1

https://tttang.com/archive/1386/

https://mp.weixin.qq.com/s/5s9eyRpaP7WhVd2estwtKg

https://github.com/lz2y/yaml-payload-for-ruoyi

https://xz.aliyun.com/t/10651

# web安全 # 网络安全技术
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录