1. 项目概述
有天下午,内网的一台应用服务器突然频繁收到某客户端的身份认证失败提示,登录日志里看不出任何异常,防火墙策略也检查过,端口是通的,服务也活着,唯独有一个规律:每隔几分钟就会蹦出一条“未知源”的认证请求,来源 IP 指向内网一个不存在的网段。
这条“未知源”请求就是典型的未识别 NTLM 通信。说白了,网络上有人在用 NTLM 协议尝试做身份认证,但没有通过常规的 SMB 服务或 HTTP 网关入口,而是直接向某台主机发起了认证请求,来源既不是已知终端,也不归属业务网段,日志里只有一个会话 ID 和一个用户名。这种问题在混合网络环境里尤其常见,域内主机、非域成员、打印机、NAS 设备、临时接入的运维笔记本,都可能成为 NTLM 流量的源头。更难缠的是,NTLM 本身不携带完整源身份信息,单靠日志条目很难判断它到底是谁、为什么发请求、请求了什么资源。
这篇文章记录的是我在处理这类问题时摸索出的一套可复现分析流程:用 Windows 事件日志做粗筛,拿 Procmon(Process Monitor)做细揪,两头夹击,把“未知 NTLM 通信”从定位到根因的完整路径走一遍。
如果你正在维护一套多网段的企业内网,经常遇到登录日志上有零星认证失败但找不到根源,或者你的安全策略要求识别所有认证流量来源但现有监控体系只能覆盖常规协议,这篇内容会很有参考价值。文章中涉及的步骤不依赖商业安全产品,工具也是系统自带或免费工具,适合中小型 IT 团队直接落地。
2. 前置认知与整体思路拆解
动手之前,建议先把 NTLM 认证的流向逻辑理清楚。这个过程本身不复杂,但网络环境和 Windows 版本差异会让“显而易见”变得“扑朔迷离”。
2.1 NTLM 认证为什么这么难定位
NTLM 认证的过程是挑战-响应机制:客户端先向服务端发送一个协商请求,服务端返回一个挑战字符串,客户端用密码哈希对挑战加密,再送回服务端验证。整个过程不传输明文密码,但也不携带完整的路由信息。也就是说,你在服务端看到一条认证条目,只能知道“谁在尝试认证”和“认证什么资源”,却很难直接知道“请求从哪条链路进来”。
这里有个容易被忽略的细节:NTLM 流量往往会经过多层转发。举个例子,某台终端通过 IIS 反向代理访问内部应用,IIS 会把请求转发给后端服务器,后端服务器看到的就是 IIS 的 IP 而不是终端的 IP。另一种常见场景是,某些老式打印机或 NAS 设备配置了“域认证”模式,它会周期性向域控发送认证请求,但因为它不在域成员列表里,会给系统管理员造成“未知设备在扫端口”的错觉。
提示:判断一条 NTLM 通信是否“未知”,重点不是看源 IP 是否在你的地址表里,而是看它是否属于已登记的业务资产。非业务地址段出现认证请求,往往比业务网段内异常更加值得关注。
2.2 事件日志与 Procmon 为什么要配合使用
单靠任何一种工具都会出现盲区。
Windows 安全事件日志能告诉你“认证是否成功”“账号是否存在”“来源 IP 是什么”,但它有两个明显短板:第一,事件日志默认只记录认证结果,不记录认证请求的具体触发进程;第二,如果攻击者或异常程序在内存中直接发起认证,不经过文件系统层面的进程创建,事件日志里根本看不到触发源。
Procmon 的优势恰恰在进程级追踪。它能记录每一个文件、注册表、网络、进程线程操作,包括“哪个进程发起了网络连接”“目标端口是什么”“认证数据包流向哪个 socket”。但它的缺点是噪声太大——在繁忙系统上一分钟能产生数万条事件,没有过滤规则根本看不过来。
两者配合的逻辑是:先用事件日志收敛时间点和源 IP,再用 Procmon 在那个时间窗口内精确定位到发起认证的具体进程,最后通过进程树追溯访问路径。这样既避免了在海量 Procmon 数据里盲目翻找,也不会因为事件日志缺少进程信息而卡在“知道有异常但找不到源头”这一步。
2.3 这套方案的适用边界
这个方法最适合中小型内网环境,网段数量在几个到十几个之间,终端数量几十到几百台。对于大型数据中心或云原生环境,建议优先考虑网络层镜像 + 身份认证网关的方案,因为虚拟化环境和容器环境里的 Procmon 覆盖能力有限。
另外要强调的是,这套方法是“识别未知流量源头”,不是“拦截未知流量”。真正要落地阻断策略,还需要配合防火墙 ACL、IPsec 策略或认证协议降级等手段,这部分我放在文章最后的建议里。
3. 工具准备与基础配置
3.1 事件日志侧需要启用的通道
NTLM 认证相关的事件主要分布在“安全”日志中,但默认配置下某些关键通道是不开的。我处理过好几起“明明认证失败了但日志里没记录”的情况,最后发现是策略没有开启。
需要确认以下三项:
- 审核登录事件(包括成功和失败)——这是追踪认证请求的基础
- 审核账户登录事件——用于记录域控侧的账户认证尝试
- 审核 Kerberos 服务票证操作——NTLM 降级场景下,部分请求会先尝试 Kerberos,失败后回退,这一项能帮你看到回退过程
如果是在域控上做追踪,还需要额外开启“NTLM 身份验证”的日志通道。这里有个操作细节:域控的“打开 NTLM 身份验证审核”策略可以在组策略管理器中配置,位置在“计算机配置 → 策略 → Windows 设置 → 安全设置 → 本地策略 → 安全选项”,值为“启用所有操作”,这样系统会在事件日志中记下全部 NTLM 认证尝试,包括成功和失败的。
3.2 Procmon 的过滤预配置
Procmon 的配置有两个要点:过滤条件和捕获设置。
捕获设置中,建议开启“启用网络活动”和“启用进程活动”,这两个默认就是开启的,但要注意“启用注册表活动”在性能受限的场景下可以暂时关掉,减少日志体积。
过滤条件建议按操作类型过滤。追踪 NTLM 通信主要关注两类操作:
TCP Connect:发起方主动连接目标端口,NTLM 通常走 445(SMB)、139(NetBIOS)或 88(Kerberos,但 NTLM 同族)TCP Send/TCP Receive:数据包收发,认证挑战码和响应码交换在这里完成
在 Procmon 主界面的“过滤器”菜单里添加三条过滤规则,操作类型归属 network,路径留空,然后应用。注意不要把进程名过滤提前加上,先把所有网络操作都抓下来,再在时间窗口内按会话 ID 缩小范围。
注意:Procmon 默认只保留最近 100 MB 的捕获数据,长时间运行的大流量服务器很容易把缓冲撑爆。操作前结合实际业务调大“捕获选项 → 缓冲区大小”至 200 MB 或更高,否则数据被覆盖之后很难找回。
3.3 测试环境的验证
不是每一次问题都能等到现场复现,配置完成后建议做一次模拟验证:找一台测试机,手动发起一次不存在的 UNC 路径访问。比如在命令行执行:
net use \\192.168.50.99\share /user:FakeUser FakePass或者用 Python 脚本模拟:
import socket target = ("192.168.50.99", 445) connect = socket.socket() connect.settimeout(3) connect.connect((target[0], target[1]))执行后立即检查安全日志和 Procmon 是否能捕获到对应的 NTLM 流量,确保后续分析时的数据采集链路是通的。这一步看起来多余,但在实际排查中能省掉大量返工时间。
4. 事件日志分析:收敛时间与源信息
4.1 从事件 ID 入手快速定位认证请求
在安全日志中筛选 NTLM 认证相关事件,核心是以下事件 ID:
| 事件 ID | 名称 | 收录的信息 |
|---|---|---|
| 4624 | 登录成功 | 用户、源 IP、登录类型、认证包名称 |
| 4625 | 登录失败 | 用户、源 IP、失败原因、认证包名称 |
| 4776 | 凭据验证 | 域控收到 NTLM 认证请求、请求来源主机名 |
| 8001 | NTLM 身份验证成功 | 请求客户端、被认证服务器、认证方式 |
| 8004 | NTLM 身份验证失败 | 同上,额外包含失败子状态码 |
如果开启的通道完整,大多数情况下直接用“当前日志 → 筛选当前日志 → 事件 ID 包含 4625 或 8001”就能看到目标。注意把时间范围拉长到发现问题前 30 分钟,因为很多异常请求是间歇性触发的。
实际操作中有一个经验:事件 ID 4776 的记录最可靠,因为它记录的是 NTLM 请求在域控侧的实际落点,包含 Netlogon 服务收到请求的源主机名。即便客户端 IP 做了 NAT,源主机名有时也能暴露真实身份。
4.2 从“登录类型”和“认证包”两个字段判断流量性质
找到记录之后,先看“登录类型”字段。NTLM 相关的常见登录类型有:
- 3(网络登录):最常见,代表通过网络访问共享文件夹或 IIS 站点
- 10(远程交互登录):常见于 RDP 场景,NTLM 作为身份验证回退方式
- 2(交互式登录):通常不会出现在远程 NTLM 请求中,如果出现且来源网段异常,优先级要提高
接着看“认证包名称”字段。正常域环境应该是Kerberos,如果显示NTLM说明客户端没有成功获取域票据,回退到 NTLM。这时候需要判断回退原因:是客户端时钟不同步,还是 SPN(服务主体名称)没有注册,或者客户端根本不在域内。
如果出现大量NTLM认证且来源 IP 属于一个不常见网段,可以先记下以下信息备用:
- 源 IP
- 源端口
- 目标端口
- 目标服务账号(即请求中试图访问的资产身份)
- 认证用户名
- 时间戳
这些信息是后续 Procmon 过滤的锚点。守好锚点,能让你在 Procmon 数据里少走几公里的弯路。
4.3 事件日志无法回答的问题
事件日志能看到“谁请求了认证”,但看不到“哪个进程发起了这个请求”。举一个实际区分场景:同一台被中转的终端上,一个是定时任务在后台映射网络驱动器,另一个是浏览器插件在扫描共享资源,两者在事件日志里可能完全一样——源 IP 相同、认证用户相同、登录类型都是 3,但后者的行为特征更接近扫描,前者的行为特征更像合法业务调用。单靠安全日志做阻断决策很容易误伤。
这正是引入 Procmon 的必要性,下一节展开讲。
5. Procmon 实操:从进程层面揪出真实发起者
5.1 建立“时间窗口 x 锚点会话 IP”双层过滤器
拿到事件日志的锚点信息之后,打开 Procmon。推荐先添加干扰时间维度过滤:
在主菜单“工具 → 时间线”里定位到事件日志记录的时间点,左右各放宽 30 秒。因为认证请求是一问一答的过程,发起连接、发送协商包、接收挑战、发送响应,这些动作可能在几百毫秒内完成,但相关进程可能有前后几秒的初始化动作。
时间窗口锁住之后,添加第二层过滤:
- 进程“路径”包含源 IP 或源端口
- 操作类型为
TCP Connect或TCP Send
如果入口方向有端口转发(比如访问的是 445 但实际连接目标是高位端口),过滤条件可以放宽为:目标端口为445、139或80/443(IIS 场景下 NTLM 会封装在 HTTP 头中)。
应用过滤器后,Procmon 会显示一个相对干净的进程网络活动列表,通常集中在两三个进程身上。不要直接终结,先看进程名和 PID。
5.2 通过进程树追溯上层调用关系
Procmon 主事件列表中,双击一条 TCP Connect 事件,会在“进程”选项卡看到进程名、PID、父进程 PID、路径。这时候按父进程 ID 重新过滤,就能一步步向上追溯:
以上面的流程为例:先是某个父壳应用起了子进程,子进程做了 DNS 解析(Procmon 中表现为DNS Query操作),随后建立了到目标资产 IP 的 TCP 连接,紧接着发出了包含 NTLM 协商数据的 TCP Send。把这几个操作按时间排序,基本可以确定该子程序就是认证请求发起者。
一个很重要的实操细节:如果目标程序是通过服务方式启动的,进程名那行可能显示的是svchost.exe或services.exe的子进程,这时候要把服务名一起记下来。服务的可执行文件路径可以通过任务管理器的“服务”标签页或者命令行查询,但更建议直接在 Procmon 里看进程树层级,因为有些恶意程序会伪装成系统服务名称注册,直接看路径能一眼识破。
5.3 用“进程里程碑”验证追踪结果
定位到进程后,不要急着下结论。推荐做一个“里程碑验证”:在 Procmon 事件列表中选中该进程的 TCP Connect 事件,右键 → 跳转时间,然后再加入一条RegSetValue操作(通常一个程序初始化时会写注册表),把整个操作序列连起来看,模拟出这个进程从启动到认证成功的“生命轨迹”。
这条验证能回答几个关键问题:
- 进程的网络连接是否发生在可信的初始化流程之后
- 连接目标是否与业务配置一致(有些程序写死了内网 IP 做探活)
- 认证请求是否伴随异常的高频重试(正常业务不会每隔 30 秒就发起一次)
我曾经遇到过一个案例:事件日志里每隔几分钟出现一次认证失败,Procmon 定位后确认是一个旧版监控代理在尝试连接已停用的管理端口。这个代理的进程名和正常版本一模一样,唯一区别是它会把现网环境的配置文件当成了测试环境配置去解析,导致目标 IP 全部指向一段已废弃的网段。单看事件日志容易误判为“外部扫描”,结合 Procmon 的进程路径和命令行参数才确认是配置漂移。
6. 常见问题与排查技巧实录
6.1 Procmon 抓不到相关流量
最常出现在高负载服务器上。原因是 Procmon 的捕获缓冲区被无关操作占满,而 NTLM 流量本身占比极小。解决办法是预先按“操作类型为网络”加上全局过滤,然后把“队列大小”调大两到三倍。另外一个低概率原因是目标主机上存在代理,NTLM 流量被封装在代理连接中,此时 Procmon 看到的仍然是 TCP 连接,只是目标 IP 是代理本身的 IP,需要结合事件日志中的源端口做对应。
6.2 事件日志里的事件 ID 对不上
部分 Windows Server 版本默认关闭 NTLM 审计日志,事件 ID 8001/8004 不会出现。如果发现没有这两类数据,就用 4624/4625 做替代,但要多看一个“登录过程”字段,正常的网络登录显示0x0,存在凭据重放时会显示0xC0000064或0xC000006A。
6.3 NTLM 通信的“假阳性”误判
很多 IT 运维把“未知 IP 的 NTLM 请求”和“恶意扫描”直接画等号,这是最大的误判来源。结合 Procmon 观察下来,大部分“未知”其实是:
- 网络打印机定期向域控发起身份验证
- 遗留的旧系统服务在尝试连接原有认证服务器
- 多宿主机器的备用网卡在使用 DNS 名称连接业务资源
判断方法很简单:看认证用户名。如果用户名是system或machine$,大概率是服务或机器账户的常规操作;如果是具体的域账号,就要结合行为频率判断。再有就是看源端口,常规服务的源端口是固定的(445/443),如果源端口每次都不同且呈递增趋势,就需要多警惕一些。
6.4 NTLM 流量穿透多级代理怎么办
有些网络结构会在应用层做反向代理,事件日志显示的是代理服务器的 IP,Procmon 在目标服务器上自然看不到“真实发起者”。这类情况处理思路要调转方向:先确认代理服务器(IIS、Nginx、各类应用网关)的日志,找到对应时间段的“上游 IP”,再回到源站所在网段去查那台设备的 Procmon。
注意:当你发现自己要找的“发起者”不在目标服务器上,而是跨越了多个跳板时,不要试图用一个窗口捕获所有链路。正确做法是分跳板逐段筛查,每跳只关注入口 IP 和出口 IP 的对应关系,最后收敛到物理终端。
6.5 过滤规则导致过拟合
还有一类问题是过滤条件加得太死,反而错过真正的可疑流量。举例来说,如果你只盯着TCP Connect,某些实现会用UDP的NetBIOS Datagram做认证发现广播,那这条路径就漏掉了。建议在过滤时把TCP Connect、UDP Send、UDP Receive都保留,最终分析阶段再按目标端口和会话时序筛选,避免过早把候选集缩小到零。
7. 实操总结与工具选型建议
7.1 一套可以直接复用的排查流程
把文章里的内容压缩成一张可执行的清单,拿过去就能直接跑:
第一步:开放事件日志通道,确认 4624/4625/8001/8004 均在记录。
第二步:按时间段筛选安全日志,取异常 NTLM 认证条目,记录源 IP、目标端口、认证用户名和时间戳。
第三步:打开 Procmon,按“时间窗口 + 源 IP/端口”过滤网络操作,定位到具体进程。
第四步:从进程路径、父进程、命令行参数判断触发来源,必要时做“里程碑验证”。
第五步:如果信息不足,到网关、代理或上游设备上查对应时间点的连接日志,做跳板收敛。
这套流程耗时不长,熟练的情况下两小时以内能搞定绝大多数谜题,关键是要按顺序走,不要跳步。
7.2 工具选型的补充建议
事件日志 + Procmon 这套组合是免费方案里的“黄金搭档”,但遇到大规模环境时性能会成为瓶颈。如果你手上有预算,可以引入纯网络侧的流量分析工具做旁路镜像,这样能看到全量认证握手过程和包级细节。无论如何,我建议先掌握日志 + Procmon 这套手法,因为它是理解 Windows 认证基础的最佳路径,网络分析工具能帮你加速,但取代不了对操作系统内部机制的熟悉。
8. 最后讲两句我的体会
我在实际排查中掉过最大的坑,是把“来源 IP 陌生”等同于“行为异常”,结果忽略了资产登记表更新滞后的问题。网络是动态的,资产不清、配置漂移、遗留服务都是常态,程序本身不会主动告诉我们“我变了”。事件日志和 Procmon 不会主动替你做判断,它们只负责记录事实,换来简洁准确的“当时发生了什么”。真正的分析功夫,一半在数据采集的完整性上,另一半在解读时能不能把上下文串起来。
如果你第一次实践这套流程时碰到定位不出结果的场景,不妨把捕获窗口拉得再宽一点。我观察到不少 NTLM 请求是周期性的,把 Procmon 挂在那台可疑主机上多跑几个小时,按小时切分时间线对比,往往就能发现触发频率与某个定时任务相匹配。这种“慢工出细活”的策略在不确定根因的场景下反而能一击命中。
最后分享一个小技巧:所有 NTLM 排查事件,不管结论如何,都建议把 Procmon 的过滤配置和结果文件导出一份,存入对应主机的文档目录。下次再出现类似的未知认证流量,直接复用之前的过滤配置就能省下从零搭建的半小时。系统行为分析这个活儿,做得多了,积累的“模板”就是你最大的财富。