☰
findpass实战:从LSASS内存提取Windows明文口令与哈希
2026/10/21 3:04:55 网站建设 项目流程

简介:一款经典的小型密码查询工具 FindPass(由 PasswordReminder 改造而来),适用于 Windows NT4/2000 系统。登录系统时,域名与用户名会明文保存在 winlogon 进程中,只要具备管理员权限,指定目标用户和对应 winlogon 进程 PID,即可在进程内存中定位并尝试还原加密口令,常被用于本机口令遗忘后的恢复、管理员审计或早期系统安全测试。资源包共 5 个文件,压缩后仅 106KB,包含可直接运行的 FindPass.exe、辅助进程列表工具 pulist.exe、完整 C++ 源码 FindPass.cpp、说明文档 readme.html 及一张效果截图。源码公开了关键技术:利用 SeDebugPrivilege 打开 winlogon、通过 NtQuerySystemInformation 枚举进程、以 ReadProcessMemory 扫描内存中的用户名字段,并调用 RtlRunDecodeUnicodeString 对 Win2K 的 hash-byte 做暴力解码,附录还提供了 pulist 的用法示例。已有 793 人学习浏览,适合系统管理员、安全测试人员以及对 Windows 进程结构和未公开 API 感兴趣的开发者参考研究。

1. findpass 没有图形界面:耐心读懂进程内存才能拿到明文口令

遇到需要从 Windows 机器上找回已保存口令的场景,比如员工离职交接不清、测试环境账号年久失修,你会发现网上那些“一键找回”的图形工具要么被杀软拦得死死,要么需要额外安装运行库。而findpass这类轻量级命令行工具能直接绕开杂技流程,它做的事情很纯粹:解析 LSASS(本地安全认证子系统)进程的内存,从里面提取出缓存的明文口令或哈希。今天这篇笔记,我会带着你把 findpass 的完整流程走一遍,包括原理、命令、以及我踩过的几个真实坑。适合有权限做安全自测或本机维护的工程师参考,新手按步骤也能操作。

2. findpass 的工作基石:为什么明文口令会留在 LSASS 内存中

2.1 从 WinLogon 到 LSASS:口令的短暂停留

要搞懂 findpass 能提取到内容的原因,得先说清楚 Windows 登录机制。用户输入密码后,WinLogon 进程会把密码交给 LSASS,LSASS 调用 SSPI(安全支持提供程序接口)体系中的认证包去验证。这个交互过程里,明文口令在 LSASS 进程内存中是有短暂驻留的。

即使完成认证,LSASS 出于性能考虑,也不会马上擦除这些内存块,因为同一会话里后续的解锁屏幕、修改口令等操作还需要复用它们。对于域环境或开启了缓存登录的机器,情况更特殊,系统会在注册表的某个键值下缓存最近若干次的口令哈希,目的是域控不可达时用户还能登录本机。

这就是 findpass 能工作的根本前提:LSASS 作为一个高权限常驻进程,内存里存有不经意留下的凭据,包括明文密码、NTLM 哈希、Kerberos 票据等。这个现象是 Windows 设计层面带来的结果,跟程序有没有安全漏洞没关系,所以几乎每一代 Windows 都适用。

2.2 用户态读取路径:findpass 与驱动级工具的本质区别

市面上获取密码内存的方式分两类。一类是加载内核驱动去读 LSASS 所在的内存区域,这类工具权限要求极高,部署时也容易触发系统签名校验;另一类就是 findpass 采用的用户态路径,在拥有 SYSTEM 或管理员权限的情况下,通过调试接口或进程读取 API 访问 LSASS 内存。

用户态路径的优点是部署简单,不需要驱动,也不依赖特定 Windows 版本的内核偏移量。缺点是它需要一个有足够权限的进程去执行,而且要绕过 LSASS 的保护机制(PPL)。想顺利读到内存,最直接的方案就是获得 SYSTEM 权限,比如通过计划任务或服务方式运行 findpass,这样进程就以 SYSTEM 令牌执行了。

操作上,你可以在任务管理器或命令行里验证执行身份,确认 findpass 进程是以 SYSTEM 账户运行的。这里有个常见误区:管理员账户不等于 SYSTEM 权限,管理员运行 findpass 大概率会失败,我后面会细说。

2.3 findpass 支持的口令格式解析

从内存中提取到的数据因为来源不同,格式也会有差异。findpass 通常能输出以下几类:

数据类型来源位置典型格式
明文密码认证缓冲区域直接在字符串列表中可见
NTLM 哈希认证会话结构体32 位十六进制字符串
Kerberos 票据票据缓存区域较长的 Base64 或字节流

明文密码的提取主要依赖对字符串列表的扫描,因为认证过程中传入的密码缓冲区通常是明文存储的。哈希值则存储在与认证会话关联的结构体里,需要解析到对应偏移量才能正确取到。

如果你拿到的输出里同时包含明文和哈希,那说明 LSASS 内存里既有新登录的凭据,也有缓存的历史凭据。findpass 默认不会去区分,它的输出逻辑是按内存块扫描出来的顺序排列的。

3. 实战部署:用 findpass 提取本机密码

3.1 准备运行环境与身份确认

首先确认目标机器是 Windows 7 及以上版本,且你是管理员账户。接着用命令确认权限状态:

whoami whoami /groups | findstr /i "S-1-5-18"

第一行输出当前用户名,第二行则是检查组 SID,S-1-5-18 对应 SYSTEM 账户。如果第一行显示的是普通管理员而第二行没有结果,说明当前会话不满足提取条件。我一般会直接在上面创建一个临时计划任务来获取 SYSTEM 令牌。

schtasks /create /tn "findpass_helper" /tr "cmd.exe /c runas /user:SYSTEM findpass.exe > C:\temp\result.txt" /sc once /st 00:00 /ru SYSTEM /rl HIGHEST schtasks /run /tn "findpass_helper" schtasks /delete /tn "findpass_helper" /f

这里需要注意:/ru SYSTEM参数的意义是任务以 SYSTEM 身份运行,而不是指定用户账号。这样启动的 findpass 进程就拥有了读取 LSASS 的权限,输出结果重定向到文本文件,完成后立即删除计划任务,避免留下痕迹。

3.2 命令行核心执行流程

获取 SYSTEM 令牌后,可以开始执行 findpass 了。它的命令格式本身不带参数也能直接运行,但我建议设置一下输出级别,方便阅读。

findpass.exe /OutputFile "C:\temp\findpass_results.txt" /Verbose

参数解释:/OutputFile指定结果保存到文件,避免控制台编码问题;/Verbose输出详细扫描信息,方便分析内存中哪些区域包含凭据。若不指定输出文件,则结果会直接打印到控制台,但当主机默认代码页是 GBK 或非 UTF-8 时,显示会乱码。

如果执行成功,你应该能在结果文件里看到账户名、密码或哈希的记录。这里放一个脱敏后的输出示例:

[USER] contoso.local\alice [PASSWORD] Summer2024!lyy [DOMAIN] contoso.local [USER] contoso.local\bob [NTHASH] a9f0c8e3d3711ba9f6a1e8c7d28e3fa4 [DOMAIN] contoso.local

这里每一段都包含用户主体名与对应凭据信息。注意看输出里[DOMAIN]这一段:当它标记为本地域名时,提取到的哈希属于本地账户;如果是域账户,则哈希来源于缓存的登录凭据。

3.3 参数微调与内存读取策略

findpass 默认扫描整个 LSASS 进程的堆内内存区域,如果你的系统内存较大且开机时间很长,扫描时间会相应增加。我一般会在执行前确认 LSASS 进程的 PID,再决定是否限制扫描范围:

tasklist | findstr /i lsass findpass.exe /PID 612 /OutputFile "C:\temp\result.txt"

这样把扫描范围限制在指定的 PID 对应的进程地址空间,而不是遍历所有可能的内存区块,能明显缩短执行时间。在内存碎片很多的老机器上,/PID参数的收益很明显,至少提速一半以上。

有一个需要注意的点:如果 LSASS 启用了 Credential Guard 隔离,那么凭据数据被存放到虚拟隔离的 LSAIso 进程里,LSASS 内存里只剩一些结构化引用,这个时候 findpass 会输出大量结果但看不到真正的明文密码。识别手段是检查服务里是否有KeyIso进程运行。

4. 从失败到跑通:findpass 的常见报错与对策

4.1 错误代码 5:拒绝访问,权限不够

现象:运行 findpass 时直接报 access denied,或者输出文件为空,控制台显示错误码 5。

原因:当前进程令牌不是 SYSTEM,或者就算进程是 SYSTEM,但系统开启了基于虚拟化的安全功能(Credential Guard 或某个安全加固策略),导致读取被拒绝或者读取到的是被隔离后的空数据。

解决:先确认当前终端是否具备调试特权,可以在 cmd 里运行whoami /priv,找到 SeDebugPrivilege 后手动启用:

powershell -Command "Enable-SeDebugPrivilege"

如果是 Credential Guard 场景,那 findpass 这类用户态工具基本无能为力,先检查服务 winmgmt 里是否存在 LSAIso 进程,存在则这台机器不适合此方案,直接换其他路径。

4.2 输出乱码:中文环境字符编码问题

现象:结果文件里汉字用户名或密码变成问号或菱形字符,英文数据正常。

原因:findpass 默认以系统当前代码页输出,而 Windows 中文环境是 GBK,终端或文件打开方式若是 UTF-8,匹配不上就会乱码。

解决:给 findpass 加一个编码强制参数,多数版本支持/Encoding UTF-8。如果版本不支持该参数,就把输出文件用记事本打开后另存为 ANSI 再查阅,或者直接用 PowerShell 读取并重编码:

Get-Content "C:\temp\result.txt" -Encoding Default | Set-Content "C:\temp\result_utf8.txt" -Encoding UTF8

这样一步转换,内容就能正常显示了。现在的系统模板里,正确设置输出编码比调整系统区域设置要省麻烦得多。

4.3 提取结果为空:LSASS 内存无可用缓存

现象:程序正常跑完,扫描了若干内存块,但结果为空,或者只出来几个不完整的字符串。

原因:机器设置了快速启动模式下的冷启动,且关机后内存被完全回收;或者是刚开机后还没发生任何本地认证,LSASS 内存里没有沉淀口令。

解决:最简单的方法是触发一次本机登录,比如锁屏再解锁一次,或者运行一个需要输入密码的服务,然后立即重新执行 findpass。另外可以检查注册表HKLM\SECURITY\Cache是否为空,为空则说明系统未开启缓存登录策略,这种情况必须在组策略里启用交互式登录缓存次数设置。

4.4 杀毒软件实时拦截

现象:运行 findpass 后几秒内进程被强制退出,或者结果文件生成瞬间被隔离。

原因:杀毒软件或 EDR 把读取 LSASS 内存的行为归类为可疑活动,无论工具本身是否恶意,行为特征一致就会触发。

解决:如果这是你的测试机,可以暂时把目录加入排除列表,跑完再恢复。不少安全产品支持命令行排除,你可以这样操作:把 findpass 放在一个固定目录,然后只对该目录做排除,不关闭实时防护,这样既能执行又不会引入额外风险。

5. 压缩时间窗的验证与自动化联动

5.1 锁定时间窗:减少凭据驻留时长的策略

提取成功后,接下来要处理的是如何缩短明文口令在内存中的存活时间。对安全加固来说,能提取出来一次,也意味着攻击者能提取一次,所以验证完必须清理内存中沉淀的凭据。

可以在验证流程后强制重启 LSASS 或建议配合补丁使用官方凭据保护机制。但有时你不想重启机器,那就用下面的方式重新生成凭据缓存:

klist -li 0:0x3e7 purge

这个命令能清空当前会话的 Kerberos 票据缓存,对于内存中的明文密码缓存,关键手段是注销所有远程登录会话并重启机器,这样内存中的凭据残留会被完全冲刷。

5.2 将 findpass 纳入巡检脚本的模板

单纯的提取对运维帮助有限,实际工作中我会把 findpass 的结果喂给密码强度分析脚本,用于发现弱口令和重复使用的口令。参考这个 Bash 脚本模板:

#!/bin/bash # 密码巡检脚本,检测重复口令与长度小于 8 的弱密码 while IFS= read -r line; do case "$line" in *[PASSWORD]*) pwd=$(echo "$line" | awk -F'[/ ]' '{print $2}') len=${#pwd} if [ "$len" -lt 8 ]; then echo "弱口令账户探测到:$line" fi ;; esac done < /tmp/findpass_results.txt

这个脚本的核心逻辑是从 findpass 的输出文件里提取密码字段,然后判断长度是否满足最小阈值,重复口令的检测则需要先做一次排序去重,再对比出现次数。你可以把脚本挂到计划任务里,每月巡检一次,结果自动发邮件或落库归档,这样密码安全状态随时可查。

5.3 结果的交叉验证:不唯工具论

最后还有一件值得做的事,直接用另一种方式验证提取结果的正确性。findpass 的输出本质上是内存快照扫描结果,不是数据库导出,遇到特殊多字节编码时也可能出现截断。

我通常会用 PowerShell 的凭据查询命令交叉比对:

Get-Credential | Select-Object -Property UserName, Password

这个命令会弹出一个交互窗口,手动输入密码后对比与 findpass 的结果是否一致。虽然 Get-Credential 拿到的密码也是驻留在内存里的对象,但它至少证明你的提取流程在真实环境中是有效且可复现的。

从那以后我每次做内存凭据提取,都会把编码参数和权限验证放在第一步强制走一遍,不跳过,不省略。因为太多环境差异都藏在你不注意的地方,一个编码参数能让你少折腾半小时乱码问题。希望这篇实战笔记能帮你顺畅跑通 findpass 的完整流程,少走一些弯路。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询