ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

SMB安全评估与加固:445端口、共享权限审计及哈希传递防御

SMB安全评估与加固:445端口、共享权限审计及哈希传递防御

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返回共享列表
Guestsmbclient -L //IP -U 'guest%'认证通过并返回内容
共享权限smbmap -H IP -u user -p pass出现 READ, WRITE 且为业务共享
SMB 签名nmap --script smb2-security-modeenabled but not required
SMB1nmap --script smb-security-mode或 PowerShell 查询协议启用
SMB 加密PowerShell 查EncryptDataFalse

这张表我一般直接放进评估报告的“快速自查”附录,运维拿去就能自己跑一遍。

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/24

unsafe=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分配特殊权限普通账户出现此项要重点看
4776NTLM 凭证验证大量 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 的机器,是因为“它一直这么跑着也没出事”。所以真正有效的加固,技术方案只是一半,另一半是让变更流程里带上安全评审这一环——新建共享要登记,新增授权要审批,旧配置要定期清理。这件事比任何一条命令都难推,但也比任何一条命令都管用。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进