Mimikatz:msv功能模块浅析
字数 2443 2025-08-06 18:07:44

Mimikatz MSV功能模块深度分析

0x01 环境准备与调试

编译环境配置

  • 开发环境: VS2022社区版
  • 常见编译问题及解决方案:
    1. 类型强制转换错误: 从"PVOID"到"DWORD"的指针截断
      • 解决方案: 在报错处修改为指针类型强制转换成DWORD
    2. PRINTER_NOTIFY_CATEGORY_ALL宏重定义
      • 解决方案: 将重复定义变量修改为原始定义的值
    3. 缺少Debug配置
      • 解决方案: 手动添加Debug配置

远程调试配置

  • 以管理员身份运行msvsmon.exe
  • 选择"无身份验证"模式最合适

0x02 Mimikatz命令执行机制

程序入口

  • 入口函数: wmain() (位于同名c文件中)
  • 命令处理循环:
    for (i = MIMIKATZ_AUTO_COMMAND_START; 
         (i < argc) && (status != STATUS_PROCESS_IS_TERMINATING) && (status != STATUS_THREAD_IS_TERMINATING); 
         i++) {
        kprintf(L"\n" MIMIKATZ L"(" MIMIKATZ_AUTO_COMMAND_STRING L") # %s\n", argv[i]);
        status = mimikatz_dispatchCommand(argv[i]);
    }
    

命令分发机制

  1. 命令传入mimikatz_dispatchCommand()函数
  2. 根据命令前缀决定执行方式:
    • !+: 使用mimidrv.sys驱动执行
    • 默认: 通过mimikatz_doLocal()进入常用命令场景

模块与命令匹配

  • mimikatz_modules数组包含所有可用模块:
    const KUHL_M * mimikatz_modules[] = {
        &kuhl_m_standard, &kuhl_m_crypto, &kuhl_m_sekurlsa,
        &kuhl_m_kerberos, &kuhl_m_ngc, &kuhl_m_privilege,
        &kuhl_m_process, &kuhl_m_service, &kuhl_m_lsadump,
        &kuhl_m_ts, &kuhl_m_event, &kuhl_m_misc,
        &kuhl_m_token, &kuhl_m_vault, &kuhl_m_minesweeper,
        #if defined(NET_MODULE)
        &kuhl_m_net,
        #endif
        &kuhl_m_dpapi,&kuhl_m_busylight,&kuhl_m_sysenv,
        &kuhl_m_sid, &kuhl_m_iis, &kuhl_m_rpc,
        &kuhl_m_sr98, &kuhl_m_rdm, &kuhl_m_acr,
    };
    
  • 匹配流程:
    1. 将module参数与各模块的shortName比较
    2. 将command参数与模块中的命令比较
    3. 执行匹配的命令函数

0x03 MSV模块深入分析

MSV模块概述

  • 功能: 枚举LM & NTLM凭证
  • 核心原理: 通过分析lsasrv.dll中的LogonSessionListLock()函数定位LogonSessionListLogonSessionListCount全局变量

关键数据结构

typedef struct _KUHL_M_SEKURLSA_PACKAGE {
    const wchar_t * Name;
    PKUHL_M_SEKURLSA_ENUM_LOGONDATA CredsForLUIDFunc;
    BOOL isValid;
    const wchar_t * ModuleName;
    KUHL_M_SEKURLSA_LIB Module;
} KUHL_M_SEKURLSA_PACKAGE, *PKUHL_M_SEKURLSA_PACKAGE;

MSV模块初始化

KUHL_M_SEKURLSA_PACKAGE kuhl_m_sekurlsa_msv_package = {
    L"msv",
    kuhl_m_sekurlsa_enum_logon_callback_msv,
    TRUE,
    L"lsasrv.dll",
    {{{NULL, NULL}, 0, 0, NULL}, FALSE, FALSE}
};

执行流程

  1. 入口函数: kuhl_m_sekurlsa_msv()
  2. 调用链:
    • kuhl_m_sekurlsa_getLogonData()
    • kuhl_m_sekurlsa_enum()
    • kuhl_m_sekurlsa_acquireLSA()

关键步骤分析

1. 获取LSASS进程信息

  • 通过kull_m_process_getProcessIdForName()获取lsass.exe的PID
  • 调用链:
    • kull_m_process_getProcessInformation()
    • kull_m_process_NtQuerySystemInformation()
    • NtQuerySystemInformation() (未公开系统API)

2. 打开LSASS进程

  • 使用OpenProcess(processRights, FALSE, pid)获取进程句柄
  • 初始化内存结构:
    KUHL_M_SEKURLSA_CONTEXT cLsass = {NULL, {0, 0, 0}};
    

3. 获取系统版本信息

  • 存储Windows版本信息到cLsass.osContext
  • 示例值(Windows 1803):
    • MIMIKATZ_NT_BUILD_NUMBER=17134
    • MIMIKATZ_NT_MINOR_VERSION=0
    • MIMIKATZ_NT_MAJOR_VERSION=10

4. 获取模块信息

  • 通过kull_m_process_peb()获取PEB(进程环境块)
  • 遍历PEB.Ldr.InMemoryOrderModuleList查找lsasrv.dll模块
  • 回调函数kuhl_m_sekurlsa_findlibs()存储模块信息

5. 定位关键变量

  • 使用kuhl_m_sekurlsa_utils_search_generic搜索特征码
  • 通过偏移量定位:
    • LogonSessionList
    • LogonSessionListCount
  • 示例偏移(Windows 1803):
    • LogonSessionListCount相对LogonSessionListLock: -4
    • LogonSessionList相对LogonSessionListLock: 23

6. 获取加密密钥

  • 调用kuhl_m_sekurlsa_nt6_acquireKeys()
  • 使用kull_m_patch_getGenericFromBuild()根据系统版本获取特征码
  • 搜索并获取初始化向量和密钥

7. 枚举会话信息

  • 根据系统版本确定结构体偏移量
  • LogonSessionList获取:
    • UserName
    • LogonDomain
    • LogonServer
  • 回调函数kuhl_m_sekurlsa_enum_callback_logondata打印信息

8. 获取凭证信息

  • 调用链:
    • kuhl_m_sekurlsa_enum_logon_callback_msv()
    • kuhl_m_sekurlsa_msv_enum_cred()
    • kuhl_m_sekurlsa_msv_enum_cred_callback_std()
    • kuhl_m_sekurlsa_genericCredsOutput()

9. 提取NTLM哈希

  • 结合特征码和偏移量定位内存中的NTLM哈希
  • 使用kull_m_string_wprintf_hex()将哈希值转换为字符串输出

0x04 技术总结

核心原理

Mimikatz通过以下步骤获取NTLM凭证:

  1. 定位lsass.exe进程中的lsasrv.dll模块
  2. 通过特征码搜索定位LogonSessionListLogonSessionListCount全局变量
  3. 解析LogonSessionList结构体
  4. 根据系统特定的偏移量读取用户凭证信息

防御规避

  • 直接从lsass.exe进程内存读取敏感数据
  • 会被大多数杀软/EDR检测为可疑行为
  • 需要收集和维护不同Windows版本的特征码和偏移量

关键点

  1. 版本适配: 需要为不同Windows版本维护特征码和偏移量
  2. 内存分析: 通过分析lsass.exe进程内存获取凭证
  3. 加密处理: 需要获取系统密钥来解密受保护的内存区域
  4. 结构解析: 深入理解Windows登录会话数据结构
Mimikatz MSV功能模块深度分析 0x01 环境准备与调试 编译环境配置 开发环境 : VS2022社区版 常见编译问题及解决方案 : 类型强制转换错误 : 从"PVOID"到"DWORD"的指针截断 解决方案: 在报错处修改为指针类型强制转换成DWORD PRINTER_ NOTIFY_ CATEGORY_ ALL宏重定义 解决方案: 将重复定义变量修改为原始定义的值 缺少Debug配置 解决方案: 手动添加Debug配置 远程调试配置 以管理员身份运行msvsmon.exe 选择"无身份验证"模式最合适 0x02 Mimikatz命令执行机制 程序入口 入口函数: wmain() (位于同名c文件中) 命令处理循环: 命令分发机制 命令传入 mimikatz_dispatchCommand() 函数 根据命令前缀决定执行方式: !+ : 使用mimidrv.sys驱动执行 默认: 通过 mimikatz_doLocal() 进入常用命令场景 模块与命令匹配 mimikatz_modules 数组包含所有可用模块: 匹配流程: 将module参数与各模块的 shortName 比较 将command参数与模块中的命令比较 执行匹配的命令函数 0x03 MSV模块深入分析 MSV模块概述 功能: 枚举LM & NTLM凭证 核心原理: 通过分析lsasrv.dll中的 LogonSessionListLock() 函数定位 LogonSessionList 和 LogonSessionListCount 全局变量 关键数据结构 MSV模块初始化 执行流程 入口函数: kuhl_m_sekurlsa_msv() 调用链: kuhl_m_sekurlsa_getLogonData() kuhl_m_sekurlsa_enum() kuhl_m_sekurlsa_acquireLSA() 关键步骤分析 1. 获取LSASS进程信息 通过 kull_m_process_getProcessIdForName() 获取lsass.exe的PID 调用链: kull_m_process_getProcessInformation() kull_m_process_NtQuerySystemInformation() NtQuerySystemInformation() (未公开系统API) 2. 打开LSASS进程 使用 OpenProcess(processRights, FALSE, pid) 获取进程句柄 初始化内存结构: 3. 获取系统版本信息 存储Windows版本信息到 cLsass.osContext 示例值(Windows 1803): MIMIKATZ_NT_BUILD_NUMBER=17134 MIMIKATZ_NT_MINOR_VERSION=0 MIMIKATZ_NT_MAJOR_VERSION=10 4. 获取模块信息 通过 kull_m_process_peb() 获取PEB(进程环境块) 遍历 PEB.Ldr.InMemoryOrderModuleList 查找lsasrv.dll模块 回调函数 kuhl_m_sekurlsa_findlibs() 存储模块信息 5. 定位关键变量 使用 kuhl_m_sekurlsa_utils_search_generic 搜索特征码 通过偏移量定位: LogonSessionList LogonSessionListCount 示例偏移(Windows 1803): LogonSessionListCount 相对 LogonSessionListLock : -4 LogonSessionList 相对 LogonSessionListLock : 23 6. 获取加密密钥 调用 kuhl_m_sekurlsa_nt6_acquireKeys() 使用 kull_m_patch_getGenericFromBuild() 根据系统版本获取特征码 搜索并获取初始化向量和密钥 7. 枚举会话信息 根据系统版本确定结构体偏移量 从 LogonSessionList 获取: UserName LogonDomain LogonServer 回调函数 kuhl_m_sekurlsa_enum_callback_logondata 打印信息 8. 获取凭证信息 调用链: kuhl_m_sekurlsa_enum_logon_callback_msv() kuhl_m_sekurlsa_msv_enum_cred() kuhl_m_sekurlsa_msv_enum_cred_callback_std() kuhl_m_sekurlsa_genericCredsOutput() 9. 提取NTLM哈希 结合特征码和偏移量定位内存中的NTLM哈希 使用 kull_m_string_wprintf_hex() 将哈希值转换为字符串输出 0x04 技术总结 核心原理 Mimikatz通过以下步骤获取NTLM凭证: 定位lsass.exe进程中的lsasrv.dll模块 通过特征码搜索定位 LogonSessionList 和 LogonSessionListCount 全局变量 解析 LogonSessionList 结构体 根据系统特定的偏移量读取用户凭证信息 防御规避 直接从lsass.exe进程内存读取敏感数据 会被大多数杀软/EDR检测为可疑行为 需要收集和维护不同Windows版本的特征码和偏移量 关键点 版本适配 : 需要为不同Windows版本维护特征码和偏移量 内存分析 : 通过分析lsass.exe进程内存获取凭证 加密处理 : 需要获取系统密钥来解密受保护的内存区域 结构解析 : 深入理解Windows登录会话数据结构