Uh, hi everyone. Welcome to DevCon. Uh, my name is Max Bazzelli and today my talk will be about exploit mitigation techniques on IIS. Can everybody hear me on the left and right side? Okay, cool. So... Um... Uh, so a few words about me. Uh, I'm from Kyiv, you can see me in Ukraine. I currently work as a staff security engineer at Lookout. Uh, last few years I've focused on XNU, LLVM, and Linux internals. Um, I also, uh, co-founded a fried Apple team, which main goal is to share IOS reverse engineering tools and techniques and methods. So, what I'll cover today, uh, first of all, IOS security mechanism, how the IOS security stuff works. Next, uh, quick introduction of function hooking on IOS. Uh, I will show, uh, techniques that Apple provide to you. Uh, first of all, I will show you how to mitigate, uh, exploit development and attacks on IOS 8 and 9. Uh, and I will show the real exploit that I found on IOS 9, uh, that allowed to run unsigned code. And as a final, uh, we will see how the future attacks on code signed may look like. So, what are IOS security mechanisms? So, first of all, uh, memory protections that prevent a change in, um, executable page permissions. So, executable page cannot be, uh, writable. Uh, and then, uh, I will explain the case codes, which compute in practice everything that, uh, Azure functions might trunk on all the time and, uh, as part of memory protection, we cannot allocate, uh, writable and executable regions in the same time. The code signing, which is a technique that all executable codes must be signed by a trusted party. Sandboxing, like, isolating, uh, process data from each other and don't stick nonsense to the files and APIs. Secure boot processes. All elements in the boot chain must be signed by Apple. control, data protection, which is hardware-based encryption for data at rest, and kernel page protection. So it's a new technique, debuted in iOS 9. It's a special patch guard that's live in a kernel, live in an IRM trust zone and continuously check for a kernel integrity. So most interesting for us are the first two, like memory protection and code sign-in. I will focus on them today. As I say, memory protection is a technique to prevent exploit code execution. There is no way for executable page to be writable. There is no way to allocate writable and executable regions in the same time. As a result of that, no dynamic code generation. But starting from iOS 4.3, Apple adds special entitlement that's how you'll use it for allocating JIT pages in Safari, JS, Netre, and Giant. As part of memory protection, non-executable stack and heap. And ISLR in user land and in kernel land. So let's look how they implement it. Here we see VM map enter, which will be in Xenu source code, which will be allocated we call it all the time when we allocate a new region in a virtual address map. So if region want to be writable and executable, VM map enter just disable VM product execute flag. The only one exclusion is for entry for JIT. The same stuff for changing existing regions. So if region is executable, is going to be writable, it just will disable executable bit. Again, special case for use it for JIT flag is set. The next security technique is code signing, which is based on mandatory access control framework. It is a pluggable framework that is permitting new security policies loaded, easily linked in a kernel, loaded at boot time. Loaded at run time. And it's like, it's a lot of features to implement new security policies. And code signing is one of the security policies. It's enforced that all code must be signed by a trusted party. In addition, it's all running code should match with the signed page hashes on load as well as run time before execution. A few words how the code signature format is look. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . and they have negative indexes. The last is a master hash of all the hashes, called a cdhash. And it's usually used to verify ad hoc signatures. Here is a picture of how code-sign validation a lot works in a kernel. So embedded signature got copied to a kernel space, and entire cdhash got verified. No individual page checked it yet. We spawned a new process with mac-exec-v or posix-spawn, and exec-activate-image got called in a kernel. It iterates through all the image activators, called exec-match-image-act, which handle mac files and call load mac file, parse mac file, load code signature, UBCCS-blob-add, and finally, call mac-v-node-check-signature-mfi-hook. This is how stuff works per page. So page. Each code-sign validation works per page fault. Page fault got generated on a page load, and vm-fault-enter got called. It's called vm-page-validate-cs, which map page to a kernel space. Called vm-page-validate-cs-mapped, and finally, cs-validate-page, which do the actual comparison between stored page hash and calculated page hash. More details on page validation. So page fault got generated when the page is loaded, and it's called vm-fault. There are a few states of a page, one called validated, another called tainted. So validated page means that page have a hash in code signature directory. Tainted means that calculated page hash is not equal to a stored page hash. And process with invalid code sign flags will be killed by kernel. A good question, when we need to verify a page hashes? So there is a macro, vm-fault-enter-needs-cs-validation from vm-fault. It says that page need to be validation if it's going to be writable, it's belong to a code-sign-ed object, it's been mapped to user space. So basically, it will be validated any interesting time. A few words, how the code sign enforcement works. So Apple uses special. Uh, kernel extension called MFI, Apple Mobile File Integrity, which register MFI hook, which register MACF hooks. And like, there is a huge set of hooks. Just a few example of them. Like mpo-vnode-check-exec, which set flags cs-hard and cs-kill for a process, which means its process should not allow to load invalid pages and should be killed if it becomes invalid. A big picture. How the code sign enforcement works. So here we have a process in the user land that called a syscall or a MAC trap. The corresponding sysend, uh, this person function from a sysend, you could call it, it calls output to a MAC framework, which check is there any, uh, policy modules requested to hook particular functionality. Next we call for MFI, which check for a code signature. If the code signature type is ad hoc, um, we are looking for, uh, for cdhash at, uh, kernel-trust-hash. If it's not ad hoc, we, uh, send out to mfid, which is in user land, which use lib-miss-dial-lib to validate the CMS blob. So a great question why we need all this info, right? Uh, before going to problem statement, a few words about the function hooking. So I use function hooking a lot, um, in my work for adding a new security features, such as data address encryption, uh, by hooking low-level open-close write functions. It's really useful for debugging server party code, logging and tracing API calls, even could be used for code de-obfuscation. All this time I was using an industry-known method called interposing. Uh, this is how it works. So starting from iOS 10, it's not Leopard, Apple decided to implement a special segment in a MAC of files for, uh, special for dynamic linker usage. The segment calls link edit, it, it consists of information about, um, process of linking and binding symbols during dynamic linkage. It relies on, uh, special command called dildin4, which servers table of content for link edit. And here what we can see link edit, rebasing4, which contain rebasing upcodes, binding4, upcodes required for import symbols, uh, lazy binding4, weak binding4, simple binding4 for lazy and weak, um, symbols correspondingly. Okay. And export info. There is a great article about how it works by Jonathan Levine, a website, so if you're interested, please take a look. So as I say, it use special opcodes. Here's looks like. Uh, these opcodes are used by dld stop binder function during dynamic, uh, linkage. And we can reuse this information and update, uh, bind addresses to point our functions. So basically we can intercept and hook functions. This is how interposing works. Uh, few words about dld shared cache. So what is it? Uh, starting from iOS 3.1, Apple, uh, move all the frameworks and libraries to one big file called the shared cache. It's remove all the original file from disk. And I think they use it for performance and security reasons. Uh, it's going load to each process space. It's, uh, have a, a, as a large slide, which is randomized per device reboot. Uh, previously, uh, in iOS 8, uh, Apple use, uh, special, uh, bind stops in a dld shared cache. So basically, uh, during dynamic linkage, the stop address will be updated. Um, but starting from iOS 9, they start to pre-calculate, uh, function offsets just inside the hash. So the, um, like bind stop is not using anymore. And it was, it was a big, really big problem for me. So. It's not working. Um, all the offsets are hard coded. And I saw what, what we can do with that. Cause our product heavily rely on a function hooking. So I start, maybe we can use the trampolines. As you remember there is a technique to hook a functions, which based on direct memory override. So here's an example. We want to hook the function A. Uh, we override first few instruction of function A with the jump to function B and redirect, uh, execution vector. Okay. In the case, if you want to skip a hook, we can save the original stolen instruction in, um, allocated memory, execute them first and then jump to, um, point in a function A that executed just after jump. So basically we reconstruct all function A, uh, instructions and execute it without a hook. So yeah, trampolines may work, uh, but as we remember, there are memory protections on iOS. Is it? Should not allow you to change, um, memory regions. So for write a trampoline, the region should be writable and how we can change the executable region to be writable. Well even if you can do that, how it's, how to switch it back to be executable and, uh, the main question, there is a cut sign check on, on a page load, how we can bypass it. So I start playing with, um, memory allocations and have an idea of what if we can allocate a new memory region with readable, writable permissions. Just on the same address where the executable region is. So long story short, we can use mmap with map-annon, map-private, and map-fixed-flex. Overwrite executable region with readable, writable, uh, copy original content back and yeah, we get a writable memory. Uh, how we can switch it back to be executable? Well that's easy, um, as it's our memory, it's, uh, anon memory, we can use just mprotects call for that. And sounds like a plan. We can take a function pointer, get, uh, page address when the function is located, copy original page content to some temporary buffer, mmap new writable, writable page over, uh, copy original content back, write a trampoline, switch it to be executable, and we got killed by a cut sign. So cut sign is still a problem. Is there any ways to bypass it? Uh, well, I start playing with cut sign implementation in a, in a Xenu. As you remember, page has got checked on a page fault. So I have an idea, what, what if we can prevent a page fault? Maybe we can, uh, prevent a cut sign check. I found a PI, like, mlock, so if you lock in a page, it will be not triggered for a page fault, and there is no cut sign check. Here is how full attack looks like. Uh, we get a function pointer, get page base, copy page content to a temp buffer. Uh, allocate a new writable page over the original one, copy page content back, lock in a page, write in a trampoline code, and protect the page to be executable. So it completely solved my problem with the function hooking, and even this technique was used later in public yellow jailbreak. But I want to go deeper. So I started playing with, uh, dynamic linker, uh, as you remember, dynamic linker is a part of the process. And it's responsible for mapping. It's segments in a memory, loading cut signature block from disk, and even forcing the kernel to do the actual cut sign check. It's rely on, uh, fcntl syscall for loading cut signatures. So if we can override or hook fcntl, we can prevent cut signature load from disk. The next interesting guy is xmmap. Uh, dynamic linker use it for, as a wrapper for x, xmap for mapping the segments. So idea is if we can hook xmmap and load. And lock all the executable regions during the mapping, we can prevent, uh, the cut sign check. This is basically how sysbypass was born. Uh, we hook fcntl, enter minus one to prevent cut signature loading. The next is we hook in xmmap, lock all the regions that have executable permissions, and there is just step number three, deal open unsigned code. Uh, this technique was open sourced by a guy, Luca Todesco. And it's available on the github. So you can check it. Uh, now it's demo time. So I have a few apps here, um, first checking how this exploit works. Let's start from one called unsigned code. So what we have inside unsigned code folder, um, mfile and actually make file. The mfile is just a simple program. It's dump in a log unsigned codes running in your computer, patching your byte and terminate the process. Um, so, um, here's how the make file look like. As we see, there is no cut sign step in a make file. Uh, we can build it and try to run on our non-jailbreaking device. To prove that there is no cut signs, um, on a file, I use an O tool and looking for LC code signature. As you see, it's not found. Uh, so, it should, it should dump unsigned code running on your computers. For testing that, I have an iPad mini, which is non-jailbroken, 9 to 1, which have a Csbypass loader here that use mlog exploit and, uh, continuously check for, um, shared documents folder for any macro files and execute them. So, what I'm gonna do, I'm uploading my unsigned code to shared folder. And run IDYS log to get the NS log dump. There's a bunch of logs. So, yeah. If you run Csbypass, it will, they'll open the unsigned code. Yeah. The process got terminated. We had a return zero. But we have in, uh, Cslog, um, unsigned code running your computers, fetching your bytes. The next example is more interesting. Uh, it's called the Flappy Bird. It is a game that was pulled from App Store a few years ago. I have my copy. Um, I decrypt it and remove the cut sign from a file and I'm gonna install it on, on non-jailbroken iPad. Again, to prove it's not signed, I use an O tool. And check for LC cut signature. Yep. There is no cut signature here. So the next step is upload to shared documents to a device. And, uh, that's it. Cool. And we're running Csbypass. Oh. We got a Flappy Bird game. So it's fully functional as the original one. Um, yeah. I'm not that good with Flappy Birds and we are running out of time. So I will switch to the next slide. As a final word, I want to tell how the future cut sign attacks may look like. First of all, the hide executable segment. So it is, uh, it is idea based on overlapping executable segments. So, uh, it is, uh, it is, uh, it is, uh, it is, uh, it is, uh, it is, uh, it is, uh, it is not executed. So we basically hide it from, from a kernel. This stuff is not executable. This attack was heavily used by TG and Pango jailbreaks. But it looks like starting from IS-9 Apple are really hard on it in a, in a DLD. So I haven't seen any attacks anymore. Next one is the hook DLD functions. It's the same attack that I just showed you with Csbypass. So if we can hook or, um, redirect the dynamic linker function, we can control how the dynamic linker functions perform. linker mapper segments, we can hide a segment from a code sign check. And last but not least, hook or update libmiss function. So libmiss is a helper in the user land which help MFID to check a CMS blob, check provision profiles and so on. If you can update or hook the functions, we can win code sign bottle in the user land. This technique was heavily used by evasion 7 and pangu 9 jailbreaks. I think we're just in time. So if you get questions, catch me downstairs or follow me on Twitter. I think that's all. Thank you.