Exploit-DB #40931
Description: Apple macOS 10.12 16A323 XNU Kernel / iOS 10.1.1 - 'set_dp_control_port' Lack of Locking Use-After-Free
Type: local
Platform: multiple
Date: 2016-12-16
Author: Google Security Research

Exploit:
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=965

set_dp_control_port is a MIG method on the host_priv_port so this bug is a root->kernel escalation.

  kern_return_t
  set_dp_control_port(
    host_priv_t host_priv,
    ipc_port_t  control_port) 
  {
          if (host_priv == HOST_PRIV_NULL)
                  return (KERN_INVALID_HOST);

    if (IP_VALID(dynamic_pager_control_port))
      ipc_port_release_send(dynamic_pager_control_port);

    dynamic_pager_control_port = control_port;
    return KERN_SUCCESS;
  }

This should be an atomic operation; there's no locking so two threads can race to see the same value for
dynamic_pager_control_port and release two references when the kernel only holds one.

This PoC triggers the bug such that the first thread frees the port and the second uses it; a
more sensible approach towards exploiting it would be to use this race to try to decrement the reference count
of a port with two references to zero such that you end up with a dangling port pointer.

Tested on MacOS 10.12 16A323
 
##############################################################################

/* ianbeer */

READ THIS FIRST:
if you do not have an iPod touch 6g running 10.1.1 (14b100) or and iPad mini 2 running 10.1.1 (14b100) this project will
not work out of the box(*)! You need to fix up a couple of offsets - see the section futher down
"Adding support for more devices"

(*) more precisely, I only have those devices and have only tested it on them.
(*) 1b4150 will probably also work, I haven't tested it.

Contents:
 1 - Build Instructions
 2 - Adding support for other devices
 3 - Notes on the bugs and exploits

*** (1) Build Instructions ***

 * download and install Xcode 8.1 or higher

 * download Jonathan Levin’s collection of arm64 iOS binaries:
    + Follow the link for "The 64-bit tgz pack" here:
      http://newosxbook.com/tools/iOSBinaries.html (you want iosbinpack64.tgz)
    + extract it into the iosbinpack64 directory which is already in the mach_portal
      source dir so that directly underneath iosbinpack64 you have the bin/, etc/, sbin/, usr/ directories
      When you expand the iosbinpack64 directory in the xcode folder view you should see those folders

 * open this .xcodeproj

 * if you don't have an apple id make one now at https://appleid.apple.com

 * if you don't have a developer signing certificate you can make a free one now in Xcode

 * in Xcode go Xcode->Preference->Accounts and click the '+' in the lower left hand corner and add your apple id

 * select your account then "View Details" and under signing identites click Create next to iOS Development

 * connect your iDevice and click "trust" in the pop up on it

 * wait for xcode to process symbol files for this device

 * in the box to the right of the play and stop buttons in the top left corner of the xcode window select your iDevice

 * in the left hand window pane select the mach_portal project and navigate to the General tab

 * in the signing window select your personal team

 * We now need to fix up a few things:

 * go to Build Settings -> Packaging and give your project a new, unique bundle identifier
    (eg change it from "com.example.mach_portal" to "com.ios.test.account.mach_portal"
     where ios.test.account is your apple id. (it doesn’t have to be your apple id, just a unique string))

 * We also need to register a unique App Group:

 * In the capabilities view scroll down to the App Groups section, remove the existing App Group ("group.mach_portal")
   and add a new unique one (eg "group.ios.test.account.mach_portal")

 * open jailbreak.c and change the app_group variable to this new app group id.

 * on the iDevice go to settings -> General -> Device Management and select your apple ID and click trust

 * in xcode click view -> debug area -> activate console so you can see debugging output (there's no output on the iDevice screen at all, that's normal)

 * make sure your iDevice and host are connected to the same wifi network and that network allows client to client connections. Note down the iDevice's ip address.

 * click play to run the app on the iDevice. If it fails press and hold the power and home buttons to reset the device. If Xcode asks you to enable developer mode on this mac agree.

 * if it succeeds you should see:
    "shell listening on port 4141"
   printed to the debug consol

 * the kernel exploit is only around 50% reliable (this can certainly be improved, read the code and make it better!)
     it will fail more often if there is high system load - try leaving the device for a minute after rebooting it and connecting it to you mac before trying again

 * connect to that port with netcat:
     nc X.X.X.X 4141
   where X.X.X.X is your iDevice’s ip address

 * you have a root shell :) There’s no controlling terminal so fancy curses gui stuff won't work unless you fix that

 * you can run any pseudo-signed thin ARM64 binaries - if you want the kernel task port it's host special port 4

 * copy your custom testing tools to the iosbinpack64 directory and they'll be bundled with the .app so you can run them from the shell

 * you're running as an unsandboxed root user so you can talk to any iokit user clients/mach services

 * amfid is patched to allow any signatures/entitlements

 * When you’re done hold power and home to reset the device

*** (2) Adding support for other devices ***
 * you have to do this manually, sorry!

 * download the ipsw for your device from https://www.theiphonewiki.com/wiki/Firmware
   The bugs are there in any version <= 10.1.1 but the further back you go the more offsets
   will be wrong so ideally stick to 10.1.1 (and for anything earlier that iOS 10 the kernel cache
   is encrypted so you'll have to do the rest yourself)

 * for >= iOS 10 unzip the ipsw and hexdump the kernel.release.* file