• selinux与kernel 0day


    selinux与kernel 0day

    kernel NULL pointer的利用需要把shellcode映射到内存0处, 大家在测试exp的时候,总能发现一个规律, 开着selinux就能溢出成功, 关闭就不能溢出成功了。 看了下内核源码,终于搞清楚了: mmap在做匿名映射的时候,会经过LSM层来做安全验证, LSM初始化的时候,会将selinux作为它的第一验证模块, capablity作为它的第2验证模块。这2个模块在做mmap映射的时候,都指向了dummy_file_mmap_addr这个函数:
    usr/src/debug/kernel-2.6.18/linux-2.6.18.i686/security/dummy.c:

    static int dummy_file_mmap_addr (struct file *file, unsigned long reqprot,
    unsigned long prot,
    unsigned long flags,
    unsigned long addr,
    unsigned long addr_only)
    {
    if ((addr < mmap_min_addr) && !capable(CAP_SYS_RAWIO))
    return -EACCES;
    return 0;
    }
    mmap_min_addr代表了用户能映射的最小内存地址, 它在/proc/sys/vm/mmap_min_addr进行设置。这里还要对当前进程的CAP_SYS_RAWIO能力做个判断, 就是说如果进程有这个能力的话, 不管mmap_min_addr的值是多大,都可以满足用户的需求, 当然就可以映射0地址了。 那么这跟selinux有什么关系呢?  进程在被执行的时候,尤其是调用了execve这个函数, 进程的权能是需要重新来计算的,在selinux开启的时候, selinux是LSM的第一验证模块, 看下它是怎么计算进程在被execve后的权能的:
    void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
    {
    /* Derived from fs/exec.c:compute_creds. */
    kernel_cap_t new_permitted, working;

    new_permitted = cap_intersect (bprm->cap_permitted, cap_bset);
    working = cap_intersect (bprm->cap_inheritable,
    current->cap_inheritable);
    new_permitted = cap_combine (new_permitted, working);

    if (bprm->e_uid != current->uid || bprm->e_gid != current->gid ||
    !cap_issubset (new_permitted, current->cap_permitted)) {
    current->mm->dumpable = suid_dumpable;

    if (unsafe & ~LSM_UNSAFE_PTRACE_CAP) {
    if (!capable(CAP_SETUID)) {
    bprm->e_uid = current->uid;
    bprm->e_gid = current->gid;
    }
    if (!capable (CAP_SETPCAP)) {
    new_permitted = cap_intersect (new_permitted,
    current->cap_permitted);
    }
    }
    }

    current->suid = current->euid = current->fsuid = bprm->e_uid;
    current->sgid = current->egid = current->fsgid = bprm->e_gid;

    /* For init, we want to retain the capabilities set
    * in the init_task struct. Thus we skip the usual
    * capability rules */
    if (current->pid != 1) {
    current->cap_permitted = new_permitted;
    current->cap_effective =
    cap_intersect (new_permitted, bprm->cap_effective);
    }

    /* AUD: Audit candidate if current->cap_effective is set */

    current->keep_capabilities = 0;
    }
    我们看到如果当前进程不是init进程的话, 权能还是会被继承下来的。

    在selinux关闭的时候, capabiliy模块成为了LSM的第一验证模块, 看下它是怎么计算的:
    static void dummy_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
    {
    if (bprm->e_uid != current->uid || bprm->e_gid != current->gid) {
    current->mm->dumpable = suid_dumpable;

    if ((unsafe & ~LSM_UNSAFE_PTRACE_CAP) && !capable(CAP_SETUID)) {
    bprm->e_uid = current->uid;
    bprm->e_gid = current->gid;
    }
    }

    current->suid = current->euid = current->fsuid = bprm->e_uid;
    current->sgid = current->egid = current->fsgid = bprm->e_gid;

    dummy_capget(current, &current->cap_effective, &current->cap_inheritable, &current->cap_permitted);
    }

    static int dummy_capget (struct task_struct *target, kernel_cap_t * effective,
    kernel_cap_t * inheritable, kernel_cap_t * permitted)
    {
    *effective = *inheritable = *permitted = 0;
    if (!issecure(SECURE_NOROOT)) {
    if (target->euid == 0) {
    *permitted |= (~0 & ~CAP_FS_MASK);
    *effective |= (~0 & ~CAP_TO_MASK(CAP_SETPCAP) & ~CAP_FS_MASK);
    }
    if (target->fsuid == 0) {
    *permitted |= CAP_FS_MASK;
    *effective |= CAP_FS_MASK;
    }
    }
    return 0;
    }
    注意看这行:
    *effective = *inheritable = *permitted = 0;
    selinux将当前进程的权能全部清0了, 所以excve后的普通进程是没有任何权能的。 也就没有了CAP_SYS_RAWIO权能,也就不能映射0内存了。 所以想阻止NULL pointer kernel 0day的攻击,最好把selinux关掉,或升级到最新的内核版本。 同时把mmap_min_addr的值设为大于4096。
  • 相关阅读:
    工具类官网Web原型制作分享-Adobe
    还在为黑白网页设计犯难?12款设计帮你轻松解决!!!
    联系我们吧
    单调栈&&单调队列
    *模板--数据结构
    非递归线段树专题
    反素数
    线段树专题训练
    BST
    排列与组合
  • 原文地址:https://www.cnblogs.com/bittorrent/p/3274672.html
Copyright © 2020-2023  润新知