SMB 这个话题,我在内网项目里碰到过太多次了。很多人对它的印象还停留在“Windows共享文件夹”,觉得就是个方便同事传文件的工具,直到某天看到一份渗透测试报告,才发现同一台机器上的 445 端口,在攻击者眼里几乎是整个域内横向移动的起点。这篇文章我想把话说透:在授权测试的环境里,Kali 上那套围绕 SMB 的工具链到底是怎么运转的,每一条命令背后在验证什么假设,哪些配置项是真正的高危放大器,以及作为防守方,你该按什么顺序把它们一个个堵上。标题里用了“破解”这个词,我得更正一下:在合规语境下这叫口令强度评估与共享权限审计,不是拿别人东西开锁。全文里的 IP、主机名、目录名全部是靶场虚构值,场景设定为“某公司授权的一次内网安全评估”,你自己动手时请务必也守住这条线。适合谁看?刚入门内网方向的安全从业者、需要自查共享配置的运维、以及想搞明白“为什么我们公司不允许随便开共享”的开发同学。
1. 先把SMB这事儿说清楚:它为什么是高价值目标
1.1 SMB到底在做什么,版本差异直接决定风险面
SMB 全称 Server Message Block,本质是一套“远程文件与资源访问协议”。你可以把它理解成办公室里的一台公共文件柜:客户端走过去说“我要开第二层第三个抽屉”,服务器验证你有钥匙,然后把抽屉拉开。这个类比里藏着两个关键点——验证和授权,SMB 绝大部分安全问题都出在这两件事上,而不是协议本身写得不好。
历史上 SMB 经历过三代演进:SMB1(1980 年代设计,NetBIOS 时代的产物)、SMB2(2006 年随 Vista 引入,协议消息大幅精简)、SMB3(2012 年起,加入了加密、多通道、持续可用等企业级特性)。这个版本差异不是学术问题,它直接决定了你的攻击面有多大。
SMB1 的问题在于设计年代太早,那时候没人考虑过对抗性环境。它的消息结构复杂、解析路径长、错误处理粗糙,历史上大量远程代码执行漏洞都出在 SMB1 的解析逻辑里。更麻烦的是 SMB1 支持一种叫“空会话”(Null Session)的机制——不提供任何凭证也能建立连接,并查询一部分系统信息。这在当年是为了方便局域网发现,放到今天就是白送的情报。
SMB2/SMB3 在协议层面收紧了很多,SMB3 还引入了 AES 加密和签名强制能力。但请注意关键词:能力。协议支持不等于默认开启,也不等于你的环境真的配了。我见过太多环境,服务器是新的,系统是新的,结果 SMB 签名还是关的,SMB1 还留着,原因往往是某个十年前的老设备、某台老打印机、某个没人敢动的旧业务系统还在依赖它。
所以判断一个环境的 SMB 风险,不能只看“系统版本新旧”,得看四个实际配置项:SMB1 是否启用、签名是否强制、加密是否启用、Guest 账户是否可用。这四项构成了后面所有讨论的基础。
1.2 攻击者视角下的三条路径:情报、凭证、漏洞
我在做授权评估时,习惯把 SMB 相关的切入点归纳成三条线,这三条线的门槛和收益完全不同,理解它们的差异对防守方排优先级特别有用。
第一条是情报线。不需要任何凭证,靠端口探测、协议协商、匿名会话就能拿到大量信息:主机名、域名、操作系统版本、共享列表、部分用户列表、密码策略。这条线的“危害”看起来最轻,但它是后面所有攻击的侦察基础。很多单位忽略了这条线,觉得“只是看到了共享名而已”,实际上共享名往往直接暴露业务结构,财务归档$、HR-2023备份这种命名,攻击者看一眼就知道该往哪使劲。
第二条是凭证线。一旦拿到一个合法账户(哪怕是低权限的普通域用户),SMB 就成了横向移动的主干道。口令喷洒、哈希传递、从共享里翻配置文件捞明文密码,都是围绕这条线展开的。这条线的特点是不需要漏洞,纯靠配置和人的习惯,所以补丁打满了也挡不住。
第三条是漏洞线。就是那些能直接远程打穿的历史高危漏洞。这条线在真实环境里的命中率其实在下降,因为大部分单位补丁管理已经规范了,但在一些隔离网、老旧产线系统、医疗设备配套主机上仍然存在。
我画张表把这三点摆清楚,你对照自己环境看:
| 路径 | 前置条件 | 典型手法 | 检测难度 | 防护优先级 |
|---|---|---|---|---|
| 情报收集 | 仅需 445 端口可达 | 匿名会话枚举、共享列表、OS 指纹 | 低(日志少) | 高(成本最低) |
| 凭证滥用 | 需一个有效账户或哈希 | 口令喷洒、哈希传递、配置泄露 | 中(有登录日志) | 最高 |
| 漏洞利用 | 需存在未修补漏洞 | 协议解析类远程执行 | 高(易被忽略) | 中(补丁即可) |
这张表最想传达的信息是:防守资源要往“凭证线”倾斜。漏洞打个补丁就没了,凭证泄露是持续性的,一个离职员工留下的本地管理员口令,可能三年都没人改。
1.3 一个常被误判的点:共享权限和 NTFS 权限是两套东西
这个坑我必须单独拎出来讲,因为我在评估报告里见过太多误判。Windows 上访问一个共享文件,要过两道门:共享权限(Share Permission)和NTFS 权限(文件系统 ACL)。最终生效的是两者中更严格的那一个。
很多运维以为“我把共享权限设成 Everyone 只读,就安全了”,但他没意识到 NTFS 权限如果给了 Everyone 完全控制,那么本地登录或者通过其他途径(比如远程桌面、其他共享的父目录)依然能改文件。反过来,共享权限给了完全控制但 NTFS 只读,实际效果就是只读。
这个机制在评估时的意义是:你不能只看net share的输出就下结论,得同时看两边的 ACL。Kali 侧的smbmap给出的权限标记(READ/WRITE)是基于实际尝试的结果,比命令行配置更可信,这也是我偏爱用它的原因——它验证的是“实际能不能写”,而不是“配置上写了什么”。
注意:判断共享是否可写,务必用实际写入测试(在临时目录里建一个空文件再删掉),不要只看权限位。我遇到过一次,配置显示只读,但因为上层目录继承了写权限,实际能写。
2. 靶场与工具链:所有测试都在自己手里跑
2.1 靶场怎么搭才靠谱:隔离、快照、可回滚
动手之前先解决环境。我的习惯是永远不在真实生产环境里做任何“试探性”操作,哪怕客户说“随便试”。原因很实际:一次失败的认证尝试可能会锁定账户,一次误写可能覆盖业务文件,这类事故的善后成本远超测试本身的价值。
靶场配置我有一个固定套路。宿主机上用虚拟化平台起三台机器:一台 Kali 作为测试端,一台 Windows Server 作为“文件服务器”靶机,一台 Windows 客户端用来模拟域内普通用户。网络设置为仅主机模式或者一个独立的内部虚拟网络,绝对不要桥接到物理网卡。这一步看起来啰嗦,但它保证了你后面所有的扫描、爆破、写入操作都被关在一个盒子里。
靶机建好第一件事是打快照。我一般会打两个点:一个是“干净初始态”,一个是“配置了脆弱共享的测试态”。这样每轮测试结束直接回滚,省去重装的时间。你别小看这个习惯,做口令喷洒测试的时候,账户锁定策略会把你锁在门外,回滚比重置密码快得多。
靶机上要故意配置出几类典型脆弱场景,这样你才能验证检测规则是否生效:
- 一个允许匿名列举的共享(模拟老式打印服务器配套目录)
- 一个 Everyone 可写的共享(模拟“临时传文件”目录)
- 一个开启了 SMB1 的兼容模式(模拟老设备依赖)
- 一个 Guest 账户启用的配置
- 一个弱口令的本地账户(模拟“测试账号忘了删”)
这五类场景基本覆盖了真实环境里 80% 的 SMB 配置问题。你在靶场里把每一类的“攻击表现”和“日志表现”都跑一遍,比看十篇文章都有用。
2.2 Kali 侧工具清单与选型理由
Kali 自带的相关工具很多,但真正高频使用的就那么几个。我把它们按“在流程中的位置”列出来,并说明为什么选它而不是别的:
| 工具 | 在流程中的位置 | 选它的理由 | 替代方案 |
|---|---|---|---|
nmap+ smb 脚本族 | 侦察 | 一条命令同时拿端口、版本、签名状态、共享列表 | masscan(更快但无脚本能力) |
enum4linux-ng | 匿名枚举 | 把零散的 rpcclient 查询打包成结构化输出 | 手动rpcclient(灵活但慢) |
smbmap | 共享权限判读 | 直接标注读写权限,支持递归列目录 | smbclient(需手动 ls) |
smbclient | 交互式访问 | 类似 FTP 的操作手感,适合精细操作 | 挂载cifs(需要 root 且易残留) |
netexec(nxc) | 批量凭证验证 | 支持多协议、结果表格化、可断点续跑 | crackmapexec(已停止维护) |
impacket套件 | 哈希传递与远程执行验证 | 纯 Python,参数透明,便于理解协议细节 | Metasploit 模块(黑盒感强) |
hashcat | 哈希还原验证 | GPU 加速,规则引擎灵活 | john(CPU 友好) |
选型上我有两个偏好值得说。第一,优先用能输出结构化结果的工具。评估报告需要可复现的证据,smbmap的表格输出直接能贴进报告,而smbclient的交互式输出还得手工整理。第二,优先用参数透明的工具。impacket的每个参数你都能在源码里找到对应位置,用它做完一次哈希传递,你对 NTLM 认证流程的理解会比用 Metasploit 深一个层次。工具用得越“傻瓜”,你对底下发生了什么就越糊涂,这在安全领域是要命的。
2.3 合规边界先划清楚,再谈技术
这一段可能有人觉得多余,但我必须放在前面。一次 SMB 相关的测试涉及的操作包括:端口扫描、账户认证尝试、文件读写、可能的服务中断。这四件事每一件都可能在未授权情况下构成问题。
我在项目里的固定做法是:书面授权里必须明确三件事——测试的 IP 段范围、允许的时间窗口、明确禁止的操作清单(比如禁止对生产数据库所在主机做写入测试、禁止在业务高峰期做口令喷洒)。测试过程中保持一份操作日志,记录每条命令的执行时间和目标,出问题时这是唯一的自证材料。
还有一条经验:口令喷洒一定先确认账户锁定策略。在 Windows 域环境里,默认的锁定阈值可能是 5 次或 10 次失败,一旦触发,整个部门的账号被锁,业务直接停摆。正确顺序是先通过低权限途径读取密码策略(匿名会话有时能拿到,或者让客户方管理员直接告诉你),然后按“每账户尝试次数 < 锁定阈值 - 2”的原则控制节奏,账户之间拉开时间间隔。
注意:这条不是技术建议,是职业底线。任何一次未经授权的测试,无论技术多漂亮,都不值得。
3. 信息收集:从端口到共享,一层层剥
3.1 端口与服务指纹:先确认对面到底是不是 SMB
第一步永远是确认目标。SMB 走 TCP 445(直接承载)和 TCP 139(NetBIOS 会话服务承载),UDP 137/138 是老的名字解析和浏览服务。现代环境里 445 是主通道,139 大多数时候可以关掉,但它的存在本身就是一个信号——说明这台机器可能还带着上世纪的习惯。
我用得最顺的一条命令是这样的:
nmap -Pn -p 139,445 -sV \ --script "smb-os-discovery,smb-security-mode,smb2-security-mode,smb2-time,smb-enum-shares" \ 10.10.10.20参数逐个解释一下,因为它们各自解决一个具体问题。-Pn是跳过主机存活探测,因为 Windows 防火墙经常丢弃 ICMP,不加这个你会得到“host seems down”的假阴性。-sV做版本识别,能区分出 SMB1 和 SMB2 的协商偏好。脚本部分:
smb-os-discovery拿主机名、域名、操作系统版本、系统时间。系统时间这个信息很多人忽略,它在后续分析 Kerberos 票据时间戳时会用到。smb-security-mode看 SMB1 的签名状态。smb2-security-mode看 SMB2/SMB3 的签名要求。这两个必须都跑,因为很多环境 SMB1 关了但 SMB2 签名没强制,风险依然存在。smb-enum-shares在允许匿名的情况下直接列出共享。
脚本输出的解读有个细节:smb2-security-mode会明确告诉你 "Message signing enabled but not required" 或者 "required"。enabled but not required 意味着客户端可以选择不签名,这就是中间人攻击的窗口。只有 "required" 才是真安全。我在报告里从来不用“已启用签名”这种模糊表述,一律写“签名要求:required / not required”。
3.2 匿名会话与空会话枚举:不需要密码能拿到什么
匿名会话探测是我认为性价比最高的一个检查项。它不需要任何凭证,不产生失败登录日志,但能暴露的信息量惊人。
# 尝试建立空会话并列出共享 smbclient -L //10.10.10.20 -N # 结构化的全面枚举 enum4linux-ng -A 10.10.10.20-N表示不提供密码。如果返回了共享列表,说明空会话可用。enum4linux-ng会尝试多条路径:RPC 匿名查询用户列表、组列表、密码策略、共享列表、会话列表。它的输出很啰嗦,但你要重点看几块:
用户列表能不能拿到。能拿到的话,你就有了一个合法的用户名清单,后续口令喷洒的命中率会大幅提升——因为很多单位的账户命名是有规律的(拼音、工号、英文名),一旦你知道规律,剩下的就是穷举。
密码策略能不能拿到。这里面包含最小长度、复杂度要求、锁定阈值、锁定持续时间。这是制定后续测试策略的关键输入。如果最小长度是 6 位且无复杂度要求,那基本不用测了,直接判定为高风险。
共享列表能不能拿到。前面说过,共享名本身就是情报。
如果空会话被禁用了(现在很多环境默认禁),你会收到NT_STATUS_ACCESS_DENIED。这时候不是死路,可以试试 Guest 账户:
smbclient -L //10.10.10.20 -U 'guest%'Guest 和匿名是两回事。匿名是“不提供身份”,Guest 是“提供一个公共身份”。很多管理员禁了匿名但忘了 Guest 还在,或者反过来。这两个都要试。
3.3 共享权限判读:从“能看见”到“能写”是关键跨越
拿到共享列表只是开始。真正的分水岭是能不能写。只读共享泄露的是信息,可写共享泄露的是整个系统的控制权——因为可写意味着你可以往里面放一个带宏的文档、一个伪装成配置文件的脚本,等着别人去点。
# 列出共享并标注权限 smbmap -H 10.10.10.20 -u guest -p '' # 对某个可写共享做递归列举 smbmap -H 10.10.10.20 -u 'testuser' -p 'P@ssw0rd123' -r 'TempShare' # 交互式进入 smbclient //10.10.10.20/TempShare -U 'testuser%P@ssw0rd123'smbmap的输出里每个共享前面会有权限标记:READ ONLY、READ, WRITE、NO ACCESS。我通常会做一次写入验证——在TempShare下建一个空文件,确认能写之后再删掉:
smbclient //10.10.10.20/TempShare -U 'testuser%P@ssw0rd123' -c 'put /dev/null test_write_check.txt; del test_write_check.txt'put /dev/null是往远端传一个空文件,这是最轻量的写入探测,不产生任何风险内容。这个动作的意义在于:配置文件显示可写和实际可写经常不一致,验证一次能避免报告出错。
看到可写共享之后,我下一步会看里面有什么。这里有个思路上的转变:可写共享的价值不在写,而在读。因为一个 Everyone 可写还 Everyone 可读的目录,往往就是备份文件、导出报表、临时脚本的堆放地,而这些文件里经常能翻到硬编码的连接字符串、数据库口令、服务账号凭据。
4. 凭证线:口令、哈希与配置泄露
4.1 口令强度评估:字典、策略与节奏控制
这一节讨论的是在授权范围内评估口令强度,前提是已经拿到明确的书面许可和账户清单。技术手段本身很直接:一批用户名 × 一批候选口令,逐个尝试认证,看哪个组合能通过。
# 生成候选用户清单(基于前面枚举的命名规律) cat > users.txt <<'EOF' zhangsan lisi wangwu svc_backup testuser EOF # 口令喷洒:每账户只尝试 1 个高频口令,避免触发锁定 netexec smb 10.10.10.20 -u users.txt -p 'Summer2023!' --continue-on-success # 若确认无锁定策略,再用字典对单账户做定向评估 netexec smb 10.10.10.20 -u testuser -p /usr/share/wordlists/rockyou.txt --continue-on-success--continue-on-success这个参数很重要,它的作用是发现有效凭证后继续尝试其他组合(用于找出所有弱口令账户),而不是一命中就停。在评估场景下你需要的是完整清单。
策略上有几个关键点,我按重要性排序:
先喷洒,后字典。喷洒(Spraying)是对多个账户各试少量口令,字典(Brute Force)是对单账户试大量口令。前者更隐蔽、更不容易触发锁定,且命中率往往更高,因为真实环境里弱口令的分布是不均匀的——总有那么几个账户会踩Summer2023!、Company@123这种。
字典的选择比字典的大小重要。rockyou.txt有一千多万行,跑起来很慢。我的做法是先用两三千条的高频组合字典跑一轮,把季节词、公司名变体、键盘序、常见后缀组合进去。真正有效的候选集往往不需要很大,关键是要贴合目标环境的文化特征。
看认证结果不要只看成功失败。netexec的输出里,STATUS_LOGON_FAILURE是口令错误,STATUS_ACCOUNT_LOCKED_OUT是账户已锁(这是紧急停止信号),STATUS_PASSWORD_EXPIRED说明口令是对的但过期了(这其实是一次有效命中,因为你知道口令了),STATUS_LOGON_TYPE_NOT_GRANTED说明认证成功但该账户无远程登录权限(也是命中)。这四种状态的含义完全不同,报告里必须区分。
来看几种常见返回码的解读:
| 返回状态 | 含义 | 后续动作 |
|---|---|---|
STATUS_SUCCESS | 凭证有效且有访问权限 | 记录,评估该账户可见资源 |
STATUS_LOGON_FAILURE | 口令错误或用户不存在 | 继续尝试(注意节奏) |
STATUS_ACCOUNT_LOCKED_OUT | 账户已被锁定 | 立即停止,等锁定周期过期 |
STATUS_PASSWORD_EXPIRED | 口令正确但已过期 | 记录为有效凭证 |
STATUS_LOGON_TYPE_NOT_GRANTED | 认证成功但无远程登录权限 | 记录为有效凭证 |
STATUS_ACCOUNT_DISABLED | 账户被禁用 | 记录,跳过 |
我吃过一次教训:某次评估没提前确认锁定策略,跑到第 4 个账户时返回STATUS_ACCOUNT_LOCKED_OUT,紧接着客户的业务部门打电话过来说有人登录不了系统。虽然授权书里写了“可能触发账户锁定”,但那半小时的压力我至今记得。从那以后我的清单里多了一条硬性前置检查:在任何口令测试之前,先用只读方式确认锁定阈值,没有确认就不动手。
4.2 哈希传递:不还原明文也能用凭证
这是 SMB 这条线里最有意思、也最容易被防守方忽略的一环。原理不复杂:Windows 的 NTLM 认证流程里,客户端并不把明文口令发出去,而是用口令的 NT 哈希去计算一个响应值。这意味着——攻击者只要拿到哈希,不需要知道明文口令,就能完成认证。
为什么这件事重要?因为这意味着“口令复杂度策略”和“定期改密”在某些场景下是失效的。你就算把口令设成 20 位随机字符,只要哈希泄露了(比如从内存转储、从备份文件、从配置脚本里),攻击者照样能登录。而口令复杂度越高,你越不可能把它改得“更方便管理”,反而越可能被硬编码到脚本里。
在授权评估里验证这个风险,用的是 impacket 套件:
# 使用 NT 哈希直接认证并验证权限,不做任何执行动作 impacket-smbclient -hashes :aad3b435b51404eeaad3b435b51404ee:5fbc3d5fec8206a30f4b6c473d68ae76 'CORP/testuser@10.10.10.20' # 若需验证远程执行能力(仅在授权范围内、且明确允许时) impacket-wmiexec -hashes :aad3b435b51404eeaad3b435b51404ee:5fbc3d5fec8206a30f4b6c473d68ae76 'CORP/testuser@10.10.10.20'哈希的格式是LM:NT,现代 Windows 的 LM 部分基本都是aad3b435b51404eeaad3b435b51404ee(空 LM 哈希的固定值),所以实际有效的是后半段。
这里必须说清楚前提条件:哈希传递能成功,通常意味着目标账户有本地管理员或远程登录权限。普通域用户即使哈希正确,也会被STATUS_LOGON_TYPE_NOT_GRANTED挡住。这个限制恰恰是防守的关键抓手——后面防御章节会展开。
还有一个变种是受限委派与票据利用,属于域环境更深层的内容,涉及 Kerberos 票据伪造与传递,超出了本文范围,但它和 SMB 是强关联的,因为票据最终也是用来访问 SMB 服务。
4.3 从共享目录里“捡”凭证:最朴素也最有效
我做过几十次内网评估,要说哪条路径命中率最高,不是漏洞,不是爆破,是在共享目录里翻配置文件。
原因很简单:人会偷懒。开发要连数据库,不想每次输密码,就写进appsettings.json;运维要跑定时备份,不想配密钥认证,就在.bat脚本里明文写net use \\server\share /user:svc_backup P@ssw0rd;财务要共享报表,就在 Excel 里存一份带连接串的模板。这些文件堆在共享目录里,权限往往设得松松垮垮。
# 递归列出共享内容(先建立文件清单) smbmap -H 10.10.10.20 -u 'testuser' -p 'P@ssw0rd123' -r 'IT-Share' -A '\.(txt|ini|conf|config|xml|json|bat|ps1|cmd|log|bak)$' # 批量下载到本地分析 smbclient //10.10.10.20/IT-Share -U 'testuser%P@ssw0rd123' \ -c 'recurse ON; prompt OFF; mget *'-A参数是正则过滤文件名,只下载关注的后缀,避免把几个 G 的备份镜像全拉下来。下载到本地后用grep扫关键字:
grep -rniE '(password|passwd|pwd|secret|token|apikey|connectionstring)[[:space:]]*[=:]' ./IT-Share/ 2>/dev/null这一步的实战价值极高,因为它找到的往往是服务账户的凭证,而服务账户通常权限高、口令长期不改、还不在常规的密码轮换范围内。我在一次评估里从一个叫backup_script.bat的文件里拿到了一个域账户的明文口令,那个账户属于备份操作组,对多台文件服务器有完全控制权限。整个过程没用到任何漏洞。
注意:下载文件时要控制量。我一般先列目录看文件名和时间戳,只拉最近修改的和命名可疑的。全量下载既慢又容易触发流量告警,还可能把无关的业务数据带到测试机上,增加数据管理风险。
5. 常见弱点汇总与影响范围评估
5.1 空会话、Guest 与共享权限过宽:三个高频配置问题
这三类问题在真实环境里的出现频率远超想象,而且它们共同的特点是不需要漏洞,纯配置问题,补丁打满了也照样存在。
空会话可用的危害是情报泄露。匿名能列举用户、组、共享、密码策略,等于把内网结构图送出去一半。很多单位觉得“反正也没密码,看看而已”,但从攻击链角度看,这一步把后续所有步骤的成功率都抬高了一档。
Guest 账户启用比空会话更严重一层,因为 Guest 是有实际身份的,某些情况下可以被赋予共享访问权限。如果某个共享的 ACL 里混进了Everyone或者Guest,那这个共享基本等于对全网开放。而且 Guest 的活动很难追溯到具体的人。
共享权限过宽(Everyone完全控制、Authenticated Users可写)是最常见的一类。它的成因往往是历史遗留——某次临时传文件,为了方便直接给了 Everyone,然后忘了收回。这类共享的危害取决于内容,但即使是“临时目录”,也经常成为横向移动的落脚点。
判断这三类问题的检测方法很统一:匿名会话探测 + Guest 登录尝试 + 共享权限枚举。前面第 3 节已经写过命令,这里给一个速判表:
| 检查项 | 判定命令 | 高风险表现 |
|---|---|---|
| 空会话 | smbclient -L //IP -N | 返回共享列表 |
| Guest | smbclient -L //IP -U 'guest%' | 认证通过并返回内容 |
| 共享权限 | smbmap -H IP -u user -p pass | 出现 READ, WRITE 且为业务共享 |
| SMB 签名 | nmap --script smb2-security-mode | enabled but not required |
| SMB1 | nmap --script smb-security-mode或 PowerShell 查询 | 协议启用 |
| SMB 加密 | PowerShell 查EncryptData | False |
这张表我一般直接放进评估报告的“快速自查”附录,运维拿去就能自己跑一遍。
5.2 SMBv1 与签名缺失:两个“历史遗留”的放大器
SMBv1 的问题前面提过,这里补充一个实操层面的判断方法。你不能只看“系统是不是 Windows 10 以上”,因为 SMBv1 是可以单独启用的功能组件,很多环境为了兼容老设备专门打开了它。
在 Windows 侧查:
Get-SmbServerConfiguration | Select-Object EnableSMB1Protocol, RequireSecuritySignature, EnableSecuritySignature, EncryptData在 Kali 侧远程判断,靠的是协议协商结果。如果nmap的smb-security-mode脚本能返回结果,说明目标接受了 SMB1 协商,基本可以判定 SMB1 未禁用。
签名缺失的影响需要说清楚,否则容易被当成“理论风险”。SMB 签名的作用是保证通信双方的消息完整性,防止中间人篡改。签名不强制的情况下,攻击者如果能处在网络路径上(比如同一个 VLAN 里的失陷主机,或者能控制一台交换机/无线路由),就可以做 SMB 中继:把 A 的认证请求转发给 B,用 A 的身份访问 B 的资源,而 A 完全不知情。
这个攻击的触发条件在真实内网里并不苛刻——只要有一台机器失陷,攻击者就能在同一个网段里做中继,配合某些自动触发认证的机制(比如强制某个服务回连一个 UNC 路径),成功率相当高。这也是为什么微软从 SMB2 开始就建议强制签名,SMB3 更是默认推荐加密。
加密(EncryptData)是比签名更强的一层,它把整个 SMB 会话内容加密,即使被中间人截获也读不出内容。代价是性能开销(现代硬件上可以接受)和兼容性(需要双方都支持 SMB3)。对于承载敏感数据的文件服务器,我的建议是签名必开,加密按数据敏感度决定。
5.3 与 SMB 相关的历史高危漏洞:只谈识别与修补
关于漏洞部分,我只讲识别方法和修复路径,不展开利用细节,这既是合规要求,也是因为对防守方来说,知道“我的环境里有没有”比知道“怎么打”有用得多。
历史上与 SMB 关联度最高的几类漏洞,成因基本都是协议解析逻辑在内存处理上的缺陷,类型以远程代码执行为主。它们在 SMB1 时代的产物居多,SMB2/SMB3 也有个别案例。识别方法很直接:
# 用 nmap 的漏洞检测脚本做批量筛查(只读探测,不执行任何利用) nmap -p 445 --script "smb-vuln-*" --script-args=unsafe=0 10.10.10.0/24unsafe=0这个参数是关键,它限制脚本只做非破坏性的探测(比如读取版本信息、发送特定协商包判断是否存在某类缺陷),不执行可能引起崩溃或蓝屏的检查。批量扫描老旧网络时,这个约束必须加上,因为某些脚本的探测方式可能导致目标服务异常,对生产设备是灾难。
筛查结果的处置逻辑我按这个优先级:
| 优先级 | 情况 | 处置 |
|---|---|---|
| P0 | 面向内网开放、存在可远程执行类缺陷 | 立即隔离或紧急补丁 |
| P1 | 隔离网内老系统、无法打补丁 | 网络层访问控制 + 主机防火墙 |
| P2 | 已打补丁但 SMB1 仍启用 | 关闭 SMB1(消除未来风险) |
| P3 | 仅签名缺失 | 强制签名 |
对于无法打补丁的老系统(产线设备、医疗配套主机是典型),我的经验是走“隔离 + 白名单”这条路:把它的 445 端口用主机防火墙限制到只允许特定的几台管理主机访问,同时在上层交换机做 VLAN 隔离。这比强行打补丁导致业务中断要稳妥得多。
6. 防御对策:配置、架构、监控三层加固
6.1 配置层:该关的关,该开的开
所有 SMB 加固里,关闭 SMB1是收益最高、成本最低的一件事。命令就一行,但要注意顺序:先确认没有业务依赖,再关,关完观察一周。
# 查看当前状态 Get-SmbServerConfiguration | Select-Object EnableSMB1Protocol, RequireSecuritySignature, EncryptData # 禁用 SMB1 服务端 Set-SmbServerConfiguration -EnableSMB1Protocol $false -Force # 禁用 SMB1 客户端(防止本机作为客户端去连老旧设备时降级) Disable-WindowsOptionalFeature -Online -FeatureName SMB1Protocol -NoRestart # 强制 SMB 签名 Set-SmbServerConfiguration -RequireSecuritySignature $true -Force Set-SmbServerConfiguration -EnableSecuritySignature $true -Force # 对敏感文件服务器启用 SMB 加密 Set-SmbServerConfiguration -EncryptData $true -Force # 禁用 Guest 账户 net user guest /active:no关 SMB1 之前有个必做的检查:确认没有设备依赖。兼容性问题的典型来源是老旧打印机、老式 NAS、部分工业控制软件、还有一些只在局域网里跑的旧版管理工具。排查方法是用Get-SmbSession或者服务端的 5140/5145 事件日志,看有没有 SMB1 协商的记录,再逐台确认。
签名强制同样有兼容性风险。某些老设备不支持签名,强制之后会直接连不上。所以我的建议是分批推:先对文件服务器和域控强制,观察事件日志里的连接失败,再逐步覆盖。
还有一个容易被忽略的配置项:SMB 加密的性能影响。加密是 CPU 密集型的,对于高吞吐的文件服务器(比如视频存储、大文件备份),启用加密前要评估 CPU 余量。我的做法是只对存放敏感数据的共享启用(通过共享级配置),而不是全局开启。
除了服务端配置,共享权限的最小化同样重要:
# 列出所有共享及其访问权限 Get-SmbShare | ForEach-Object { $name = $_.Name Get-SmbShareAccess -Name $name | Select-Object @{n='Share';e={$name}}, AccountName, AccessControlType, AccessRight }输出里只要出现Everyone且权限不是Read,就要重点核。我的原则是:业务共享绝不使用Everyone,一律用安全组授权。新增人员走组申请流程,离职走组移除流程。这样权限可审计、可批量收口。
6.2 架构层:让 SMB 不要“全网可达”
配置层解决的是“单个服务是否健壮”,架构层解决的是“失陷一台主机之后能横向走多远”。后者才是决定一次入侵最终影响范围的东西。
第一条原则:445 端口不该对所有网段开放。典型的企业内网是扁平结构,办公区、研发区、服务器区在同一个大二层里,任何一台机器中招,攻击者就能直接对全网做 SMB 扫描和认证尝试。分段之后,办公区到服务器区的 SMB 访问需要有明确的策略允许,其余一律拒绝。
主机防火墙层面可以做一层兜底:
# 只允许指定管理网段访问 445,其余阻断 New-NetFirewallRule -DisplayName "SMB-Restrict-Inbound" -Direction Inbound ` -Protocol TCP -LocalPort 445 -RemoteAddress 10.10.20.0/24 -Action Allow New-NetFirewallRule -DisplayName "SMB-Block-Others" -Direction Inbound ` -Protocol TCP -LocalPort 445 -Action Block注意规则顺序,允许规则要先于阻断规则生效(Windows 防火墙的 Block 规则优先级高于 Allow,所以实际操作中建议用"默认阻断 + 显式允许"的组合,或者用-RemoteAddress精确控制)。
第二条原则:限制高权限账户的远程登录范围。回到哈希传递那一节,它能成功的前提是账户有远程登录权限。如果把本地管理员账户配置为“禁止通过网络访问此计算机”(通过组策略的“拒绝从网络访问这台计算机”),那即使哈希泄露也无法直接用于 SMB 认证。这是一个非常有效的收敛手段,尤其对服务账户。
第三条原则:特权账户分层。域管理员账户不应该用于日常登录任何工作站,工作站管理员账户不应该和服务器管理员账户复用。这样即使某台工作站失陷,攻击者拿到的凭证也无法直接跳到服务器。这个原则在微软的安全基线里叫“分层管理模型”,实施成本不高,收益很大。
6.3 监控层:从日志里看见正在发生的事
配置再好也会有漏网之鱼,监控是最后一道。SMB 相关的日志主要分布在三个位置:安全日志、SMB 客户端/服务端日志、以及网络设备的流量日志。
安全日志里最该盯的几个事件 ID:
| 事件 ID | 含义 | 告警建议 |
|---|---|---|
| 4624 | 登录成功 | 关注 Logon Type 3(网络登录)的异常源 IP |
| 4625 | 登录失败 | 阈值告警:同一账户 5 分钟内失败 ≥ 5 次 |
| 4634 / 4647 | 注销 / 用户发起注销 | 配合 4624 计算会话时长 |
| 4648 | 使用显式凭证登录 | 高频出现说明有人在切换身份操作 |
| 4672 | 分配特殊权限 | 普通账户出现此项要重点看 |
| 4776 | NTLM 凭证验证 | 大量 NTLM 认证说明有人在尝试哈希传递 |
| 5140 | 访问网络共享 | 结合 5145 看具体访问了什么 |
| 5145 | 检查网络共享对象的访问 | 重点关注对敏感目录的写入和删除 |
配置审计策略把这些事件记下来是第一步:
# 开启"审核登录事件"和"审核对象访问" auditpol /set /subcategory:"登录" /success:enable /failure:enable auditpol /set /subcategory:"文件系统" /success:enable /failure:enable auditpol /set /subcategory:"详细文件共享" /success:enable /failure:enable第二步是建立基线。什么叫异常?不是“出现 4625 就告警”,而是“某个账户在非工作时间、从非常用 IP、出现连续失败”。我在做规则设计时,一般会先用两周的正常流量跑一个基线,统计出每个账户的常用源 IP 段和登录时段,然后在基线之上加偏离检测。
第三步是蜜罐共享。这个方法成本极低、效果极好:创建一个名字看起来很有诱惑力的共享(比如财务备份、HR-2024、IT-密码归档),里面放几个空文件,然后不给任何真实账户授权。正常情况下永远不该有人访问它,一旦有访问记录,基本可以确定是有人在枚举和尝试。这个检测点的误报率极低,我在多个环境里部署过,抓到过真实的内网扫描行为。
注意:蜜罐共享的命名要贴合业务语境,但不能真的包含敏感数据。空文件 + 合理的文件名 + 修改时间,足够了。
7. 常见问题与排查记录
7.1 连不上、认证失败:按这个顺序排查
SMB 相关的问题,排查顺序错了会走很多弯路。我总结了一个从下往上的顺序,每次按这个走,基本能在十分钟内定位。
第一步:端口通不通。nc -zv 10.10.10.20 445或者nmap -p445。不通的话,先怀疑防火墙(主机防火墙、网络 ACL、云安全组三层都要查),再怀疑服务没起(Get-Service LanmanServer)。
第二步:协议能不能协商。smbclient -L //10.10.10.20 -N报protocol negotiation failed,多半是 SMB1 被禁但客户端还在用 SMB1 协商。加-m SMB3强制高版本试试。
第三步:认证阶段。报NT_STATUS_LOGON_FAILURE是凭证问题;报NT_STATUS_ACCOUNT_LOCKED_OUT是账户已锁;报NT_STATUS_LOGON_TYPE_NOT_GRANTED是权限问题(凭证对但该账户不允许网络登录);报NT_STATUS_ACCESS_DENIED是认证过了但共享权限不够。这四种要分清,处理方向完全不同。
第四步:权限阶段。能列共享但进不去某个目录,检查共享权限和 NTFS 权限的交集。用smbmap -r递归看具体哪个层级被拒。
来看一个速查表,我把常遇到的问题和对应处置都列上:
| 现象 | 最可能原因 | 处置 |
|---|---|---|
| 端口不通,ping 通 | 主机防火墙拦截 | 检查入站规则,Test-NetConnection -Port 445 |
protocol negotiation failed | 版本不匹配或 SMB1 已禁 | 客户端加-m SMB3 |
NT_STATUS_LOGON_FAILURE | 凭证错误 / 用户不存在 | 核对用户名格式(域\用户 vs 用户@域) |
NT_STATUS_ACCOUNT_LOCKED_OUT | 触发锁定策略 | 等待锁定周期,之后降低尝试频率 |
NT_STATUS_LOGON_TYPE_NOT_GRANTED | 该账户禁止网络登录 | 查“拒绝从网络访问”策略 |
NT_STATUS_ACCESS_DENIED | 认证成功但共享无权 | 查共享 ACL 与 NTFS ACL 交集 |
| 能写但改不了已有文件 | NTFS 权限只给了创建/写入 | 检查文件级 ACL 而非目录级 |
| 传输速度极慢 | SMB 签名或加密开销 / MTU 问题 | 关闭加密对比测试,检查 MTU |
| 偶发断连 | 会话超时 / 网络抖动 / 多通道问题 | 检查Get-SmbClientConfiguration |
7.2 几个踩过的坑,写下来省你时间
坑一:用户名格式搞错,浪费半小时。SMB 认证的用户名有三种写法:用户、域\用户、用户@域。用smbclient时如果只写用户名,它会用本地 SAM 库认证;如果目标账户在域里,必须写域\用户或者用-W指定工作组/域。我曾经因为少写一个域名前缀,反复确认密码是不是错了,最后发现是认证目标搞错了。
坑二:smbmap显示 NO ACCESS 不代表真没权限。它只是用当前凭证尝试了一次,如果这个凭证恰好对某个共享没权限,会显示 NO ACCESS。换成另一个账户或者 Guest 再试一次,结论可能完全不同。评估报告里写“共享 X 无权限”之前,至少要用两种身份验证。
坑三:Windows 的“简单文件共享”会覆盖你的精细配置。在老版本客户端上,如果开启了简单文件共享(默认开启),你设的 NTFS 权限可能被简化成 Everyone。做权限收敛时先确认这个开关是关的。虽然新版系统里这个选项已经不显眼了,但在一些长期不重装的工作站上依然存在。
坑四:下载大量文件会触发流量监控。我在一次评估里用mget *拉了一个共享的全量内容,大约 8G,直接把客户的流量监控告警触发了,安全团队打电话过来问是不是在传数据出去。从那以后我的做法是先ls看清单,用正则过滤,单次下载控制在 100M 以内,并且提前告知客户的监控团队。
坑五:别忽略系统时间。做哈希传递或者 Kerberos 相关验证时,客户端和目标的时间偏差超过 5 分钟会导致认证失败,报错往往很模糊(STATUS_MORE_PROCESSING_REQUIRED之类的)。遇到莫名其妙的认证失败,先date -u对一下时间。
坑六:测试完要清理。建过的文件、改过的共享权限、加过的账户,全部要还原。我习惯在测试前把所有原始配置导出成一份清单,测完逐项核对。这个习惯救过我一次——某次忘了删一个测试账户,被客户的月度审计发现了,虽然没造成影响,但解释起来很费劲。
7.3 如果只能做三件事
现实里很少有环境能一次把所有加固措施推完,资源永远不够。如果让我给一个优先级排序,只做三件事的话,我会选这三个:
第一,关掉 SMB1,强制签名。两条 PowerShell 命令,成本几乎为零,收益覆盖了历史上大部分 SMB 相关的高危问题。风险在于兼容性,所以先在测试环境验证,再小范围推。
第二,清理共享权限里的 Everyone。把所有共享的 ACL 导出来过一遍,凡是Everyone有写权限的一律改成安全组授权。这一步能直接掐掉大部分“横向移动落脚点”。
第三,部署蜜罐共享 + 登录失败告警。一个假共享的成本是五分钟,但它能给你提供最早期的入侵信号。配合 4625 的阈值告警,基本能在攻击者还在侦察阶段就发现异常。
这三件事做完,你的 SMB 攻击面会缩小一个数量级。剩下的漏洞修补、网络分段、加密启用,都是在这个基础上做增量优化。
最后分享一个我在实际项目里的体会:SMB 的安全问题,九成不是技术难题,是管理惯性。那个 Everyone 可写的共享,是五年前某次紧急上线时留下的;那个没改的默认口令,是交接时没人提过;那台还开着 SMB1 的机器,是因为“它一直这么跑着也没出事”。所以真正有效的加固,技术方案只是一半,另一半是让变更流程里带上安全评审这一环——新建共享要登记,新增授权要审批,旧配置要定期清理。这件事比任何一条命令都难推,但也比任何一条命令都管用。