Win32Ntv.ps1
# Native Windows functions $source=@" using System; using System.IO; using System.Text; using System.Runtime.InteropServices; using System.Collections; using System.Collections.Generic; using System.Management.Automation; namespace AADInternals { public static class Native { /** * Type definitions */ private enum DhcpRequestFlags : uint { DHCPCAPI_REQUEST_PERSISTENT = 1U, DHCPCAPI_REQUEST_SYNCHRONOUS = 2U, DHCPCAPI_REQUEST_ASYNCHRONOUS = 4U, DHCPCAPI_REQUEST_CANCEL = 8U, DHCPCAPI_REQUEST_MASK = 15U } private struct DHCPCAPI_PARAMS_ARRAY { public uint nParams; public IntPtr Params; } private struct DHCPCAPI_PARAMS { public uint Flags; public uint OptionId; [MarshalAs(UnmanagedType.Bool)] public bool IsVendor; public IntPtr Data; public uint nBytesData; } /** * Native methods */ [DllImport("dhcpcsvc.dll", CharSet = CharSet.Unicode)] private static extern int DhcpRequestParams(DhcpRequestFlags Flags, IntPtr Reserved, string AdapterName, IntPtr ClassId, DHCPCAPI_PARAMS_ARRAY SendParams, DHCPCAPI_PARAMS_ARRAY RecdParams, IntPtr Buffer, ref uint pSize, string RequestIdStr); [DllImport("dhcpcsvc.dll", CharSet = CharSet.Unicode)] private static extern int DhcpUndoRequestParams(uint Flags, IntPtr Reserved, string AdapterName, string RequestIdStr); [DllImport("dhcpcsvc.dll", CharSet = CharSet.Unicode)] private static extern int DhcpCApiInitialize(out uint Version); [DllImport("dhcpcsvc.dll", CharSet = CharSet.Unicode)] private static extern int DhcpCApiCleanup(); [DllImport("kernel32.dll", SetLastError = true)] public static extern Int32 RegQueryInfoKey( Microsoft.Win32.SafeHandles.SafeRegistryHandle hKey, StringBuilder lpClass, [In, Out] ref UInt32 lpcbClass, UInt32 lpReserved, out UInt32 lpcSubKeys, out UInt32 lpcbMaxSubKeyLen, out UInt32 lpcbMaxClassLen, out UInt32 lpcValues, out UInt32 lpcbMaxValueNameLen, out UInt32 lpcbMaxValueLen, out UInt32 lpcbSecurityDescriptor, out Int64 lpftLastWriteTime ); /** * Ncrypt imports */ [DllImport("ncrypt.dll", SetLastError = true)] private static extern int NCryptOpenStorageProvider( ref IntPtr hProvider, [MarshalAs(UnmanagedType.LPWStr)] string szProviderName, int dwFlags); [DllImport("ncrypt.dll", SetLastError = true)] private static extern int NCryptImportKey( IntPtr hProvider, IntPtr hImportKey, [MarshalAs(UnmanagedType.LPWStr)] string szBlobType, IntPtr pParameterList, //shoud be NcryptBufferDesc ref IntPtr phKey, byte[] pbData, int cbData, int dwFlags); [DllImport("ncrypt.dll", SetLastError = true)] private static extern int NCryptExportKey( IntPtr hKey, IntPtr hExportKey, [MarshalAs(UnmanagedType.LPWStr)] string szBlobType, IntPtr pParameterList, //shoud be NcryptBufferDesc [In, Out] byte[] pbOutput, uint cbOutput, ref uint pcbResult, int dwFlags); [DllImport("ncrypt.dll", SetLastError = true)] private static extern int NCryptSetProperty( IntPtr hKey, [MarshalAs(UnmanagedType.LPWStr)] string szProperty, byte[] pbInput, int cbInput, int dwFlags); [DllImport("ncrypt.dll", SetLastError = true)] private static extern int NCryptFinalizeKey( IntPtr hKey, int dwFlags); [DllImport("ncrypt.dll", SetLastError = true)] private static extern int NCryptFreeObject( IntPtr hObject); [DllImport("Ncrypt.dll", SetLastError = true)] private static extern int NCryptDecrypt( IntPtr hKey, [MarshalAs(UnmanagedType.LPArray)] byte[] pbInput, int cbInput, IntPtr pPaddingInfo, [MarshalAs(UnmanagedType.LPArray)] byte[] pbOutput, int cbOutput, ref int pcbResult, int dwFlags); /** * BCRYPT.dll imports */ [DllImport("bcrypt.dll", SetLastError = true, CharSet = CharSet.Unicode)] private static extern uint BCryptOpenAlgorithmProvider( out IntPtr phAlgorithm, string pszAlgId, string pszImplementation, uint dwFlags); [DllImport("bcrypt.dll", SetLastError = true, CharSet = CharSet.Unicode)] private static extern uint BCryptCreateHash( IntPtr phAlgorithm, out IntPtr phHash, byte[] pbHashObject, //out IntPtr pbHashObject , uint cbHashObject, byte[] pbSecret, uint cbSecret, uint dwFlags); [DllImport("bcrypt.dll", SetLastError = true, CharSet = CharSet.Unicode)] private static extern uint BCryptHashData( IntPtr hHash, byte[] pbInput, uint cbInput, uint dwFlags); [DllImport("bcrypt.dll", SetLastError = true, CharSet = CharSet.Unicode)] private static extern uint BCryptFinishHash( IntPtr hHash, byte[] pbOutput, uint cbOutput, uint dwFlags); [DllImport("bcrypt.dll", SetLastError = true, CharSet = CharSet.Unicode)] private static extern uint BCryptGetProperty( IntPtr hObject, string pszProperty, out IntPtr pbOutput, uint cbOutput, out uint pcbResult, uint dwFlags); [DllImport("bcrypt.dll", SetLastError = true, CharSet = CharSet.Unicode)] private static extern uint BCryptCloseAlgorithmProvider( IntPtr hAlgorithm, uint dwFlags); [DllImport("bcrypt.dll", SetLastError = true, CharSet = CharSet.Unicode)] private static extern uint BCryptDestroyHash( IntPtr hHash); [DllImport("bcrypt.dll", SetLastError = true, CharSet = CharSet.Unicode)] private static extern uint BCryptDeriveKeyPBKDF2( IntPtr hAlgorighm, byte[] pbPassword, uint cbPassword, byte[] pbSalt, uint cbSalt, UInt64 cIterations, byte[] pbDerivedKey, uint cbDerviedKey, uint dwFlags); /** * Advapi32 imports */ [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool CryptAcquireContext(ref IntPtr hProv, string pszContainer, string pszProvider, uint dwProvType, uint dwFlags); [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool CryptCreateHash(IntPtr hProv, uint algId, IntPtr hKey, uint dwFlags, ref IntPtr phHash); [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool CryptSetHashParam(IntPtr phHash, uint dwParam, byte[] pMacInfo, uint dwFlags); [DllImport("advapi32.dll", SetLastError = true)] private static extern bool CryptHashData(IntPtr hHash, byte[] pbData, uint dataLen, uint flags); [DllImport("advapi32.dll", SetLastError = true)] private static extern bool CryptGetHashParam(IntPtr hHash, uint dwParam, byte[] pbData, ref uint dwDataLen, uint dwFlags); [DllImport("advapi32.dll", SetLastError = true)] private static extern bool CryptDestroyHash(IntPtr hHash); [DllImport("advapi32.dll", SetLastError = true)] private static extern bool CryptDestroyKey(IntPtr phKey); [DllImport("advapi32.dll", EntryPoint = "CryptReleaseContext", CharSet = CharSet.Unicode, SetLastError = true)] private static extern bool CryptReleaseContext(IntPtr hProv, Int32 dwFlags); [DllImport(@"advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool CryptImportKey(IntPtr hProv, byte[] pbKeyData, UInt32 dwDataLen, IntPtr hPubKey, UInt32 dwFlags, ref IntPtr hKey); /** * Method for calculating the weird HMAC used with DPAPI masterkeys */ public static byte[] getHMAC(uint algId, byte[] key, byte[] data, int maxLen = 1024) { // Return value byte[] retVal = null; // Create the HMAC Information blobl MemoryStream hmacInfoStream = new MemoryStream(28); hmacInfoStream.Write(BitConverter.GetBytes(algId), 0, 4); hmacInfoStream.Write((new byte[]{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // pInnerString 0x00, 0x00, 0x00, 0x00, // DWORD InnerString length 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // pOuterString 0x00, 0x00, 0x00, 0x00 // DWORD OuterString length }), 0, 24); byte[] hmacInfo = hmacInfoStream.ToArray(); // Create the key blob MemoryStream keyBlobStream = new MemoryStream(); keyBlobStream.Write((new byte[] { 0x08, // PLAINTEXTKEYBLOB 0x02, // CUR_BLOB_VERSION // WORD reserved 0x00, 0x00, // DWORD ALG_ID: RC2 (0x00006602) 0x02, 0x66, 0x00, 0x00, }), 0, 8); keyBlobStream.Write(BitConverter.GetBytes((uint)key.Length), 0, 4); keyBlobStream.Write(key, 0, key.Length); byte[] keyBlob = keyBlobStream.ToArray(); IntPtr hProv = new IntPtr(); IntPtr hKey = new IntPtr(); IntPtr hHash = new IntPtr(); if (CryptAcquireContext(ref hProv, null, null, 24 /*PROV_RSA_AES*/, 0xF0000000 /*CRYPT_VERIFYCONTEXT*/)) { if (CryptImportKey(hProv, keyBlob, (uint)keyBlob.Length, IntPtr.Zero, 0x00000100 /*CRYPT_IPSEC_HMAC_KEY*/, ref hKey)) { if (CryptCreateHash(hProv, 0x00008009 /*HMAC*/, hKey, 0, ref hHash)) { if (CryptSetHashParam(hHash, 0x0005 /*HP_HMAC_INFO*/, hmacInfo, 0)) { if (CryptHashData(hHash, data, (uint)data.Length, 0)) { uint bufferSize = 0; if (CryptGetHashParam(hHash, 0x0002 /*HP_HASHVAL*/, null, ref bufferSize, 0)) { byte[] buffer = new byte[bufferSize]; if (CryptGetHashParam(hHash, 0x0002 /*HP_HASHVAL*/, buffer, ref bufferSize, 0)) { retVal = new byte[Math.Min(buffer.Length, maxLen)]; Array.Copy(buffer, 0, retVal, 0, Math.Min(buffer.Length, maxLen)); } } } } CryptDestroyHash(hHash); } CryptDestroyKey(hKey); } CryptReleaseContext(hProv, 0); } return retVal; } /** * Method for creating PKCS5 PBKDF2 HMAC used with DPAPI masterkeys */ public static byte[] getPBKDF2(uint algId, byte[] password, byte[] salt, int iterations, int keyLen, bool isDPAPIInteral = false) { // Return value byte[] retVal = null; IntPtr hProv = new IntPtr(); IntPtr hHash = new IntPtr(); if (CryptAcquireContext(ref hProv, null, null, 24 /*PROV_RSA_AES*/, 0xF0000000 /*CRYPT_VERIFYCONTEXT*/)) { if (CryptCreateHash(hProv, (uint)algId, IntPtr.Zero, 0, ref hHash)) { if (CryptHashData(hHash, password, (uint)password.Length, 0)) { uint sHmac = 0; if (CryptGetHashParam(hHash, 0x0002 /*HP_HASHVAL*/, null, ref sHmac, 0)) { byte[] buffer = new byte[keyLen]; int keyPos = 0; for (uint count = 1; keyLen > 0; count++) { // Create a new salt MemoryStream asalt = new MemoryStream(); asalt.Write(salt, 0, salt.Length); byte[] countSize = BitConverter.GetBytes((uint)count); Array.Reverse(countSize); asalt.Write(countSize, 0, 4); byte[] bAsalt = asalt.ToArray(); // Get the first HMAC byte[] d1 = getHMAC(algId, password, bAsalt); // Copy the result to new buffer byte[] obuf = new byte[d1.Length]; Array.Copy(d1, 0, obuf, 0, d1.Length); // Get new HMAC based to this one as many times as requested for (int i = 1; i < iterations; i++) { d1 = getHMAC(algId, password, d1); for (int j = 0; j < sHmac; j++) { obuf[j] ^= d1[j]; } if (isDPAPIInteral) { Array.Copy(obuf, 0, d1, 0, sHmac); } } // This is for scenario, where the requested key is longer than the HMAC value int r = Math.Min((int)keyLen, (int)sHmac); Array.Copy(obuf, 0, buffer, keyPos, r); keyPos += r; keyLen -= r; } retVal = buffer; } } CryptDestroyHash(hHash); } CryptReleaseContext(hProv, 0); } return retVal; } /** * Utility function to calculate PBKDF2 */ public static byte[] getPBKDF2(byte[] password,byte[] salt = null, uint iterations = 10000) { IntPtr phAlgorithm; byte[] retVal = new byte[32]; uint pwLen = 0; uint sLen = 0; if(password != null) { pwLen = (uint)password.Length; } else { throw new Exception("Password cannot be null"); } if (salt != null) { sLen = (uint)salt.Length; } uint status; // BCRYPT_ALG_HANDLE_HMAC_FLAG = 0x00000008 if ((status = BCryptOpenAlgorithmProvider(out phAlgorithm, "SHA256", null, 8)) == 0) { status = BCryptDeriveKeyPBKDF2(phAlgorithm, password, pwLen, salt, sLen, iterations, retVal, (uint)retVal.Length, 0); BCryptCloseAlgorithmProvider(phAlgorithm, 0); } return retVal; } /** * Utility function to calculate SHA256 from the given data using HMAC flag. Don't ask.. */ public static byte[] getSHA256withHMACFlag(byte[] data) { IntPtr phAlgorithm = IntPtr.Zero; IntPtr phHash = IntPtr.Zero; byte[] retVal = null; byte[] hash = new byte[0x20]; uint status; // BCRYPT_ALG_HANDLE_HMAC_FLAG = 0x00000008 if ((status = BCryptOpenAlgorithmProvider(out phAlgorithm, "SHA256", null, 8)) == 0) { if ((status = BCryptCreateHash(phAlgorithm, out phHash, null, 0, null, 0, 0)) == 0) { if ((status = BCryptHashData(phHash, data, (uint)data.Length, 0)) == 0) { if ((status = BCryptFinishHash(phHash, hash, 0x20, 0)) == 0) { retVal = hash; } } BCryptDestroyHash(phHash); } BCryptCloseAlgorithmProvider(phAlgorithm, 0); } return retVal; } /** * Utility function for converting keys to different formats */ public static byte[] convertKey(byte[] key, string sourceType = "RSAPRIVATEBLOB", string targetType = "CAPIPRIVATEBLOB") { IntPtr hProv = new IntPtr(); IntPtr hKey = new IntPtr(); byte[] retVal = null; int status = 0; if((status = NCryptOpenStorageProvider(ref hProv, "Microsoft Software Key Storage Provider",0)) == 0) { if((status = NCryptImportKey(hProv, IntPtr.Zero, sourceType, IntPtr.Zero, ref hKey, key,key.Length, 0x00000400 /*NCRYPT_DO_NOT_FINALIZE_FLAG*/)) == 0) { // Export policy: // NCRYPT_ALLOW_EXPORT_FLAG = 0x00000001 // NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG = 0x00000002 byte[] policy = { 0x03, 0x00, 0x00, 0x00 }; if ((status = NCryptSetProperty(hKey,"Export Policy",policy,4,0)) == 0) { if ((status = NCryptFinalizeKey(hKey,0)) == 0) { uint blobSize = 0; if ((status = NCryptExportKey(hKey, IntPtr.Zero, targetType, IntPtr.Zero, null, blobSize, ref blobSize, 0)) == 0) { byte[] blob = new byte[blobSize]; if ((status = NCryptExportKey(hKey, IntPtr.Zero, targetType, IntPtr.Zero, blob, blobSize, ref blobSize, 0)) == 0) { retVal = blob; } } } } NCryptFreeObject(hKey); } NCryptFreeObject(hProv); } if (status != 0) { //Console.WriteLine(string.Format("Error: 0x{0}", status.ToString("x8"))); throw new ExternalException( string.Format("Error: 0x{0}", status.ToString("x8")),status); } return retVal; } /** * Utility function for calling ProofOfPossessionCookieInfoManager COM method based on work by Lee Christensen * https://github.com/leechristensen/RequestAADRefreshToken */ [Guid("CDAECE56-4EDF-43DF-B113-88E4556FA1BB")] [ComImport] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] private interface IProofOfPossessionCookieInfoManager { int GetCookieInfoForUri( [MarshalAs(UnmanagedType.LPWStr)] string Uri, out uint cookieInfoCount, out IntPtr output ); } [Guid("A9927F85-A304-4390-8B23-A75F1C668600")] [ComImport] private class WindowsTokenProvider { } [StructLayout(LayoutKind.Sequential)] private struct UnsafeProofOfPossessionCookieInfo { public readonly IntPtr NameStr; public readonly IntPtr DataStr; public readonly uint Flags; public readonly IntPtr P3PHeaderStr; } public static List<PSObject> getCookieInfoForUri(string uri) { var provider = (IProofOfPossessionCookieInfoManager)new WindowsTokenProvider(); uint count = 0; var ptr = IntPtr.Zero; provider.GetCookieInfoForUri(uri, out count, out ptr); List<PSObject> retVal = new List<PSObject>(); var offset = ptr; for (int i = 0; i < count; i++) { var info = (UnsafeProofOfPossessionCookieInfo)Marshal.PtrToStructure(offset, typeof(UnsafeProofOfPossessionCookieInfo)); Hashtable properties = new Hashtable(); properties.Add("name", Marshal.PtrToStringUni(info.NameStr)); properties.Add("data", Marshal.PtrToStringUni(info.DataStr)); properties.Add("flags", info.Flags); properties.Add("p3pheader", Marshal.PtrToStringUni(info.P3PHeaderStr)); retVal.Add(new PSObject(properties)); Marshal.FreeCoTaskMem(info.NameStr); Marshal.FreeCoTaskMem(info.DataStr); Marshal.FreeCoTaskMem(info.P3PHeaderStr); offset = (IntPtr)(offset.ToInt64() + Marshal.SizeOf(typeof(UnsafeProofOfPossessionCookieInfo))); } Marshal.FreeCoTaskMem(ptr); return retVal; } /** * Utility function for getting Wire Server ip address for WindowsAzureGuestAgent using DHCP */ public static System.Net.IPAddress getWireServerIpAddress(string adapterName, uint optionId = 245U) { uint num = 1024U; System.Net.IPAddress result = null; for (; ; ) { IntPtr intPtr = Marshal.AllocHGlobal((int)num); try { DHCPCAPI_PARAMS_ARRAY sendParams = default(DHCPCAPI_PARAMS_ARRAY); sendParams.nParams = 0U; sendParams.Params = IntPtr.Zero; DHCPCAPI_PARAMS dhcpcapi_PARAMS = new DHCPCAPI_PARAMS { Flags = 0U, OptionId = optionId, IsVendor = false, Data = IntPtr.Zero, nBytesData = 0U }; IntPtr intPtr2 = Marshal.AllocHGlobal(Marshal.SizeOf(dhcpcapi_PARAMS)); try { Marshal.StructureToPtr(dhcpcapi_PARAMS, intPtr2, false); DHCPCAPI_PARAMS_ARRAY recdParams = default(DHCPCAPI_PARAMS_ARRAY); recdParams.nParams = 1U; recdParams.Params = intPtr2; int retVal = DhcpRequestParams(DhcpRequestFlags.DHCPCAPI_REQUEST_SYNCHRONOUS, IntPtr.Zero, adapterName, IntPtr.Zero, sendParams, recdParams, intPtr, ref num, "WindowsAzureGuestAgent"); if ((long)retVal == 124L) { num *= 2U; continue; } if (retVal==0) { dhcpcapi_PARAMS = (DHCPCAPI_PARAMS)Marshal.PtrToStructure(intPtr2, typeof(DHCPCAPI_PARAMS)); if (dhcpcapi_PARAMS.Data != IntPtr.Zero) { byte[] array = new byte[dhcpcapi_PARAMS.nBytesData]; Marshal.Copy(dhcpcapi_PARAMS.Data, array, 0, (int)dhcpcapi_PARAMS.nBytesData); if (array.Length == 4) { result = new System.Net.IPAddress(array); } } } } finally { Marshal.FreeHGlobal(intPtr2); } } finally { Marshal.FreeHGlobal(intPtr); } break; } // Clean up DhcpCApiCleanup(); return result; } /** * Utility functions for getting PRT using LSAS CloudAP based on work of Yuya Chudo from Secureworks * https://github.com/secureworks/BAADTokenBroker/blob/main/BAADTokenBroker.ps1 */ const string pbLabel = "AzureAD-SecureConversation"; const int STARTF_USESHOWWINDOW = 0x00000001; const int SW_HIDE = 0x00000000; const uint EXTENDED_STARTUPINFO_PRESENT = 0x00080000; const int PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES = 0x00020009; const uint TOKEN_DUPLICATE = 0x0002; const int SecurityImpersonation = 2; private static IntPtr hImpProc = IntPtr.Zero; private static IntPtr hImpToken = IntPtr.Zero; private static IntPtr hImpDupToken = IntPtr.Zero; private const int STATUS_SUCCESS = 0; private const int CALLPKG_GENERIC = 2; private static readonly Guid AadGlobalIdProviderGuid = new Guid( 0xB16898C6, 0xA148, 0x4967, 0x91, 0x71, 0x64, 0xD7, 0x55, 0xDA, 0x85, 0x20 ); [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct STARTUPINFOEX { public STARTUPINFO StartupInfo; public IntPtr lpAttributeList; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct STARTUPINFO { public Int32 cb; public string lpReserved; public string lpDesktop; public string lpTitle; public Int32 dwX; public Int32 dwY; public Int32 dwXSize; public Int32 dwYSize; public Int32 dwXCountChars; public Int32 dwYCountChars; public Int32 dwFillAttribute; public Int32 dwFlags; public Int16 wShowWindow; public Int16 cbReserved2; public IntPtr lpReserved2; public IntPtr hStdInput; public IntPtr hStdOutput; public IntPtr hStdError; } [StructLayout(LayoutKind.Sequential)] private struct PROCESS_INFORMATION { public IntPtr hProcess; public IntPtr hThread; public int dwProcessId; public int dwThreadId; } [StructLayout(LayoutKind.Sequential)] private struct SECURITY_ATTRIBUTES { public int nLength; public IntPtr lpSecurityDescriptor; public int bInheritHandle; } [StructLayout(LayoutKind.Sequential)] private struct SECURITY_CAPABILITIES { public IntPtr AppContainerSid; public IntPtr Capabilities; public uint CapabilityCount; public uint Reserved; } [StructLayout(LayoutKind.Sequential)] private struct LSA_STRING { public ushort Length; public ushort MaximumLength; public IntPtr Buffer; } [StructLayout(LayoutKind.Sequential)] private struct CAP_PKG_INPUT { public uint ulMessageType; public Guid ProviderGuid; public uint ulInputSize; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] public byte[] abInput; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct NGC_IDP_ACCOUNT_INFO { public string idpDomain; public string tenantid; public IntPtr val3; }; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct NGC_KEY_INFO { public IntPtr idpDomain; public string tenantid; public IntPtr userId; public IntPtr sid; public IntPtr keyName; }; [DllImport("kernel32.dll")] private static extern bool CreateProcess( string lpApplicationName, string lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, [In] ref STARTUPINFOEX lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation ); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool UpdateProcThreadAttribute( IntPtr lpAttributeList, uint dwFlags, IntPtr Attribute, ref SECURITY_CAPABILITIES securityCapabilities, IntPtr cbSize, IntPtr lpPreviousValue, IntPtr lpReturnSize ); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool InitializeProcThreadAttributeList(IntPtr lpAttributeList, int dwAttributeCount, int dwFlags, ref IntPtr lpSize); [DllImport("KERNEL32.dll", SetLastError = true)] private static extern void DeleteProcThreadAttributeList(IntPtr lpAttributeList); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool CloseHandle(IntPtr hObject); [DllImport("advapi32.dll", SetLastError = true)] private static extern bool ConvertStringSidToSid(string StringSid, out IntPtr ptrSid); [DllImport("advapi32.dll", SetLastError = true)] private static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, out IntPtr TokenHandle); [DllImport("advapi32.dll")] private extern static bool DuplicateToken(IntPtr ExistingTokenHandle, int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle); [DllImport("advapi32.dll", SetLastError = true)] private static extern bool ImpersonateLoggedOnUser(IntPtr hToken); [DllImport("secur32.dll", SetLastError = true)] private static extern int LsaConnectUntrusted(out IntPtr LsaHandle); [DllImport("secur32.dll", SetLastError = true)] private static extern int LsaLookupAuthenticationPackage(IntPtr LsaHandle, ref LSA_STRING PackageName, out uint AuthenticationPackage); [DllImport("secur32.dll", SetLastError = true)] private static extern int LsaCallAuthenticationPackage(IntPtr LsaHandle, uint AuthenticationPackage, IntPtr ProtocolSubmitBuffer, int SubmitBufferLength, out IntPtr ProtocolReturnBuffer, out int ReturnBufferLength, out int ProtocolStatus); [DllImport("SECUR32.dll", SetLastError = true)] private static extern int LsaFreeReturnBuffer(IntPtr Buffer); [DllImport("kernel32.dll")] private static extern void RtlZeroMemory(IntPtr dst, UIntPtr length); [DllImport("advapi32.dll", SetLastError = true)] private static extern bool RevertToSelf(); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool TerminateProcess(IntPtr hProcess, uint uExitCode); [DllImport("cryptngc.dll")] private static extern int NgcImportSymmetricPopKey(ref NGC_IDP_ACCOUNT_INFO accountInfo, IntPtr arg2, IntPtr arg3, IntPtr sessionKey, uint cbSessionKey, out IntPtr pbKey, out uint cbKey); [DllImport("cryptngc.dll")] private static extern int NgcSignWithSymmetricPopKey(IntPtr pbKey, uint cbKey, string pbLabel, uint cbLabel, IntPtr pbContext, uint cbContext, string pbData, uint cbData, out IntPtr ppbOutput, out uint pcbOutput); [DllImport("cryptngc.dll")] private static extern int NgcDecryptWithSymmetricPopKey(IntPtr pbKey, uint cbKey, string pbLabel, uint cbLabel, IntPtr pbContext, uint cbContext, IntPtr pbIv, uint cbIv, IntPtr pbData, uint cbData, out IntPtr ppbOutput, out uint pcbOutput); [DllImport("cryptngc.dll")] private static extern int NgcEncryptWithSymmetricPopKey(IntPtr pbKey, uint cbKey, string pbLabel, uint cbLabel, IntPtr pbContext, uint cbContext, IntPtr pbIv, uint cbIv, string pbData, uint cbData, out IntPtr ppbOutput, out uint pcbOutput); [DllImport("cryptngc.dll")] private static extern int NgcGetUserIdKeyPublicKey(byte[] keyName, out IntPtr ppbOutput, out uint pcbOutput); [DllImport("cryptngc.dll")] private static extern int NgcSignWithUserIdKey(byte[] keyName, string pbData, uint cbData, uint Val, out IntPtr ppbOutput, out uint pcbOutput); [DllImport("cryptngc.dll", CharSet = CharSet.Unicode)] private static extern int NgcEnumUserIdKeys(string idpDomain, string tenantDomain, string userId, string userSid, out IntPtr pbOutput, out uint pcbOutput); private static bool Impersonate() { bool success = false; IntPtr appContainerSid; if (ConvertStringSidToSid("S-1-15-2-1910091885-1573563583-1104941280-2418270861-3411158377-2822700936-2990310272", out appContainerSid)) { var sInfoEx = new STARTUPINFOEX(); sInfoEx.StartupInfo = new STARTUPINFO(); sInfoEx.StartupInfo.cb = Marshal.SizeOf(sInfoEx); sInfoEx.StartupInfo.dwFlags = STARTF_USESHOWWINDOW; sInfoEx.StartupInfo.wShowWindow = SW_HIDE; var lpSize = IntPtr.Zero; InitializeProcThreadAttributeList(IntPtr.Zero, 1, 0, ref lpSize); sInfoEx.lpAttributeList = Marshal.AllocHGlobal(lpSize); if (InitializeProcThreadAttributeList(sInfoEx.lpAttributeList, 1, 0, ref lpSize)) { var securityCapablities = new SECURITY_CAPABILITIES(); securityCapablities.AppContainerSid = appContainerSid; if (UpdateProcThreadAttribute( sInfoEx.lpAttributeList, 0, (IntPtr)PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES, ref securityCapablities, (IntPtr)Marshal.SizeOf(securityCapablities), IntPtr.Zero, IntPtr.Zero)) { var pInfo = new PROCESS_INFORMATION(); var pSec = new SECURITY_ATTRIBUTES(); var tSec = new SECURITY_ATTRIBUTES(); pSec.nLength = Marshal.SizeOf(pSec); tSec.nLength = Marshal.SizeOf(tSec); if (CreateProcess("C:\\Windows\\system32\\Notepad.exe", "", ref pSec, ref tSec, false, EXTENDED_STARTUPINFO_PRESENT, IntPtr.Zero, "C:\\", ref sInfoEx, out pInfo)) { hImpProc = pInfo.hProcess; if (OpenProcessToken(hImpProc, TOKEN_DUPLICATE, out hImpToken)) { if (DuplicateToken(hImpToken, SecurityImpersonation, ref hImpDupToken)) { success = ImpersonateLoggedOnUser(hImpDupToken); } } } } DeleteProcThreadAttributeList(sInfoEx.lpAttributeList); Marshal.FreeHGlobal(sInfoEx.lpAttributeList); } } Console.WriteLine("ImpersonateLoggedOnUser: {0}",success); return success; } private static void Revert() { RevertToSelf(); if (hImpDupToken != IntPtr.Zero) { CloseHandle(hImpDupToken); } if (hImpToken != IntPtr.Zero) { CloseHandle(hImpToken); } if (hImpProc != IntPtr.Zero) { TerminateProcess(hImpProc, 0); } return; } private static IntPtr GetLsaHandle() { IntPtr hLsa; int status = LsaConnectUntrusted(out hLsa); if (status != STATUS_SUCCESS) { return IntPtr.Zero; } return hLsa; } private static uint GetCloudApPackageId(IntPtr hLsa) { string szCloudAPName = "CloudAP"; LSA_STRING cloudApPackageName = new LSA_STRING { Length = (ushort)(szCloudAPName.Length), MaximumLength = (ushort)((szCloudAPName.Length + 1)), Buffer = Marshal.StringToHGlobalAnsi(szCloudAPName) }; uint cloudApPackageId; int status = LsaLookupAuthenticationPackage(hLsa, ref cloudApPackageName, out cloudApPackageId); Marshal.FreeHGlobal(cloudApPackageName.Buffer); if (status != STATUS_SUCCESS) { string strError = status.ToString("x"); Console.WriteLine("GetCloudApPackageId Error: 0x{0}", strError); return 0; } return cloudApPackageId; } private static string CallCloudAP(IntPtr hLsa, uint cloudApPackageId, string payload) { CAP_PKG_INPUT capPkgInput = new CAP_PKG_INPUT(); capPkgInput.ulMessageType = CALLPKG_GENERIC; capPkgInput.ProviderGuid = AadGlobalIdProviderGuid; capPkgInput.ulInputSize = (uint)payload.Length; IntPtr capPkgInputPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CAP_PKG_INPUT))); Marshal.StructureToPtr(capPkgInput, capPkgInputPtr, false); byte[] capPkgInputBytes = new byte[Marshal.SizeOf(typeof(CAP_PKG_INPUT))]; Marshal.Copy(capPkgInputPtr, capPkgInputBytes, 0, Marshal.SizeOf(typeof(CAP_PKG_INPUT))); Marshal.FreeHGlobal(capPkgInputPtr); int cbCloudApRequest = Marshal.SizeOf(typeof(CAP_PKG_INPUT)) + 1 + payload.Length; IntPtr cloudApRequestBuf = Marshal.AllocHGlobal(cbCloudApRequest); RtlZeroMemory(cloudApRequestBuf, (UIntPtr)cbCloudApRequest); Marshal.Copy(capPkgInputBytes, 0, cloudApRequestBuf, Marshal.SizeOf(typeof(CAP_PKG_INPUT))); byte[] requestJsonBuffer = System.Text.Encoding.ASCII.GetBytes(payload); Marshal.Copy(requestJsonBuffer, 0, cloudApRequestBuf + 4 + 16 + 4, payload.Length); int cbCloudApResponse; IntPtr pResponseBuffer; int subStatus; int status = LsaCallAuthenticationPackage( hLsa, cloudApPackageId, cloudApRequestBuf, cbCloudApRequest, out pResponseBuffer, out cbCloudApResponse, out subStatus ); Marshal.FreeHGlobal(cloudApRequestBuf); string response = ""; if (status == STATUS_SUCCESS) { if (pResponseBuffer != IntPtr.Zero) { byte[] cloudApResponseBytes = new byte[cbCloudApResponse]; Marshal.Copy(pResponseBuffer, cloudApResponseBytes, 0, cbCloudApResponse); LsaFreeReturnBuffer(pResponseBuffer); response = Encoding.UTF8.GetString(cloudApResponseBytes, 0, cloudApResponseBytes.Length); } } else { string strError = status.ToString("x"); Console.WriteLine("Error: 0x{0}", strError); Console.WriteLine("Payload: {0}", payload); } return response; } private static string SendToCloudAp(string payload) { string response = ""; IntPtr hLsa = GetLsaHandle(); if (hLsa != IntPtr.Zero) { uint cloudApPackageId = GetCloudApPackageId(hLsa); if (cloudApPackageId != 0 && Impersonate()) { response = CallCloudAP(hLsa, cloudApPackageId, payload); Revert(); } } return response; } public static string RequestSSOCookie(string nonce) { string payload = string.Format("{{\"call\": 2, \"payload\":\"https://login.microsoftonline.com/common/oauth2/authorize?sso_nonce={0}\", \"correlationId\":\"00000000-0000-0000-0000-000000000000\"}}", nonce); return SendToCloudAp(payload); } } } "@ Add-Type -TypeDefinition $source -Language CSharp -Verbose |