What do Nintendo Switch and iOS 9.3 have in common? CVE-2016-4657 walk-through

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
What does iOS 9.3 and the Nintendo Switch have in common? They both use the browser engine WebKit with a version that is vulnerable to a known memory corruption vulnerability. Remember the news of the pegasus malware for iOS, which was discovered when it was used in a targeted attack against the human rights activist Ahmed Mansoor? That malware used a webkit exploit as the first stage, to gain arbitrary code execution. Qwerty and the pangu team then used this bug in their jailbreakme website. And it turns out, the browser of the Nintendo Switch is so old, that is also has this bug. And this is what a lot of people are using right now as a first entry point in hacking the switch. Obviously the whole jailbreak is extremely complex, even just getting code execution is insane. But I spent now quite some time understanding the bug itself and the first crucial part which creates an arbitrary read/write primitive. So you can overwrite anything in memory, for example function pointers or jitted code. But let’s start at the beginning. <intro> First we need to figure out how to access the browser in the switch. You may have heard that the Nintendo Switch doesn’t have a browser, so what the heck am I talking about? Well there is no good browser implemented, but it turns out, that when you connect to a wifi, which requires you to login in a captive portal, it will use a browser view and load that page for you. A captive portal is common in hotels and airports and stuff. So we have to figure out how to load our own website here. When you look at the network settings, you can specify a proxy server, which is great because then I can run a proxy server on my laptop and intercept all the traffic. I use Burp Suite as my proxy server and just have to make sure it listens on all interfaces, so other devices on the same network can use it. So now we just have to enter the IP of this laptop into the proxy settings of the switch. When we now connect to the wifi, the switch will establish connections through this laptop. And we can see here in the Burp history view, that the switch tried to contact conntest.nintendowifi.net That site just responds with a simple string that the connection works. It uses this to check if you have internet connection or not. So, if this check fails, it will think you first need to authenticate from a captive portal. So next we need to redirect this request to a different page, basically our “captive portal”. We can do that by simply modifying the /etc/hosts file, to point the conntest domain to another IP. For example localhost. Then we spawn a simple webserver on our machine, for example with php -S. We can place a index.html file in here to verify that this works. And with a browser we can see that we have now on localhost a webserver running. So, when the switch now connects to the wifi, it will try to contact conntest and it will go through the proxy on my laptop. My laptop sees in the /etc/hosts file what the IP for conntest is. So the proxy will connect to localhost instead, which will access our index.html file. Let’s try it. We search for the wifi. We connect to it. It will check if there is access to the internet. It didn’t get the expected result for conntest back and tells you you have to login. When we now press next, it will load what it thinks is the captive portal. Now we have access to a browser that loads our website. We can also have a look at the requests in burp, which shows us the User Agent the switch uses. So now that we have that setup, let’s read up a bit more on the webkit bug. It was assigned CVE-2016-4657 and has the description: “WebKit in Apple iOS before 9.3.5 allows remote attackers to execute arbitrary code or cause a denial of service (memory corruption) via a crafted web site.” The description can be a bit misleading. Makes it sound like it’s only an iOS issue, but its generally a webkit bug, and would affect anything that used that particular webkit version. In our case the nintendo switch. Also this is not an exploit where you just type into metasploit `use exploit/nintendoswitch/webkit`. This is something where you actually have to understand it quite in depth to be able to use it. Now let’s take qwerty’s jailbreakme code, which uses the webkit bug, extract the first relevant part and adapt it to the nintendo switch. I won’t go through all this process because that took me ages to understand, but I want to show and explain to you what I got now... So let’s walk through it. First we create a Typed Array of unisgned 32bit integers. And in memory this will create a struct with a couple of different values such as a JSCell which contains a couple of interesting values such as a structure ID that determines kind of the type of this object. We will look at that later again. A butterfly pointer, which is used in a bit more complex objects but not quite relevant for us right now, a vector which contains a pointer to a chunk of memory that represents our array. And the length of that memory. So that array gives us basically access to raw bytes in memory. Obviously you can’t access beyond it’s length. Then we create a more flexible array. A standard array like you might use it. That array is a bit different, as it can contain arbitrary types. Any kind of objects. So instead of just pointing to raw memory, it points to more complex objects called JSValues. And here is an example of the integer with the hex value 41414141, it would store 0xffff0000 before it, to indicate the value is an integer. Look at the amazing phrack paper if you want to know more details about these JSValues. In the case of the exploit it will set the first element of the Array to a big ArrayBuffer and the second to some number. An Array Buffer is also access to raw bytes. Basically different typed arrays can point to the same buffer in memory. Whatever, read the javascript reference. So If I’m not mistaken, the first element of the array is now a JSValue with a pointer to an array buffer. Next we create a simple Javascript Object and overwrite its toString() function. That function is called whenever you want to get a string representation of that object. So if I return 1337 object as a string, and I would alert this object, it would call to string and show me that one. But in this case the function does a bit more. It first sets the reference to the array we just created to null, as well as setting another property to null. In a second you will see that this “stale” property is also a reference to the arr array. Theoretically now all references to the array are gone, and the garbage collector can free that array. To force the garbage collector to kick in right now, we can use the function which just allocates and removes a lot of objects. And when you do this a couple of times you can be fairly certain that the garbage collector did the work. After the garbage collection the function will now allocate a lot of new Uint32Arrays. The reference to those are stored in buf, so we can access those arrays. And if everything goes well those arrays might be allocated where the previous array was. But how is this object with that toString function used now. We define an object that we use as properties. And I think we allocate more than just two, so the properties are not stored inline, but I’m not 100% sure here. Anyway, one of these properties is called stale, and it is set to the array reference. That is the property that the toString function will set to null. Another property is `length` which is set to the not_number object. Then we create a new empty array target and apply those properties to it with Object.defineProperties. This means all those properties we defined will be set to the target array. During this assignment, the toString() function of not_number will be called and causes the garbage collection of the array. As well as the allocation of a lot of Uint32Arrays. And this is where the bug happens. Theoretically the stale property was set to null, and should not be accessible. But somehow the reference is still there. Some stuff internally did not properly check everything. This means that we have a reference into some memory where previously the arr array was allocated. And we also allocated a lot of Uin32Arrays and we hope that these now overlap. As I mentioned earlier, the Uint32Arrays allow direct memory access, they can read and write raw bytes. While the arr array was a complex object, with JSValues. Now it’s already clear what you can do with this. You can use the Uint32Arrays, which are accessible via buf. To read and write raw bytes at the location where the stale property thinks a standard Javascript object is. So first it has to find if and how the buf and the stale array overlap. To do this, we can simply add a number to the first element of stale. But what is the first element of stale now. Isn’t that garbage memory? well ideally, if everything works, it points to where we created the uInt32Arrays, and we populated that memory region with 0xffff000041414141, which is a JSValue representing an integer. In fact the number 0x41414141. This means that now we add hex 101 to the first element of the stale array, making it 0x41414242. We can then simply search through the whole uInt32Array memory looking for this 0x41414242. Keep in mind that the buf has access to raw bytes, so it will infact see the 0xffff0000 and the 0x41414141, while the stale array things this is a javascript object, and only uses the 0xffff0000 internally to determine, that we have an integer and the value of it is 0x41414141. So what can we do with this now. This is where exploitation really become creative. The phrack article says that once you have the ability to craft arbitrary javascript objects, you could craft a Float64Array to create a read/write primitive, but qwerty used a Uint32Array. To quote him, here is his reason: “Easier than float to do math with. Lol.” And I guess he has a point. Floating point values in raw bytes are really annoying. So first of all, why do we want to craft a Uint32Array. If you remember the basic structure of a Uint32Array, it uses a vector to point to some raw memory. If you control where this pointer points to, you can control where you can read data from and write data to it. Because it thinks it points to the actual array. There is a super clever way how to craft this array now. Qwerty creates a new object with four properties. A,b,c,d. He probably just took that from the phrack article, because when you look at how a simple object with only four properties is stored, it stores the values inline. This is very helpful in a second. As you see, the values set, like the hex 1337 are simply placed here in memory after eachother. So that’s a very neat way to control a couple of consecutive values in memory. The two 64bit values are the JSCell and the butterfly pointer. The JSCell, or more specifically the structure ID inside of the JSCell determines, what this Javscript Object actually is. In the phrack article it looks like, this object here has the ID 136. So in order to craft a Uint32Array, we would have to know the structure ID of that. According to the phrack article, this ID can change sometimes, maybe at restart or between different webkit builds. But apparently it’s very common to be 105. Nontheless, because my exploit was very unstable I tried to see if the value is maybe different and the phrack article shows a technique how to do that. Back to the new object for a second. So this will allocate a new object with 4 properties that looks like this in memory. 0x69, or in decimal 105, then zero, the pointer to the smash array, which we allocated way at the beginning and 0x100. The function u2d is a clever little helper. As every number in javascript is basically a float, we can create a new dataview of 16bytes, so 64bit, set the high and the low 32bits and return the float representation of those bytes. This new object creation will also overwrite stale[0]. Just a few seconds ago I mentioned that stale[0] points to a JSValue representing a number, but now it was overwritten with a JSValue representing a pointer. A pointer to the JSObject that was just created. This JSObject it points to is not very interesting for us. It’s not an arbitrary object we have crafted. But remember, that the JSValue with the pointer to this object is in the memory that is overlapped by the buf. This means we can use buf to manipulate the pointer. And what we do is, we add 0x10 or decimal 16, which moves the pointer into the properties of the JSObject. Now suddenly the 0x69 is the JSCell value. And the zero here is the butterfly. And the smsh address becomes the vector, the pointer where the actual array is in memory. To be clear this points into the similar struct of that array, so this doesn’t point into the memory location of that smash array, but also into this JSObject struct with its vector pointer and its length. And 0x100 is the length of that array, which is actually just the Object structure of the smash array. So now you know how we can misalign the pointer to this object, which will interpret the properties here as the actual object. This means we can now try different structureIDs in a loop and check with instanceof if we have crafted a Uint32Array. We remember the original stale[0] pointer in stale[1], then missalign stale[0], then we can check the type of the stale[0] object, if it’s not correct, we increment our structureID guess, and assign a new value to the stale[1] ‘a’ property, which will look like the StructureID from the missaligned pointer in stale[0]. What we basically created now is, we have two pointers in stale. Which slightly overlap in memory. We also have somwhere an array called smsh. We have also set the memory location for our crafted array, the vector pointer, to point to smsh. To the smash structure, not the actual memory location of the smash array. This means we have another object that we can fully control. Stale is an array. The first element of stale points to a crafted Uint32Array. So when we access the elements of that array, we obviously access the 32bit values of the smsh JSObject structure. And as you know, the object contains 64bit values, and the fourth 64bit value is the length of the smsh array. So stale[0] of [0] and [1] would be the first 64bit, 2,3 would be the second 64 bit, 4,5 would be the third 64bit and 6,7 would be the 4th 64bit. So with stale[0][6] we can overwrite the length of the smash array. And we can now check the length of the smsh array. Let’s try this on the switch. We load the page and it might not immediately work, but it will refresh and try again. Ok so we triggered the bug and we found overlapping memory by looking for the 0x41414242 value. Now we check the current length of smash, we craft our object, try to find the structure id, we actually find it’s 105, so I didn’t have to go through this trouble of iterating over them, then we change the length of smsh and print the smsh length again. And it changed. Isn’t this crazy! So now we can just modify the vector where the smash array points to in the exact same way, and then simply read the raw data it points to from the smsh array. or write to the smash array. It gives us super simple access to the whole memory of the process. Next steps could be to find the address of the browser binary in memory to dump it. Maybe find some function pointers in memory you can overwrite, create a ROP chain or maybe even shellcode because we should have jitted code, I guess? This video is already crazy long. So let’s stop here for now. I really learned a lot working through the first part of qwerty’s exploit. I hope this this also gives you a sense for how frckn complicated these modern memory corruption exploits are and what kind of work and knowledge is required to do them. I only scratched the surface here. I hope this also increases your respect for the people who do this kind of research. At this point I also want to thank Retr0id and Ando who I just met on IRC and were in the same boat as me and we and we helped eachother trying to figure how this works. And also a huge thank you to qwerty, who answered a lot of my noob questions and shared his progress with me. I really appreciate you supporting somebody who tries to learn this! If this sounds like fun to you, make sure you read the phrack paper by samuel groß, or saelo about “attacking javascript engines”, which gives a way more in depth insight into how this works. There is also another article more specifically about firefox, which is different from webkit, but also gives you a better idea of how browsers w ork. Thank you very much, keep on hackin’ in the free world, and doot doola doot doo.
Info
Channel: LiveOverflow
Views: 315,738
Rating: undefined out of 5
Keywords: Live Overflow, liveoverflow, hacking tutorial, how to hack, exploit tutorial, CVE-2016-4657, Nintendo switch, iOS, jailbreak, webkit bug, webkit exploit, webkit jailbreak, pegasus, trident, NSO group, qwertyoruiop, qwertyoruiopz, switchdev, homebrew, chrome exploit, safari exploit, modern exploitation, javascript explot, jbme, jailbreak me, 9.3.X, jailbreak 9.3, iOS 9.3, switch 2.0, arbitrary read, rwx, rce, hacking switch, switch hacked, exploit, heap corruption
Id: xkdPjbaLngE
Channel Id: undefined
Length: 18min 43sec (1123 seconds)
Published: Mon Mar 13 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.