public static void TriagePSCredFile(Dictionary <string, string> MasterKeys, string credFile, bool unprotect = false) { // triage a saved PSCredential .xml // example - `Get-Credential | Export-Clixml -Path C:\Temp\cred.xml` if (!File.Exists(credFile)) { throw new Exception($"PSCredential .xml); file '{credFile}' is not accessible or doesn't exist!\n"); } var lastAccessed = File.GetLastAccessTime(credFile); var lastModified = File.GetLastWriteTime(credFile); var xmlDoc = new XmlDocument(); xmlDoc.Load(credFile); Console.WriteLine(" CredFile : {0}", credFile); Console.WriteLine(" Accessed : {0}", lastAccessed); Console.WriteLine(" Modified : {0}", lastModified); var props = xmlDoc.GetElementsByTagName("Props"); if (props.Count > 0) { var userName = props[0].ChildNodes[0].InnerText; var dpapiBlob = props[0].ChildNodes[1].InnerText; Console.WriteLine(" User Name : {0}", userName); var blobBytes = Helpers.StringToByteArray(dpapiBlob); if (blobBytes.Length > 0) { var decBytesRaw = Dpapi.DescribeDPAPIBlob(blobBytes, MasterKeys, "blob", unprotect); if ((decBytesRaw != null) && (decBytesRaw.Length != 0)) { var password = ""; var finalIndex = Array.LastIndexOf(decBytesRaw, (byte)0); if (finalIndex > 1) { var decBytes = new byte[finalIndex + 1]; Array.Copy(decBytesRaw, 0, decBytes, 0, finalIndex); password = Encoding.Unicode.GetString(decBytes); } else { password = Encoding.ASCII.GetString(decBytesRaw); } Console.WriteLine(" Password : {0}", password); } } } Console.WriteLine(); }
public static void DisplayCredProfile(Dictionary <string, string> MasterKeys, XmlNode credProfileNode, bool unprotect = false) { // helper that displays a Credential Profile/Logon settings XML node from RDG/RDCMan.settings files var profileName = credProfileNode["profileName"].InnerText; if (credProfileNode["userName"] == null) { // have a profile name only Console.WriteLine(" Cred Profile : {0}", profileName); } else { var userName = credProfileNode["userName"].InnerText.Trim(); var domain = credProfileNode["domain"].InnerText.Trim(); var b64Password = credProfileNode["password"].InnerText; var password = ""; var fullUserName = ""; if (String.IsNullOrEmpty(domain)) { fullUserName = userName; } else { fullUserName = $"{domain}\\{userName}"; } Console.WriteLine(" Profile Name : {0}", profileName); Console.WriteLine(" UserName : {0}", fullUserName); var passwordDPAPIbytes = Convert.FromBase64String(b64Password); if (passwordDPAPIbytes.Length <= 0) { return; } var decBytesRaw = Dpapi.DescribeDPAPIBlob(passwordDPAPIbytes, MasterKeys, "rdg", unprotect); if (decBytesRaw.Length != 0) { // chop off anything after the UNICODE end var finalIndex = Array.LastIndexOf(decBytesRaw, (byte)0); if (finalIndex > 1) { var decBytes = new byte[finalIndex + 1]; Array.Copy(decBytesRaw, 0, decBytes, 0, finalIndex); password = Encoding.Unicode.GetString(decBytes); } else { password = Encoding.ASCII.GetString(decBytesRaw); } } Console.WriteLine(" Password : {0}", password); } }
public static void TriageKeePassKeyFile(Dictionary <string, string> MasterKeys, string keyFilePath = "", bool unprotect = false) { if (!File.Exists(keyFilePath)) { return; } var lastAccessed = File.GetLastAccessTime(keyFilePath); var lastModified = File.GetLastWriteTime(keyFilePath); Console.WriteLine(" File : {0}", keyFilePath); Console.WriteLine(" Accessed : {0}", lastAccessed); Console.WriteLine(" Modified : {0}", lastModified); byte[] keyFileBytes = File.ReadAllBytes(keyFilePath); // entropy from KeePass source https://fossies.org/windows/misc/KeePass-2.47-Source.zip/KeePassLib/Keys/KcpUserAccount.cs (lines 44-47) byte[] keyBytes = Dpapi.DescribeDPAPIBlob(keyFileBytes, MasterKeys, "keepass", unprotect, Helpers.ConvertHexStringToByteArray("DE135B5F18A34670B2572429698898E6")); if (keyBytes.Length > 0) { Console.WriteLine(" Key Bytes : {0}", BitConverter.ToString(keyBytes).Replace("-", " ")); } }