# Decrypting Credentials Stored in Remote Desktop Connection Manager (RDCMan) .rdg

•
•
•
•
•
•

Today, while logging into a Windows Server via my favorite RDP tool (RDCMan), I was faced with the “Your password has expired” prompt.  No worries, just enter my password and change it.

Except for the part where the password has been saved and I neglected to add it to my password manager. Oops.  So, naturally, the first thing I want to do is just go look in the saved file (an .RDG).  Not surprisingly, it’s encrypted with something:

After tinkering around wit ConvertFrom-SecureString, I guessed that it was probably done by something in the application itself.  So, I started by importing the DLLs as modules and looking around.  I imported the MSTSCLib.dll, and started tabbing through the types.  I stumbled onto a good potential in MSTSCLib.IMsTscSecuredSettings, but alas, it was a false alarm.

I dug around a little more, but met with similar dashed hopes.

I then started looking for ways to decrypt it using the RDCMan executable.

Sometimes, you can luck out by attempting to run Import-Module against an EXE.  It might have exported commands available. Nope. Not it.

Sometimes, you can add an EXE as an assembly, and then import:

Struck out again.

And then, you can sometimes load it via reflection:

Ooh, promising.

Next, I decided to see if there were any exports that could further ignite hope:

Now that we have something maybe to go on, we can try importing and creating some objects to see what sticks.  First, import the reflected assembly:

The module is called RDCMan, so that’s what we’re going to use as the base to add the values we discovered in GetExportedTypes() a few steps earlier:

Looks like we have a couple of potential opportunities with EncryptionMethod and EncryptionSettings.  Running a Get-Member on both of those helps us further narrow down the field of “interesting things” to EncryptionSettings:

While we’re here, let’s also take a look at what methods RDCMan.Encryption has to offer us.  After typing [RDCMan.Encryption]:: in the prompt and tabbing, I’m delighted to find two methods: DecryptPasswords() and DecryptString().

Both look like potential winners, but the DecryptString caught my eye because the OverloadDefinitions had some detail about what to pass to it: I needed an encrypted string (which I had in the .RDG XML file) and something in RdcMan.EncryptionSettings.  I had successfully executed New-Object against RdcMan.EncryptionSettings, so mayyyyybe:

BOOM. SUCCESS.

So, I bundled it all up as a handy script that you can copy/paste here or get over on the TN Gallery.  Note: If you saved the file with a Windows account credential and attempted to run this from a different computer, this method won’t work.

# Decrypt passwords in RDG files
param($RDGFile,$PasswordString,
$RDCManSource ) If (!$RDCManSource)
{
$RDCManSource = (Get-ChildItem -Path @('C:\Program Files\Microsoft', 'C:\Program Files (x86)\Microsoft') -File "RDCMan.exe" -Recurse -ErrorAction SilentlyContinue)[0] } If (!$RDCManSource)
{
Write-Error "Remote Desktop Manager must be installed.  If it is installed, use the -RDCManSource parameter to specify the executable's location."
Exit
}
else
{
try
{
$Assembly = [Reflection.Assembly]::LoadFile($RDCManSource.FullName)
}
catch
{
$_.Exception.Message.ToString(); Write-Host "Catch"; Exit } try { Import-Module$Assembly }
catch
{
$_.Exception.Message.ToString(); Write-Host "Import Exception"; exit } } If ($RDGFile)
{
[xml]$Data = Get-Content$RDGFile
$CredentialValues =$Data.SelectNodes("*//logonCredentials")
$global:Output = @() foreach ($obj in $CredentialValues) { try {$EncryptionSettings = New-Object -TypeName RdcMan.EncryptionSettings
$Password = [RdcMan.Encryption]::DecryptString($obj.password, $EncryptionSettings) } catch {$_.Exception.Message.ToString(); continue
}
If ($Password -and ($Password -notcontains 'Failed to decrypt'))
{
$CredObject = New-Object PSObject$CredObject | Add-Member -Type NoteProperty -Name "ProfileName" -Value $obj.ProfileName -ea SilentlyContinue -Force$CredObject | Add-Member -Type NoteProperty -Name "UserName" -Value $obj.username -ea SilentlyContinue -Force$CredObject | Add-Member -Type NoteProperty -Name "Password" -Value $Password$CredObject | Add-Member -Type NoteProperty -Name "Domain" -Value $obj.domain$global:Output += $CredObject } } If ($Output)
{
$Output } Else { Write-Host "Nothing to show." } } else { If ($PasswordString)
{
$EncryptionSettings = New-Object -TypeName RdcMan.EncryptionSettings$Password = [RdcMan.Encryption]::DecryptString($PasswordString,$EncryptionSettings)
Write-Host "Cleartext password: $($Password)"
}
}

Good luck recovering!

Helping companies conquer inferior technology since 1997. I spend my time developing and implementing technology solutions so people can spend less time with technology. Specialties: Active Directory and Exchange consulting and deployment, Virtualization, Disaster Recovery, Office 365, datacenter migration/consolidation, cheese.

This site uses Akismet to reduce spam. Learn how your comment data is processed.