Home About

Exploring Remote Desktop Manager

Introduction

I've been meaning to take a look at this product for a while, since I ported Ben Turner and Rich Hicks implementation of Remote Desktop Connection Manager to .NET. There PowerShell Version can of that can be found here.

With that said, Remote Desktop Manager was the next one to look at (no, its not the same thing :D).

 

image-20210327155156598

The Application

It has some cool Credential Entry options:

image-20210327155254191

It also has a load of different Sessions, for example:

image-20210327155430014

Even AD, Citrix and iDRACs:

image-20210327155554519

As well as PowerShell Remoting:

image-20210327155620299

I want to focus on extracting Windows Credentials, although there are a lot of options for other Third-Party Credentials.

Spectating the Application

I want to see where its storing the data I give it, easiest way is Process Monitor:

image-20210327164245199

And in Remote Desktop Manager:

image-20210327164423465

When that is done, it goes to the Local Data Source:

image-20210327164504714

Some ProcMon later, a few interesting DLLs are found:

C:\Program Files (x86)\Devolutions\Remote Desktop Manager Free\Devolutions.Wayk.Native.Windows.dll
C:\Program Files (x86)\Devolutions\Remote Desktop Manager Free\Devolutions.Wayk.Net.Windows.dll
C:\Program Files (x86)\Devolutions\Remote Desktop Manager Free\Devolutions.WaykDen.Client.dll
C:\Program Files (x86)\Devolutions\Remote Desktop Manager Free\Devolutions.Zxcvbn.dll
C:\Program Files (x86)\Devolutions\Remote Desktop Manager Free\Itenso.dll
C:\Program Files (x86)\Devolutions\Remote Desktop Manager Free\System.ValueTuple.dll
C:\Program Files (x86)\Devolutions\Remote Desktop Manager Free\x64\DevolutionsWayk.dll

As well as a bunch of operations in:

C:\Users\mez0\AppData\Local\Devolutions\RemoteDesktopManagerFree

Specifically:

C:\Users\mez0\AppData\Local\Devolutions\RemoteDesktopManagerFree\Connections.db

However, there is a file called RemoteDesktopManagerFree.cfg, which contains:

<EncryptedDataSources>
<string>SB8ec+PVfiJSo1mw93nSZ7al3imoRySDVs3PF1X9El82J2DBQ2L0BCGRLg7IjEZUANmAyoUYI4DRLO5/ZhTx4GggayCDYZNjaSPvqwqhlnN4d7tElLioaoA1UN0fFSOO4L0eQWzSYfWzmbnbO9LcWHyB3VDMGdHB2O9VfxWRHh0pZ95fyYLsr8asLNjilSH3r64SYHAaBeZHYBQGy5uoNsTY8JuqE/Ofsfu8MxOzmMXRGINN4Fu4ZiXTB4LOYPerNvd4Y3EmzJQWTh7mrwWfl+CkRzZ1Z5vDL/d86FSuqynfCc+ECkCEIVVeSuzXGLLEb8BuZ2z+H0qt9JyZ87zPX1VeSuzXGLLERcR3UCqIN75gyf3qfO/vDCZymNfXReWPFFht/PHivzs0TObbqCtd5TBlHCqkwjxM47N8/J7NYRmlpjbp/WTgNQvReRppJze+tYKhGTzLcIssu5EiqPwfczzi/kccsP9G/ujtK/0nIb1MyjskCVTUzk1TZ6IFzx1lpIeMYiXjgJ8cylfy8afMcDPfCeF+elt9KvU6frXWt270OsMOS5BQqDPfCeF+elt9XOQOct3RTzUs9jxm/LhS1qzpgAfU7r6QvUb/ayKq1rmgzkgvXE+3NQ==</string>
</EncryptedDataSources>

If I create another entry, does it give me two of these?

Nope, its still one:

image-20210327173254486

But, the Connections.db does update:

image-20210327173313137

Back to this database! To be honest, the Dashboard does mention this:

image-20210327173421599

Connections.db

As everything is pointing me to this database, I'll load it up in SqliteStudio. Clicking through all the available tables, ConnectionHistory contains the credentials names:

image-20210327175932548

TESTTESTTEST and TESTTESTTESTAGAIN contain different credentials, and the DATA field contains two different strings:

TESTTESTTEST:

1d5RlSD3ByJm5TykJ7s70/NZSIWYbbzqlHjD1JXLSQR9MpOx2OyHeJR4w9SVy0kEhN1qwu/Avif1OZYqMQpNWJPme5cowXkJ1yH5O9KR4MNrJWkurPbU7mFvYbcLsH0RoyDnHlJRHVJR46VgC/nIza9ppnbD/6BQYW9htwuwfRG0ipkmD/wgKt5F54WIa+KLod9kQ1fuXhUz3ZHFCDG9V/BHEJJia9SNMbSmfLeCv1icBRfZnQjn2jfx+jAavMPWfW70Cz4XfJgSJ6j/d9xLPA5Y4RF4hS8JitySMTL28PREua5IlpTFUa+lnYhzQAPjRamZGAlglEik7Ax2qZWDPE0BeYWSoMmvQZMgRgHxFAiOfxTIKFgAJpNPUlS9vl18THew6Jl5CmJBC/2E9RP0jBh0Zg/Jvx3KFg8nzY6NpBl6mgvLdjSOEvU5lioxCk1YxcUy7P8mfHRGLYLMlUA0AaWo9b+1umOJwSZ4N1qmBpr+MjpEsIWZgMqxmEhLEQUMd0eJyzNSHlOt3NNrCZ3Llm46Z4t4aEzSz22XDcA2MKP4uHNuKEBlwn6CshPHo8M5JKz4AMakCMl3oWLb10uYJnrqEqm0oIE4VCTEXPIrCXC1rEEtCVwPjF4134C2CODukLOE8sTqu5ggo7KOLCj9SEkVCywS93yLl92HOHXZVTWlLk04+uGsBm14fgRscJdCF5iDUTfovGieTSt+KRuNQQkScyS3xa407ThSeSlMl/WlmBgtTBbsl4JtWrwAx4smaVKC0xsdLw3oQkwSsKnRXdKwVz8C+Nn1C3/r4PF2yd2au840ziZYf8eabI+QzQBWN6w8xxmUElOD+D4hoMS/qd0U3PpktKGD+VODX3TdDMKL+KkoNh8tRD3V2fcP/R8NQ5WR9uu9NKDheY342OWv15W/nbo5Le47ufdFog2GCGq4QbJwoxGQEuuSdwpsWFVyiLOzni0vXkpsQyYHdo/Y5eVxdf7UutUeCRS6hO/0l+hBQEuLEqEzUizW+17u90nDOamOR1Mm/ainRTgzhGOUaNxe2BAXOXDYd0eJyzNSHlP10PejQaMANK+KYdtY5Qrv8+E5H/XDPKoYh6b/SdGeGK+KYdtY5Qrv8+E5H/XDPKoYh6b/SdGeGESdMr/Gv6ZyZzTvUGsB1Z6cOCHqL70QXbeNYpd0K6Mp/fq8b8cNUNk=

TESTTESTTESTAGAIN:

1d5RlSD3ByJm5TykJ7s70/NZSIWYbbzqlHjD1JXLSQR9MpOx2OyHeJR4w9SVy0kEhN1qwu/Avif1OZYqMQpNWJPme5cowXkJ1yH5O9KR4MNrJWkurPbU7mFvYbcLsH0RoyDnHlJRHVJR46VgC/nIza9ppnbD/6BQYW9htwuwfRG0ipkmD/wgKt5F54WIa+KLod9kQ1fuXhUz3ZHFCDG9VyBX+yEfmB704x8U41FQRFGcBRfZnQjn2jfx+jAavMPWz7M98q1he0h9GgtvMo/Ezd2JZMhLCQGGI2yIFCKUp7hqo4EWU/3qHPvZFCSRxn20RamZGAlglEik7Ax2qZWDPOa+yKNbqZWDfMPkaRAbNbmMxVfdXhc97EEq/6y/cT1Pfuexfw3RyQiRMXbHn6TUDp2+HG1QpRu3YZfMHAn6evfODUtGQwhbu6FKFFvdFA2UgTWLATAMY1TyK10AXzQHKBNCjP3n+3p6k+ozCyiiLv+0ZfaJ3CsZNRvfUSFnW7RSiJq8lKRHqB5NpxOsupD0lRUUG/9OuMgMk8Hwe/YA9GlH39h4jyUaovWE7AwuNyspuBCb53sT9wWPk63cxRUW4ECYEtgvSM7ckKCWxClCIpTo/1Trb5SAit0cnv+s3W4/Zb2aEznfdm98txHd+bYqtkN+cccOs9EJJBkqBK5WGLD9gwYfnCEN10Pi3BxSOGRH5NMXnA7OhuwwnqYx7Lf5Ixu3Pfhhm5db8+E5H/XDPKoYh6b/SdGeGGdX4MfzqI+6Us2r9akd9k2D+D4hoMS/qd0U3PpktKGD+VODX3TdDMJykuL4Xiqltf7VTbgvjaWwa2gTtb2JtaXtOFJ5KUyX9b31N08xk5EPiiwpPxliBjc0wazVCSjzt3Hch0q+WOqCMea+Sf5x9KmkkRf6uc8xPejYx64piiNYljylq5OpRiRss0Cch1luP7DyFLyUEDB9HjscnWZXuKdA2Wt9WueppiiyMbq1MJHX4xs+qRRdIOR+cwNfGsuVjyaeU3ab32va4XbnCvbEUZ9buyZHNeEQ6jEjQmrlW3G0gXtUKZ43DVbDgvdPWdT3/IDxKZoytSZ9h08mpDJO5Vwuo3eaxzjcroknkMltGnh/YG2eQqqKrMEkrPgAxqQIyYknkMltGnh/YG2eQqqKrMGfb4LrhoYBVSCjso4sKP1ISRULLBL3fItN+jj9AIuaopcQaz6s83vl

The first 213 characters are the same:

1d5RlSD3ByJm5TykJ7s70/NZSIWYbbzqlHjD1JXLSQR9MpOx2OyHeJR4w9SVy0kEhN1qwu/Avif1OZYqMQpNWJPme5cowXkJ1yH5O9KR4MNrJWkurPbU7mFvYbcLsH0RoyDnHlJRHVJR46VgC/nIza9ppnbD/6BQYW9htwuwfRG0ipkmD/wgKt5F54WIa+KLod9kQ1fuXhUz3ZHFCDG9V

As cool as this is, their Security Overview details:

All passwords stored in the data sources are encrypted using a strong encryption algorithm, to the extent that if a user attempts to access the data directly in the database, it will be considered unreadable.

It then goes on to say:

If you choose to store passwords locally, Remote Desktop Manager will use the same mechanism used by mstsc.exe (Remote Desktop Manager client), which stores the passwords in the Windows Credential Manager. It must be noted that the password will not be able to be viewed due to being encrypted by Windows. For obvious reasons, this choice also means that credentials stored in this fashion are not shared. Please refer to Windows Credential Manager for more information.

And finally:

The encryption key is built-in the application and is therefore the same for all copies of the software in circulation. It is imperative that you follow our recommended steps and apply a Security Provider to encrypt not only the passwords, but also all connection data stored in the data source. This will provide protection over your data at rest, using a key under your exclusive control.

So, if I establish a connection to a host, it should use the same mechanism as mstsc.exe and store credentials in the Credentials Manager. If that's the case, then RDPThief can be used to steal credentials from mstsc.exe. As for Windows Credential Manager, it is trivial to extract credentials from.

Before looking at the Windows Credential Manager, may as well see if the AES Key can be pulled from the Application; or if that is avoidable and a decryption function is accessible (similarly to Remote Desktop Connection Manager).

Crypto Hunting

Opening this in Process Hacker confirms it is a .NET application:

image-20210327183225733

Naturally, the next thing is DotPeek. Some poking around later, it seems the important segments are obfuscated:

image-20210327190243286

Reversing this can be a last resort. As I already mentioned, there are easier ways than reversing crypto to get credentials for RDP. I'll double check that they work, I can't really be bothered to debug the application to get the Key and IV when I don't need to.

Creating a Session

Lets create a session and see what it does:

image-20210327170112581

The above screenshot is the application loaded and pointed towards the credentials created earlier.

Its worth noting that this application has a lot of functionality. In this case, the Display:

image-20210327170147398

External presumably creates an mstsc.exe process. But, we'll see.

Now there is a new entry in Local Data Source:

image-20210327170318571

 

Opening a session within the application loads it like so:

image-20210327170411738

Looking at the process, it doesn't create an mstsc.exe process when opened as an embedded session, but it has a bunch of mstsc threads:

image-20210328124606824

This appears to be the MsTscAx Class, which makes sense.

When its opened external, thats when the mstsc.exe process is spawned as a child:

image-20210328124724079

So, how does Windows Credential Manager work here. Embedded first:

image-20210328124836589

Nothing.

And now external (I'm expecting mstsc.exe to add the credentials to this manager):

image-20210328125002561

As expected. TERMSRV/10.10.11.113 is now an entry.

This is trivial to extract with CredEnumerateA, and the only way to get mstsc.exe involved from RDPThief is to use the external feature. So far nothing specific is used to attack this application. However there is one last thing I want to check, and that is APIMonitor. I want to see how MsTscAx is being used.

API Monitor

Starting API Monitor and monitoring Remote Desktop Manager, mstscax.dll is seen an awful lot. Poking through the results, this sticks out:

image-20210328160234888

CredIsMarshaledCredentialW is the target within RDPThief. Looking through the code, Rio used Detours to hook this function and it can be seen on line 77.

RDPThief works by monitoring for mstsc.exe processes and injects the DLL into that process, this can be seen in the Agressor Script. A quote from the README:

An aggressor script accompanies it, which is responsible for managing the state, monitoring for new processes and injecting the shellcode in mstsc.exe. The DLL has been converted to shellcode using the sRDI project (https://github.com/monoxgas/sRDI). When enabled, RdpThief will get the process list every 5 seconds, search for mstsc.exe, and inject to it.

If the user is using the external functionality of Remote Desktop Manager, then RDPThief is fine. If the user is using the embedded functionality, then this DLL will need to be injected into that process.

The CNA for RDPThief uses bshinject as seen on line 28:

bshinject($1, $pid , "x64" ,script_resource("RdpThief_x64.tmp"));

And then uses bshell to type the file:

alias rdpthief_dump {
    bshell($1,"type %temp%\\data.bin")
}

So, in theory I can replicate this but point it at a different process:

image-20210328162553548

That works. Note 6644 is RemoteDesktopManagerFree.exe.

Finally, CredEnumerateA with SeatBelt:

image-20210328163652342

Conclusion

I'm actually not to sure why its all hashes, if you know please let me know on Twitter. Presumably, it is some kind of credential guard but I wanted to explore some fancy form of credential extraction. It is worth noting, however, that you could probably load a DLL into this process, but I prefer the shellcode injection that RDPThief uses; bit more lowkey. Final thing to mention here is that the code to hook the required function isn't complex so I didn't feel the need to rewrite it, its probably easier just to expand the RDPThief CNA script to handle Remote Desktop Manager.

Remote Desktop Manager is like any other session manager. It has its limitations at a Windows Level, but as an application it seems to be protecting its data enough for me to not be bothered to reverse it. That said, its just obfuscation and a hard-coded AES Key/IV. Using popular-repurposed tools like RDPThief and Seatbelt, it falls victim to credential extraction. It would be cool to see how it handles the PowerShell, Azure etc credentials too. But, that can be left for another time.