
we have any introduction to mac OS kernel exploitation by jeff ball so my name is jeff ball I'm gonna talk a little bit of about Mac OS kernel exploitation as he just mentioned first off who am i I'm a researcher at grim I'm also a member of the DEF CON group of Orange County and my handle is Jeff ball at 55 on Twitter if you want to look me up later so first we're gonna talk a little bit about why we will care about trying to exploit the Mac OS kernel first reason is obviously that it controls all of the authorization checks and prevents any type of system modifications that you might want to do
and so if you can exploit the kernel then you can obviously bypass these and so that's the the most obvious reason why you would want to the second reason is that a lot of software is started sandboxing itself so for instance fari will sandbox any of the more complicated processing and it's one way you can break out of sandbox is because oftentimes when you're inside the sandbox you can still talk to the kernel and so you can exploit the kernel you can easily just by pious and get out of the sandbox without having to go through and try and exploit the other half of the unseen box process and so it's just oftentimes seen as the easier of the two
approaches to just exploit the kernel and get out that way rather than trying to go the other way and so those are kind of the two of the more main ones the second one being a more recent concern next I'm just going to talk a little bit about an introduction to the xnu kernel which is the Mac OS kernel so the ex-new kernel is actually a combination of two kernels there's the MA calf and the BSD half mock was an early research project out of Carnegie Mellon it is actually a microkernel and so what that is is it tries to only have the components that are necessary to be running inside of ring three as compared
to a monolithic one like the other half over the bsd half and so what that means is it will do simple things like message passing memory management's scheduling but the rest is run as applications inside of userland and so if my application wants to send a network packet I don't actually talk to the kernel to send that Network packet I pass a message to the networking application which then sends the network packet out as compared to within traditional monolithic kernels like Linux or Windows I just talked to the kernel directly and that code that does the network parsing and network sending of packets is inside of the kernel and so it can be seen to be a much more
secure approach because if you were to exploit the networking application you only gain access to that application and not the entire OS so Mac OS is actually a combination of that and the monolithic kernel of BSD so the bsd half provides things like the disk i/o and networking i/o management of processes whereas the mach half does things like memory management inter process communication messages and managing of tasks and threads one other thing to note is the X and U kernel is open source Apple puts it up on open source Apple comm and they also have a github that lags slightly behind their website you can go and get it compile it and make changes and
install it yourself on your macbook they don't always have the latest version up so they will put up the new versions of the kernel open sourced slightly after so for instance right now the latest version that's open source is ten thirteen six and they're on to 1014 for Mojave so a little bit about the maca that's important for to know for exploitation is mock is heavily based on passages and so if you want to talk to a service you pass a message to it and those are called mock messages on the other hand and when you pass a message you pass it to a processes or a tasks mock port which is basically just a
endpoint for you to receive a one directional mock message the ports themselves have access restrictions which are known as port rights in mock terminology and those being send send once and receive CIN is obvious you can send if you have the send right on a port you can send a mock message to it receive is also obvious if you have the receive right you are the receiver for that mock port you get all messages from that are sent to that port and then send once means you're allowed to send a mock message to a port once that's often used for callback functionality so if I have the received port and someone sends me a message and
they want me to be able to talk back they'll give me a send once right to one of their own ports and so through that mechanism I can then use that send right or send once right to send a message back the other thing that's important to note is that these mock port rights can be passed through mock messages so you can send it to another process or another process can send it to you and that's actually how you get the port rights for other services these mock ports and mock messages are how a large portion of the services and kernel API is accessed from user land so for instance if I want to draw something on
the screen I will get a port right to the windows server which is the process on Mac OS that does all of the drawing and I will send a mock message requesting that it draw something on the screen and then it did an addition to the processes like windows the windows service the kernel actually has a number of ports as well that it listens on that you can send messages to as well see on the next slide one other thing that's useful to know especially when talking about exploiting through the use of mock ports and messages is task port task port Tsar like other ports except as the name implies they focus on managing a
task and so this allows if you have the task port to a task or prop process the one side note the processes are the BSD term and tasks are the mock term they are correlated in that each process has a corresponding task but I'm going to basically use them interchangeably but anyway if you have the task port for a task it lets you do things like create a thread fork it terminate and very usefully read and write the memory of that task that's useful for the debugger and so things like ll DB and gdb will use task force to debug other processes we'll see a little bit later how they're useful for exploitation the next component that I'm
going to talk about is i/o kit IO kit is kind of another portion of the kernel that is the device driver framework it allows you to create device drivers without having to code the whole thing yourself it's a C++ wrapper that allows you to just extend off of base classes most related to your driver and so there's a number of classes that you can inherit off of that will have most of the functionality you'll need with you just needing to implement the specific components related to your device when you code a device driver and i/o kit one of the things that you can do is you register that driver with the i/o registry through that the user LAN
components that want to talk to your driver they will look it up via the i/o registry and create an i/o user client which is just the i/o frameworks class for talking to that driver and then you can define functions in the driver that the user land can call with their own values and so if you want to provide a way for users a user land process to talk to your driver in order to make it work you just register it with the i/o registry the user name process creates an i/o user client and then it just calls the functions in your driver that you've defined for that purpose one of the internally this is all based off of
mock messages the i/o kit framework and use your land when you say please call this driver method or please give me a user client before this driver will talk to the i/o kit nasty report which is a mock port and it will say please call this method on behalf of this user client one thing you can do is you can sorry screen size changed you can look and see what what drive I awoke it drivers are available via the i/o edge command and so in this you can see that I have the VirtualBox driver at the bottom that's installed and if I want to talk to it I would make a VirtualBox USB user client and then I would be able to call
the various functions that the VirtualBox driver has oh shoot sorry let me get out of that yeah that's good he told me now cuz oh wow this change size on me well alright there's the VMware one cuz I also have that installed but so if I wanted to I could talk to that kernel extension by making a VMware USB port USB client and then calling the functions that that driver has set up for to me to call so that's just one of the areas of text if this is all of these drivers here it's very hard to see at this huge screen size but it's actually a hierarchy with drivers having multiple different classes anywho anyway so moving on they
just talked a little bit about the attack surface that's available if you're trying to go after the X and you colonel obviously like most OS is it's got sis calls there's the BSD half which has over 500 sis calls and that Apple keeps changing them with each kernel update and so they will introduce new functionality which means new bugs as well as some of the old ones also have the still bugs and they continue to find bugs in the large number of sis calls that BSD provides and then additionally because the X new kernel is split in half there's also the mock half which has their traps which is just another terminology for how they talk about sis
calls those also have had bugs in recent years Ian beers found one and wrote a jailbreak using it just I think last year additionally like Linux there's device files and those device files have iocked dolls and so that is another part place where user values and user data can be parsed which may lead to bugs networking protocols also have taken user input and so just a week and a half ago or so there was the ICMP error vulnerability which the networking code inside of the bsd half for ice P error messages incorrectly read trusted a.length inside of the packet which led to a heap overflow which can lead to memory corrupt or which will lead to memory corruption and can
possibly be exploited so that code while it has been there for a while is still having bugs as simple as not checking a header length so that it could also be another area and then one of the areas that I'm gonna talk a little bit more about today and the vulnerability we'll focus on is inside of an i/o kit driver device drivers are notorious for having bugs because they aren't as widely used or as looked at as the rest of the kernel and they also parse user data and so if a device driver author forgets to check a value that might lead to a vulnerability and we'll see how that I actually can and how that vulnerability
can be exploited in a little bit next I'm going to talk a little bit about some of the methods of debugging or testing while you're trying to write an exploit and so what can you do to try and help yourself out to make things a little bit easier so the first thing i said or i already mentioned is that xnu is open source and you can compile and install it and make changes to it it's a little bit of a process there's oftentimes slight changes to the build system that their build mechanisms that you'll need to make in order to get it compiled but there are some handy guides online you can find oftentimes you'll
have to make small Corrections to the source code such as just commenting out or casting a field that that a compiler option would cause a warning that will make the build not work so one of the things you can do while you're debugging things is just add print statements and look at D message it can be a little bit of a process to recompile it and reinstall it every time but it is a very simple way to try and see what's going on in the kernel the kernel also does have some code to not print out pointers so you'll have to get rid of that as well if you try and print out pointers which bug things overall it's not the
most effective way but it's very simple the next one is if you manage to crash the kernel you can see an output of from the panic log and so if you want to know what happened you can look at that example again which will probably be miss formatted ah so it's not that bad but anyway it looks a little bit like this if you crash the kernel you can see it will dump all of the registers and then give you a stack trace as well and so if you're trying to figure out what exactly happened you can come see and think oh this values in are the RX register I thought it would be this value so it's again not the most
helpful but it is somewhat useful after that you've crashed it and you're trying to figure out what happened what went wrong with my exploit in the stack trace you can see in this one I was overriding the stack with this nonsense value so it failed to walk its full way back up the stack so you can see the frame pointer is just three three three so again another useful useful thing you can do while debugging but not the most useful z print z print is a heap specific tool it prints out the heap allocations from the zone allocator it will tell you how many of each zone is allocated and you can use that while heaps praying or trying to
look at when memory allocations are made it's very useful if you're trying to exploit a heap based vulnerability so this right sorry
such a small to see yes alright in this it's just Z print printing out the kalloch which is one of the main allocators in the kernel it's printing out the number of elements in each zone so for instance if we have a vulnerability that affects a specific zone such as the 256 one we can take a look at the number of allocations in that and we can whenever we're trying to do something like heap flood this will tell us when new ones are being made or when they're being released and we kind of contract the progress of what's going on with the Cal yeah in the calc 256 zone this is kind of a specific tool
that's really only useful if you're trying to exploit a heap based vulnerability the next tool which is very useful for a lot of different situations is 1 by Sigma it's called iOS carney tools it's also available for mac OS so it's useful for this as well and what that does is it shows you the kernel memory map and then it also allows you to read and write kernel memory and so if you're trying to figure out what happened or what's at a specific address and the kernel memory you can use these tools one downside is it does require you to already have roots so obviously you can't use it in an exploit it also requires you to have
already exported a kernel task port to userland and I'll get into what that means and in a little bit when we look at our exploit the other thing that you can do instead of already having it a curl test board is you can recompile your kernel and patch it to allow for this I haven't in the repository then I'm going to push with this talk I have instructions on how to do that now just let's take a quick look at it all right good so in this kernel I have already like I said it requires root and so as you can probably would have been able to see with better formatting this is the kernel memory map it shows you what is
that each dress and so for instance on this one it shows you that there is a kernel extension with 16 K of memory read/write permissions and so you can just basically see where everything is in the kernels memory and so if you're trying to figure out what is that a specific location or where it is in memory you can use these tools one of the other ones it's also useful it's called kmm that stands for kernel memory and as you can probably guess from the name it allows you to read and write memory and so what I'm asking it there is to print out 40 bytes at that address and so that'll just show us that that string is
at that address in the kernel memory we can also use this tool to write to kernel memory if we want to try out a payload or a post exploitation mechanism without actually having to re exploit it the kernel each time so you can use these tools for that purpose as well they're very useful and I highly recommend them and then the last tool which is probably the most useful but also the most the most work to set up and is also a little buggy is just the kernel debugging you can set up the debugger for the kernel and then step through it or set breakpoints and read memory or if it crashes it'll come back
to you and you can see what happened one thing you do have to do is run that and if you change the env Rams to include that command however you can't do that while sip is on so it requires you to reboot into system recovery or turn off system integrity protection yourself so one thing that to note is that Apple all is in addition to making the source they make the kernel debug symbols available for the official Apple o kernels so if you want to debug an official kernel you can just go download the symbols with an Apple Developer account and install them and then use that in the debunker so just to show that off a little bit
simply start the debugger then you just tell it to load the kernel debugger symbols yeah I compiled the kernel that that VM is running and so I have the symbols there then you can load up that command the KDP remote command with the IP address of the VM or the other computer that you're debugging this does work over the network and then you hit the magic key combination to tell the debugger to start up in the kernel this for Apple is control option command shift escape so right now that VM is frozen and if we go back to the debugger and try and connect to it you'll see that it loads it up and we've now
stopped at that address inside of the debugger and so what you can do is you can set breakpoints or read and write memory or registers and then continue the I just hit enter hit can type continue and hit enter and the the OS will start up and until it hits a break point where you crash the kernel you won't be given context back to it so this is useful that you could set breakpoints on your op gadgets or at the vulnerability and read the registers and memory and see what all is happening and where things are going wrong or how you can adjust things accordingly this is um just a super useful but it it also is a
little buggy often times it just crashes or you don't your breakpoints might not be hit so it's does have its faults but it's very useful
next I'm going to talk a little bit about some of the mitigations for criminal exploits that are present in the xnu kernel so the first one is kernel address space layout randomization the Mac OS kernel is actually loaded at any one of 256 different spots in memory they randomly pick a slide value and then that gets added to the load address of the kernel and so each each load address is two mega bar and two megabytes apart and so there's 512 there 510 different megabytes that it could be changed so essentially if you're trying to exploit and you try to hard code in address that will only work one out of 256 times and so it's not a very useful thing you need
to find a way to leak that address and calculate it for development purposes there's the caste info which stands for kernel address space info assist call that you can call and that will actually just give you back the kernel slide and so it's very useful to start out with using the caste info syscall until you've worked up your exploit to be able to leak that address one thing to notice that does of course require root because they don't want to just have a Kor bypass and it only works with system integrity protection disabled or a compiled kernel to remove that and on the left you can just see we can see that the kernel on the first with a slot
of 0 is loaded at that base address which is the default one and then with a slide of dthe with six zeros it gets loaded at D with six zeros higher than the the zero slide it's not a very complicated randomization and it's also rather weak as we'll see the next mitigation that Mac OS has is supervisor mode execution protection so what that does is the kernel will refuse to run in run in user land memory and so if you try to tell it to jump to a use to code inside the user land the processor will actually throw an exception and when that happens the kernel and your ex point won't work prior to
this you could just if you were overriding a function pointer you could just override the function pointer with the hard-coded address that you put code at a New Zealand and the kernel would jump to it you could run a little snippet of code that would do whatever your desired effect was and then you could just clean up and it would that would be as complicated as it got now now we can't do that anymore and we have to find some other way to run code that's not from user land pages the next mitigation is supervisor mode access protection or SMAP it's another Intel processor feature that is only recent so only the late later 2016 and anon models of
MacBooks have them essentially it's very similar to the exploit protection except it is for reading and writing memory from user land so the kernel will refuse to read or write memory directly from user then obviously this can't be on all the time so the Mac OS kernel just selectively turns it on and off when it it's meant to and so if you're not in using one of the specific functions to copy data from you use your land the snap will be the snap protection will be on if you are inside one of those specific functions that will be off and so what this does is if the vulnerability allows us to dereference an arbiter arbitrary address or read
something from an arbitrary address we can't host our that data inside of a user Lane process we need to get it into the kernel and memory somehow and so this is just another one of those protections that makes our job as an exploit writer harder and then the final mitigation we'll talk about is not really an exploit mitigation more of just a defense against a successful exploit well some other non kernel means and so it's system integrity protection also known as rootless when it was first introduced the name is actually kind of a misnomer which is why they changed it there's still a root account it's just less powerful system integrity protection prevents you from as the root user doing
certain actions so if I want to write to the bin directory to change some process or debug some one of Apple's processes system integrity protection won't let me and so even as the root user would where I was I'm supposed to have ultimate authority to do whatever I want on Mac OS I can't whereas on something like Linux the root user is all-powerful and can do that this is implemented through Mac OS is mandatory access control framework which is based off of trusted BSD which is essentially just a large number of kernel hooks scattered throughout the kernel that whenever an actions such as creating a file or opening a socket are happens the kernel will call one of
those hooks for the installed policies and that function hook will decide is this user allowed to write to this file or open the socket and so on we can just take a quick look at that and so this is sorry it's gonna keep getting me yeah so this is the struct inside the kernel that has all of the function pointers and so for instance we have the check file oh it's down there the file check function pointer when I go to create a file the kernel will iterate over each of the policies and check if that function pointers define and it will call that function if for each policy and the system integrity protection is
just one of the policies that are in them and we'll see how we can neuter this by knocking out those function pointers later on just a little demo of system integrity protection actually first I have to change snapshots
so that previous one was after the exploit so that I could show the i/os Kearney kills
all right so the CSR util is a simple utility which lets you turn on and off system integrity protection obviously can only run recovery mode or if the SIP is already turned off and you can use the status command to just check and so we can see that it is enabled and so if I yeah I'm the root user right now but if I try to write to the bin directory I'm not allowed so it just tells me operation not permitted because sips Paul C function for create files was called and it said oh you're trying to write to the bin directory I'm not going to allow it because that would be a system modification and sips purpose is
to not allow that so that is a system integrity protection we'll see how to turn that off in a second so next we're gonna I'm going to show off the specific vulnerability and then we'll talk through how you go about creating an exploit for it the vulnerability that I chose for this case study is that CV up there which is a vulnerability in the AV bridge dry i/o kit driver it was originally found by Alex Plaskett the URL for that is down there when you go to pull up the slides this is a IO kit func driver function you can call it from kernel with a user control value and so what it is is this user control
value is passed into the command gates array it has an index off it and then it calls a C++ function of one of the objects in that array however the array is not checked to make sure that it is within the bounds of the array just a little visualization of that we have our AV bridge object up there and there's a command gates array which has four objects in it it's only for value long however they don't check the index so we can fill in any value and it will go to whatever that addresses in memory and try and read out a pointer to a C++ IO command gate object and then it will read the feed table out pointer from
that command object and then do you reference it if you're not familiar with C++ V tables they're essentially just arrays of function pointers for a class and so what this is doing is when I say zero for that index it called it goes to the zeroth item it reads the pointer out goes to the V table pointer reads it out again which goes to right here it adds an offset to it and in this case it's trying to call the run action function which is 1c 8 down from the top of the V table it will read that pointer and then it jumps to it and so however if we give it a much larger index it will try and
read something from memory up here which clearly one point at one of these I'll command gates and things will go wrong if I can't read if that isn't a valid pointer it'll crash if it is it will try and use that as if it were an i/o command gate and try and read a V table pointer out and so we'll look at how we can kind of fake that out and cause it to jump to our code so now I'm just gonna talk a couple about a couple techniques that we'll look at and for bypassing some the mitigations as well as exporting the first one is one of the important things to do is spray the
memory because we don't know where that object is in memory specifically because of the ksl our slide well will need to spray the memory and so we'll have to what that we do with that is we allocate a large number of blocks and we fill those blocks with our fake object pointers and then when the kernel at we give it an index larger than that it will reach around past the top of the memory back into our userland memory and somewhere within the spray what we'll do is we'll actually spray two gigabytes of memory so that that 512 megabyte slide that it could possibly have is just miniscule in comparison and it will always land within our two gigabytes
spread one thing to note about when you're doing this in userland you don't actually need to 'allah gate allocate the two gigabytes of memory you can just use duplicated memory mappings to all it to set up that memory with your spray without actually adding more because you the memory is copy on right it's only allocated when you change it you can make as many of those as you want and you can actually allocate more in your spray than memory then you have in your laptop so for instance this MacBook has 16 gigabytes of memory but using duplicated memory mappings I was able to spray 32 gigabytes of memory or however much I want because it's not
actually allocated and so as you can see I'm left without the spray if we use a hard-coded index it'll point if the slide is 0 it might actually point to our user memory if it's not then it might not point to our user land remember whereas if we just have a too good good bite spray it will always hit somewhere in our usual our user only in memory how we'll use that just looks a little bit like this what we'll do is we will spray fake vtable pointers which are essentially these pointers oh right here sorry the pointers right here well spray a bunch of fake vtable pointers as if that was the the i/o command gate
objects then we'll use a hard-coded index it will wrap the memory will wrap back around back to right here and then these will all point to our payload pointer which would be essentially a normal point at run action but will instead point to our payload and so and that's how we'll get code execution one of the things to note is if we were to try that it wouldn't work because of smack if your computer is new enough and you have snap that when you try and point it into usually in memory it'll actually just crash because of the processor exception so instead what you can do is you can spray the kernel with that memory and so and then point it into the
kernel instead there's a number of i/o kit classes which you can allocate via various api's with the kernel in kernel memory one of the more useful ones is called OS OS string which is just simply just an i/o kit string object they're very useful because you can set that all of the content you can create them or delete them or read them back whenever you want and you can make them of arbitrary size and so what you can do is you can create many large string objects in it and it will actually allocate that in memory and once you've filled up the available free slots they will all be allocated in a row and so that lets you all okay
use a hard-coded memory address because it's such a large amount of memory and so for this macbook i was actually able to spray two gigabytes of memory and find that the address ffff nine to five eight with followed by six zeros is always allocated and always set to my content if i've sprayed to your bytes of memory so we can use that to point things there and when we need to bypass man the specific laptop does not so we don't have to bypass that this laptop actually does have snap though so we will have to bypass that and the way that's done is simply through return oriented programming or Rob like you would in a normal user land exploitation
as well what that does essentially just you set the stack to value that you control and then you will set one address you want to run any values it uses and then the read instruction will read that address and execute this little code snippets that you can then combine to do something in this example on the right we have a gadget that's pop RDI ret and so what that will do is it will pop this RDI value into the RDI register off the stack and then the ret will load the next gadget which is a pop RSI which will do the same with the RSI value and through that means you can set the registers and then if you put a
function address on there it will call that function as x86 is fast call or takes the arguments via that registers that will call a function with our arguments that we want and so through that we can run our little bits of code without actually having to get that code loaded up into kernel memory in in an executable memory region one of the other things to note is the function thread exception return which is very useful function when doing Rob what that function does is it will just stop the kernel context and return to user land wherever you are and so how that's useful is such that if you don't safely end your wrap chain the
current we'll crash and when it crashes you obviously the OS goes down and you can't use anything that you just did in your rock chain and so you need to safely exit your rock chain or return it back to the normal context and there's two ways of doing that one there's the complicated way of getting back onto the correct stack frame with the creative values on it in order to continue execution the other way which is much easier is just to call the function thread exception return a normal user land exploitation this doesn't really matter as much because you can just let your process crash and after you've achieved whatever you were trying to in
kernel land that would cause the OS to crash and so you just throwing that function on there it will terminate your Rob chain how we'll use that is simply we'll just rather than pointing the payload buffer into our payload will point it up into a kernel Rob gadget the first drop gadget is our stack pivot and so what that does in this in this vulnerability re X points into content week control and so what we'll do is we'll push the first gadget pushes our X onto the stack and then pops it into the stack pointer so what that does is it just allows us to set the stack to our content and lets us set up those gadgets
on the stack that we'll run after that we just set up our Rob chain to call whatever functions we want so specifically we want that those Rob gadgets to make us become route and so this little snippet of code we will run in Rob gadgets that will grab the current process struct out of kernel memory it will take the credentials out of that and then the POSIX credentials which is just an inner wrapper inside of the credential structs and we'll assign 0 or the ID for route to the saved user ID pointer and so that little snippet of code essentially makes our process have root privileges we'll just use the set UID to take the saved you ID pointer and
make it the effective one again and then we've become route because we've modified the structure that holds what user we are in kernel memory
after we've become Rupe the next thing we're gonna want to do is get a kernel task port exported to user land I mentioned that was what you needed in order to use the iOS Kern utils to read and write kernel memory this is actually how it's accomplished the kernel is a task just like any other it's task is given pit 0 it's the first task obviously and because it's a task you can use the normal read and write mock API in order to read and write kernel memory if you have the kernel task board so the VM read and VM write functions they can be used to just read it like you would any other process with that
kernel task board and so what we'll do is we'll have our rock chain grab that kernel task port and shove it into the real hosts array the real hosts array is a functionality in the the mac OS kernel which holds a number of ports that you can query from user land and obtain and so if you want to grab a port to a service like the auto mount daemon tour the audit daemon you can ask the kernel to retrieve one of those for you and give it to you so that you can talk to those various statements however there are some empty slots in there and we'll just use our rock chain to copy the
pointer to the kernel task to one of those empty slots and then whenever our any user land process wants to have to modify criminal memory or recur memory they can ask the kernel for that specific port out of the real hosts array and then use that to call the VM read in vm write functions that's actually become one of the more standard techniques and so a lot of tools such as the iOS Kern utils will try and retrieve that port to grab the kernel task board and then they can use that to read and write memory so then one of the the next thing we'll want to do now that we have the ability to read and write memory but
we don't have to use complicated Rob to do it we can just ask for the task port and call the normal function Alice's will want to neuter system integrity protection or just turn it off and so that's actually rather trivial once you obtained kernel memory read/write ability and so there's a symbol called Mac policy list which lists all of the policies that are currently enforced for the for Mac OS and so we'll just read that area of memory out of the kernel and updated so all those function pointers we saw where are now zero we can just take a look at what that let's take a look at what that how that's done the macros here K read and K right just
to read from kernel memory yeah maybe that's better so at the top you can see we're reading out the Mac policy list and then we go down here to the for loop where we iterate over each entry in that list we'll read the list out of memory if it's not null or that slot is an empty will then read the specific policy out and the function pointers that make up that policy and then we'll just change them all to be null and so then next time the kernel goes to call one of these functions that function pointer will be null and the kernel will think hey there that policy doesn't define it it doesn't care about
that specific action and so it's the one that as I showed before in the file check create that function is called when we create a file but if that pointer is now null it won't actually be called and so if we do that to the system integrity and then down here we write it out if we do that to the system integrity protection policy that'll essentially turn it off so we've written it back to kernel memory with all those modified function pointers and it's essentially neutered
so now just to show off the exploit that we've been building
so once again we can't we can't modify it even though we're route let's go over here to where we're not route we'll run our exploit and we get a root shell essentially what happened to us we sprayed our memory set up the rock gadgets so that the spray memory points into the pointer to our rock gadgets well we triggered the vulnerability with a hard-coded index which caused it to wrap around past the end of memory back into our sprayed memory then it would call it D references that D references again to the pointer to our op gadgets runs each of them then we call that thread exception return function which returns back to user land after it our
wrap chain is copied the kernel task pointer into that real host array we use the set UID to become root after our wrap chain fixed our credentials to be zero and then we called the API to get that kernel task pointer back and we used it to modify the system integrity protections function hooks so that they're all zero and then we just launch a root shell and now you can see I'm root and if I want to change the bin directory I can just however I want although those function pointers are no longer called so I'm essentially allowed to do whatever I want without system integrity protection stopping me
so and that's kind of conclusion let's hope that was helpful if you go to try and exploit the Mac OS kernel I'll be pushing all the materials for this talk to that URL later today and that's my contact info if you have any questions afterwards there's any questions now I can take them or we can go to lunch yes
it's real hard to because essentially all those tools are going to run at the kernel level and you are also running at the kernel level after you've successfully exploited them what one of the more effective things that can be done about this is sandboxing and so I mentioned how kernel exploits are kind of a way around the sandbox but in some cases you're not actually allowed to call various api's to the kernel and so that actually can be a way to lower the attack surface if you want to stop these it's really more useful to stop the to not expose that attack surface than it is to try and catch it after they're running their own code at kernel level
since if you're running at the same protection levels what that Apple actually does with iOS is they have higher levels of it with the secure element and so the secure element is one level above the kernel and so it can actually look down and try and catch various things and so that doesn't really exist on Mac OS which is why it's kind of an easier target
so that specifically does not in fact if I go back there you can actually see it still it it actually still thinks system integrity protections enabled because all I did was neuter it however the CSR utils will now actually work to disable it or are changing the way you disable is by changing the NVRAM and i and i nuked the function pointers that prevented you from changing nvram so now I can turn it off if I wanted to but these this specific exploit doesn't do that because I was just trying to show off how you can change kernel memory but now you're outside of sip and once you're outside of sip you can make any changes you want to the nvram it's
essentially the way you turn it off and without an exploit is you boot up into recovery mode where sip isn't enabled except now sip is just not enabled because of my exploit
Oh