CVE-2021-22555 linux内核提权 - 安全客,安全资讯平台

robots

 

该漏洞作者Andy Nguyen (theflow@) ,writeup已经公开。

简单概述

主要是在xt_compat_target_from_user()中有溢出,经过特殊构造产生uaf,

具体exp中,使用了struct msg_msg作为溢出,导致两个指针指向同一个chunk,使用套接字简化了uaf的使用流程,最后利用pipe()管道中的struct pipe_buf_operations 来泄露地址,以及伪造修改关闭pipes时调用的release 函数地址调用rop链,完成权限提升以及返回用户空间

 

修补方案

在查询源代码过程中发现某些版本的代码中选择将xt_compat_target_from_user()的漏洞触发代码删除(简单明了)

 

漏洞具体分析

在兼容模式下,即存在#define CONFIG_COMPAT条件下

套接字 IPT_SO_SET_REPLACE 或者IP6T_SO_SET_REPLACE被调用,

xt_compat_target_from_user()memset()参数target->targetsize没有检查偏移,导致可能出现字节越界。

#ifdef CONFIG_COMPAT
int xt_compat_target_offset(struct xt_target *target)
{
    u_int16_t csize = target->compatsize ? : target->targetsize;
    return XT_ALIGN(target->targetsize) - COMPAT_XT_ALIGN(csize);
}
EXPORT_SYMBOL_GPL(xt_compat_target_offset);

void xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr, int *size)
{                    //t 表示用户或者内核的target_size target_name
                    //
    struct xt_target *target = t->u.kernel.target;//内核target 对应struct xt_target 即target基本类型
    struct compat_xt_entry_target *ct = (struct compat_xt_entry_target *)t; //xt = t的副本
    int pad, off = xt_compat_target_offset(target);
    u_int16_t tsize = ct->u.user.target_size;

    t = *dstptr;
    memcpy(t, ct, sizeof(*ct));//将ct覆盖到dst
    //当内核偏移与用户态偏移不同时使用
    if (target->compat_from_user)
        target->compat_from_user(t->data, ct->data);
    else
        memcpy(t->data, ct->data, tsize - sizeof(*ct));
    pad = XT_ALIGN(target->targetsize) - target->targetsize;
    //漏洞触发点
    if (pad > 0)
        memset(t->data + target->targetsize, 0, pad);//末位补0,控制target->targetsize偏大,可以造成\x00溢出
    //这里有越界 off by null 设置偏移
    tsize += off;
    t->u.user.target_size = tsize;

    *size += off;
    *dstptr += tsize;
}

target->targetsize不由用户控制,可以通过选择不同大小的target类型结构体来控制targetsize大小。

 

如何触发漏洞?

漏洞成因 在xt_compat_target_from_user()memset()参数target->targetsize 溢出导致

memset(t->data + target->targetsize, 0, pad);

原本目的应该是将未满足的偏移填充0。targetsize不被用户直接控制,可以通过选择不同的target类型,但是targetsize不能是8位偏移整齐,满足pad>0,

构造数据data,通过控制pad。控制溢出数量。

exp利用时,选择创建data数据,date数据长度为0x1012。这样刚好覆盖到接下来申请0x1000大小堆块的对应结构体的指针后2bit,造成指针的指向错误。

 

具体实现 uaf

由于在内核中无法直接申请固定大小堆块,exp选择使用创建msg_msg结构体,

msgsend()内部使用alloc_msg(),

alloc_msg将一定长度的msg利用kmalloc多次分配每一段msg开头都有msg_msg结构体

/* one msg_msg structure for each message */
struct msg_msg {
    struct list_head m_list;/*链表头*/
    long m_type; /*类型*/
    size_t m_ts;        /* message text size */
    struct msg_msgseg *next;
    void *security;
    /* the actual message follows immediately */
};
//把id取出来
struct list_head {
    struct list_head *next, *prev;
};

struct msg_msgseg {
    struct msg_msgseg *next;
    /* the next part of the message follows immediately */
};

msgget()首先创建4096个消息队列,对每一个队列先发送msg_primary,大小为0x1000,再对每一队列发送msg_secondary,大小为0x400,这样对于每一个队列中都有两条消息,分别对应0x1000 和0x400大小的chunk,并且分别对每一个msg进行标号,使msg内部存有对应msg标号,struct msg_msg位于整个chunk的头部,

以上是基础chunk的构造

通过读取msg,将对应chunk释放,由于释放的是0x1000大小,使用触发漏洞,将下一个堆块msg_msgstruct list_head的后两位溢出为0,如果正确运行,成功将一个primary_msg对应的secondary_msg指向不属于它本身队列的secondary _msg,此时就会有一个secondary_msg同时被两个指针指向,由此造成uaf。

为继续利用,我们需要找到哪两个primary_msg指针指向了同一个secondary_msg.由于在发送msg时提前将标号放入msg的内容中,可以使用msgrcv()获取secondary_msg ,这时的获取通过primary_msgstruct msg_msg->m_list获取,被修改的msg会指向id与消息队列id不同的secondary_msg,这时可以通过当前消息队列的id与secondary_msg的id获取具体哪两个指针指向同一个msg

 

SMAP

smap阻止内核直接访问用户空间的内容,这使泄露内核的地址会更复杂。

先将被双重指针指向的地址free掉,创建一个fakemsg内容如下:

build_msg_msg((void *)secondary_buf, 0x41414141, 0x42424242,
                PAGE_SIZE - MSG_MSG_SIZE, 0);

采用套接字将fakemsg放到可以被uaf的地方,

int spray_skbuff(int ss[NUM_SOCKETS][2], const void *buf, size_t size) {
  for (int i = 0; i < NUM_SOCKETS; i++) {
    for (int j = 0; j < NUM_SKBUFFS; j++) {
      if (write(ss[i][0], buf, size) < 0) {
        perror("[-] write");
        return -1;
      }
    }
  }
  return 0;
}
//原理 ss是由 socketpair制造一对相互连接的套接字

改变了fakemasg的m_ts位置,即扩大了读取范围,可以通过指针获取到

msg = (struct msg_msg *)&msg_fake.mtext[SECONDARY_SIZE - MSG_MSG_SIZE];
  //获取相邻msg

fakechunk的相邻的chunk信息,通过该chunk找到 对应primary地址,以此构造一个合法的msg ,将他free掉。此时ss[i][1]产生的指针指向该地址。

这些对于msg的操作是为了更简便地uaf攻击。

 

攻击内核路径。

计算内核地址,采用pipe()对应结构体,通过调用pipe()可以分配到pipe_buffer

创建pipe

struct pipe_buffer {
    struct page *page;
    unsigned int offset, len;
    const struct pipe_buf_operations *ops;
    unsigned int flags;
    unsigned long private;
};

其中有const struct pipe_buf_operations *ops;

struct pipe_buf_operations {
    int (*confirm)(struct pipe_inode_info *, struct pipe_buffer *);
    void (*release)(struct pipe_inode_info *, struct pipe_buffer *);
    bool (*try_steal)(struct pipe_inode_info *, struct pipe_buffer *);
    bool (*get)(struct pipe_inode_info *, struct pipe_buffer *);
};

一旦有pipe被写入struct pipe_buffer就会被写入内容,由于其中 ops会定位到.data段。泄露该地址,由于偏移固定,很容易可以计算出内核基地址。

 

创建攻击内核的rop链

通过uaf覆盖修改pipe。将对应release函数的地址伪造成rop链。

rop链需要完成更改creds(身份信息),commit_creds(prepare_kernel_cred(NULL))并且返回命名空间 switch_task_namespaces(find_task_by_vpid(1), init_nsproxy)

由此提权

 

调用rop链

上面提到已经计算出内核基址,因此创建一个fakepipebuffer,伪造ops,更改ops中realese的指向为对应rop的起始地址。在关闭pipe时调用到realese。实际劫持流程执行提权rop。

最后启动shell 为root权限。

 

实验演示

docker本地搭建

内核小白,如果理解上有偏差,请指正

本文来源于: https://www.anquanke.com/post/id/247830

相关推荐

Shellcoding: Process Injection with Assembly

Conor Richard home.. Shellcoding: Process Injection with Assembly July 2021 Introduction It has been a long time since m

Cobalt Strike and Tradecraft | hausec

It’s been known that some built-in commands in Cobalt Strike are major op-sec no-no’s, but why are they bad? The goal of

Pre-Auth RCE in ManageEngine OPManager · Haxolot.com

Vulnerability Summary ManageEngine OpManager is a popular Java-based network monitoring solution used by large companies

macOS TCC.db Internals by keith | Rainforest Engineering

macOS TCC.db Internals Keith Johnson, Tuesday February 9, 2021 A deep dive into what the TCC database contains and the m

A guide to non-conventional WAF/IDS evasion techniques – 0xFFFF@blog:~$

This is a tutorial detailing various non-conventional methods of circumventing signature based WAF or IDS software. Rath

加密固件之依据老固件进行解密

作者:OneShell@知道创宇404实验室 时间:2021年7月27日 IoT漏洞分析最为重要的环节之一就是获取固件以及固件中的文件系统。固件获取的方式也五花八门,硬核派有直接将flash拆下来到编程器读取,通过硬件调试器UART/SPI

如何使用FalconEye实时检测Windows进程注入行为 - FreeBuf网络安全行业门户

关于FalconEye FalconEye是一款功能强大的Windows终端安全检测工具,可以帮助广大研究人员实时检测Windows进程注入行为。FalconEye也是一个内核模式驱动工具,旨在实现实时的进程注入行为。由于FalconEye

梨子带你刷burpsuite靶场系列之服务器端漏洞篇 - 服务端请求伪造(SSRF)专题 - 安全客,安全资讯平台

robots 本系列介绍 PortSwigger是信息安全从业者必备工具burpsuite的发行商,作为网络空间安全的领导者,他们为信息安全初学者提供了一个在线的网络安全学院(也称练兵场),在讲解相关漏洞的同时还配套了相关的在线靶场供初学者

Tomcat渗透测试方法总结 - FreeBuf网络安全行业门户

前言 Tomcat服务器是一个免费的开放源代码的web应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP程序的首选。可以这样认为,当在一台机器上配置好 Apache服务器,可利用它响应

滴滴之后,Uber陷入数据安全风波 - FreeBuf网络安全行业门户

滴滴之后,Uber再度陷入数据安全风波。 网安的舆论漩涡的中心依旧是数据安全,这一点从近期种种合规行动中可见一斑。其中,出行行业由于其涉及庞大的用户数据、地图数据,成为数据安全的又一焦点聚集地。 回到今天的主主角,Uber。由于一件数据泄露

议题征集 | 「成都网络安全大会」金融分论坛,等你show - FreeBuf网络安全行业门户

2021 CCS成都网络安全大会(以下简称:CCS大会)将于8月26日至27日在成都举办。此次大会由成都市互联网信息办公室、成都高新区管委会联合主办,成都无糖信息技术有限公司承办;斗象科技与无糖信息达成战略合作,承办CSS大会的金融安全分论