Page 1 of 1

Using restricted entitlements on Sierra

PostPosted: Sun Jan 22, 2017 5:55 pm
by Siguza
As of Sierra, AMFI seems to kill binaries with "restricted entitlements" (such as task_for_pid) that don't have a valid signature.

I have tried to disable AMFI via boot-args (SIP is disabled), as:
Code: Select all
sudo nvram boot-args='cs_enforcement_disable=0x1 amfi_allow_any_signature=0x1 amfi_get_out_of_my_way=0x1'
but to no avail. systemctl kern.bootargs shows exactly the values I set, and e.g. cs_debug=0x1 works just fine, but for some reason AMFI can't be tamed (I guess it was just designed that way).

Short of deleting AMFI.kext, is there any way I can run self-signed binaries with restricted entitlements?

Re: Using restricted entitlements on Sierra

PostPosted: Tue Jan 24, 2017 7:31 pm
by b3ntx
PE_i_can_has_debugger is checked before those boot-args are acted upon.

If you're just looking to use task_for_pid on sierra with as little protections disabled as possible (i.e. as close to a "stock" install as you can get), then I think
Code: Select all
csrutil enable --without debug

may be the closest you can get and still allow task_for_pid.

If you're interested in any other restricted entitlements then you will have to compile the kernel yourself or patch it such that PE_i_can_has_debugger returns true.

Re: Using restricted entitlements on Sierra

PostPosted: Thu Mar 02, 2017 9:55 pm
by Siguza
I found a way now, which requires no (permanent) changes to the kernel.

There's actually a SIP flag/bit that makes PE_i_can_has_debugger return true: CSR_ALLOW_KERNEL_DEBUGGER, aka 0x08 (not to be confused with CSR_ALLOW_TASK_FOR_PID aka. 0x04, which can be allowed with "csrutil enable --without debug").
Problem is it can't be enabled with csrutil, and you cannot change any nvram variable that starts with "csr-" by the law of Sandbox.kext. With CSR_ALLOW_TASK_FOR_PID, you can, however, get the kernel task port (!!!) via the processor_set APIs as per J's PoC. :P
With that you can NULL-out the mac_iokit_check_nvram_* hooks of Sandbox's MACF policy, after which you can finally run:
Code: Select all
nvram csr-active-config='%ff%00%00%00'
After a reboot, the MACF patches are gone, but you now got the CSR_ALLOW_KERNEL_DEBUGGER flag, which means AMFI will once again listen to boot-args given to it. :P

I'll be releasing an update to kern-utils that makes them work on OS X, as soon as I've sorted out my current issues with iOS 10. :)

Re: Using restricted entitlements on Sierra

PostPosted: Fri Jun 30, 2017 3:26 pm
by pvieito
Hi, I' trying to disable amfid in macOS Sierra, could you share how you do the NULLing-out of the mac_iokit_check_nvram_* hooks? I'm a bit lost here. I previously tried to patch the amfid process to allow restricted Entitlements but is a bit cumbersome:

Re: Using restricted entitlements on Sierra

PostPosted: Sat Jul 01, 2017 2:41 am
by Siguza
  1. Disable SIP if you haven't already.
  2. Grab kern-utils from here and compile them for macOS (instructions in README).
  3. Find out the mac_policy_list offset:
    Code: Select all
    bash$ nm /System/Library/Kernels/kernel | egrep 'mac_policy_list$'
    ffffff8000b29780 S _mac_policy_list
    bash$ jtool -l /System/Library/Kernels/kernel | head -1
    LC 00: LC_SEGMENT_64          Mem: 0xffffff8000200000-0xffffff8000a00000   __TEXT
    => offset is 0x929780
  4. Get your kernel base:
    Code: Select all
    bash$ sudo kinfo -b
  5. Add them together and read the pointer from kernel memory:
    Code: Select all
    bash$ sudo kmem 0xffffff8017cc3bd0 0x20
    [*] Reading 32 bytes from 0xffffff8017cc3bd0
    04 00 00 00 00 02 00 00  03 00 00 00 04 00 00 00  |................|
    01 00 00 00 04 00 00 00  00 D0 4E 36 80 FF FF FF  |..........N6....|
    The corresponding C structs are:
    Code: Select all
    struct mac_policy_list {
        u_int numloaded;
        u_int max;
        u_int maxindex;
        u_int staticmax;
        u_int chunks;
        u_int freehint;
        struct mac_policy_list_element *entries;
    struct mac_policy_list_element {
        struct mac_policy_conf *mpc;
    So there are 4 loaded modules whose pointers are stored at 0xffffff80364ed000.
  6. Print the pointers:
    Code: Select all
    bash$ sudo kmem 0xffffff80364ed000 0x20
    [*] Reading 32 bytes from 0xffffff80364ed000
    10 30 00 98 7F FF FF FF  90 A4 0B 98 7F FF FF FF  |.0..............|
    E0 20 0E 98 7F FF FF FF  10 11 0F 98 7F FF FF FF  |. ..............|
  7. Find the Sandbox module (usually the 3rd):
    Code: Select all
    bash$ sudo kmem 0xffffff7f980e20e0 0x30
    [*] Reading 48 bytes from 0xffffff7f980e20e0
    FA FD 0D 98 7F FF FF FF  0C 01 0E 98 7F FF FF FF  |................|
    30 21 0E 98 7F FF FF FF  01 00 00 00 00 00 00 00  |0!..............|
    38 21 0E 98 7F FF FF FF  00 00 00 00 00 00 00 00  |8!..............|
    The corresponding C struct is:
    Code: Select all
    struct mac_policy_conf {
        const char *mpc_name;
        const char *mpc_fullname;
        char const *const *mpc_labelnames;
        unsigned int mpc_labelname_count;
        struct mac_policy_ops *mpc_ops;
        int mpc_loadtime_flags;
        int *mpc_field_off;
        int mpc_runtime_flags;
        mpc_t mpc_list;
        void *mpc_data;
    So using the first pointer you can check the name and make sure you really got the Sandbox:
    Code: Select all
    bash$ sudo kmem 0xffffff7f980dfdfa 0x8
    [*] Reading 8 bytes from 0xffffff7f980dfdfa
    53 61 6E 64 62 6F 78 00                           |Sandbox.|
  8. The mpo_iokit_check_nvram_get, mpo_iokit_check_nvram_set and mpo_iokit_check_nvram_delete hooks are the 123rd, 124th and 125th pointers in mpc_ops, so with that we can replace them with NULL pointers:
    Code: Select all
    sudo kpatch -q 0xffffff7f980e2508 0x0
    sudo kpatch -q 0xffffff7f980e2510 0x0
    sudo kpatch -q 0xffffff7f980e2518 0x0
  9. Fully disable SIP:
    Code: Select all
    sudo nvram csr-active-config='%ff%00%00%00'
  10. Disable AMFI:
    Code: Select all
    sudo nvram boot-args='amfi_get_out_of_my_way=0x1'
  11. Reboot for the changes to take effect.

Re: Using restricted entitlements on Sierra

PostPosted: Sat Jul 01, 2017 2:27 pm
by pvieito
Wow, thanks for the really detailed explanation! Unfortunately with your method I am stuck in the same point I was when I was trying by myself. When I try to access the kernel base address with kinfo I got the following:

Code: Select all
[DEBUG] Getting kernel task... [src/lib/libkern.c:65]
[DEBUG] Trying processor_set_tasks()... [src/lib/libkern.c:71]
[DEBUG] Getting default processor set name port... [src/lib/libkern.c:75]
[DEBUG] Success! [src/lib/libkern.c:77]
[DEBUG] Getting default processor set priv port... [src/lib/libkern.c:80]
[DEBUG] Success! [src/lib/libkern.c:82]
[DEBUG] Getting processor tasks... [src/lib/libkern.c:85]
[DEBUG] Got 351 tasks, looking for kernel task... [src/lib/libkern.c:95]
[DEBUG] Success, caching returned port. [src/lib/libkern.c:137]
[DEBUG] kernel_task = 0x00001403 [src/lib/libkern.c:139]
[DEBUG] Getting kernel base address... [src/lib/libkern.c:772]
[DEBUG] Getting base region address... [src/lib/libkern.c:774]
[DEBUG] Looping over kernel memory regions... [src/lib/libkern.c:216]
[DEBUG] Searching for next region at 0000000000000000... [src/lib/libkern.c:229]
[DEBUG] Failed to find base region, returning 0. [src/lib/libkern.c:786]
[!] Failed to locate kernel

It seems that processor_set_* calls works as expected but all the calls to read or modify kernel memory are blocked. I tried on my own with mach_vm_read and then using libkernel.c which is using vm_region_recurse_64 and also fails. The error returned by both vm_region_recurse_64 and mach_vm_read are Mach error 4 - (os/kern) invalid argument.

I also tried redisabling SIP, to ensure a correct bitmask:

Code: Select all
csr-active-config   w%00%00%00

Then I even tried to use kinfo from the Recovery OS with no success. I hope this is not due to a change in the kernel in macOS Sierra 10.12.5. What version were you using? The sysctl kern.secure_kernel is 0 so processor_set_tasks should be supported to access the kernel.

Re: Using restricted entitlements on Sierra

PostPosted: Sun Jul 02, 2017 2:08 am
by pvieito
Good news! As I wasn't able to use that way, I found another surprisingly easier way to do it. I used the following Swift code to compile an executable with the entitlement used by csrutil:

Code: Select all
//  main.swift
//  SystemIntegrityTool
//  Created by Pedro José Pereira Vieito on 2/7/17.
//  Copyright © 2017 Pedro José Pereira Vieito. All rights reserved.

import Foundation
import IOKit

let entry = IORegistryEntryFromPath(kIOMasterPortDefault, "IODeviceTree:/options")

guard entry != 0 else {
    print("IORegistry invalid path.")

let noRestrictions = Data(bytes: [0xFF, 0x00, 0x00, 0x00])
let result = IORegistryEntrySetCFProperty(entry, "csr-active-config" as CFString, noRestrictions as CFData)

guard result == KERN_SUCCESS else {
    print("Error setting the IORegistry property: \(result).")


Then I executed it in the Recovery OS where AMFI is luckily disabled. And with:

Code: Select all
nvram boot-args='amfi_get_out_of_my_way=0x1'

Voilà, AMFI is gone!

Re: Using restricted entitlements on Sierra

PostPosted: Sun Jul 02, 2017 1:38 pm
by Siguza
lolwut. :D
I didn't even consider running my own stuff in recovery, but... whatever works, I guess. ¯\_(ツ)_/¯

Also, I'm still on 10.12.3. I plan to update soon and then I'll have a look at what goes wrong with the kernel task there...