36C3 preroll music Herald: The following talk is titled "It's Not Safe in the Streets, especially for your 3DS" and it's about exploring a new attack surface on the 3DS. And the speaker is nba::yoh. The show is yours. applause nba::yoh: Hi, everyone. I'm nba::yoh and today I'm going to talk about 3DS hacking and especially about a protocol, an undocumented protocol. And we're gonna see how I attacked the protocol and got remote code execution on the system. But before before saying, oh, I did that, I'd like to do a quick recap of the state of 3DS hacking in 2019, because there have been a lot of userland exploits, a lot of patched kernel flaws and there's a lot of documentation online about the system. And during the last few years, people have been working on it and broke the hardware keyscambler. And they managed to dump the bootroms. And as a result, anyone who now have the bootrom can derive all the secret keys of the system. And as a bonus, they were able to find a permanent unpatchable bootrom exploit. So at that point, you might be wondering what's left to do in the system. And actually, I wonder if it would be possible to use those keys to attack features that were protected until then by encryption. So that's why today I'm going to talk about StreetPass. First, I'm going to do a quick introduction about the feature and then we'll see how I expoited it and see what's possible to do once you get code execution. So what is StreetPass? This is a local and wireless communication feature. The basic idea behind StreetPass was that users would take their 3DS with them and go out and it would automatically communicate with other people's systems. The point of the feature was to share data between applications like custom levels for your games or messages, avatars, et cetera. So this is quite an interesting feature for players, but also for hackers. So this is the player point of view so you can send your messages and other people will be able to receive them. But we'd like to - from an hacker point of view - we'd like to replace one of these systems with a PC to tamper with the protocol, for example. And eventually it would be nice if we could send some corrupted messages and see if we can get code execution on foreign systems. But for doing that, you need to know how the street the StreetPass feature works. So it's quite simple. It acts like a mailbox. So you have CECD, which is a system module, and it's the only one that manages all this StreetPass feature. So all your applications have an inbox and an associated outbox in the CECD file system and they can put and get messages from and to these boxes via IPC. Then messages in these boxes are used to craft packets which are then sent using the StreetPass protocol. And we can already see on this diagram which path we could try to attack. The first one you might think about are our application boxes because it's very likely that you'll be able to find some kind of game or application that have a float parser. So we might take and get remote code execution in such an application. But the most interesting one would be to try to attack CECDs parser. And this would give us remote code execution in a system module, which would be nice. But for doing that, we need to figure out how the StreetPass protocol works and nobody really knows how it works. There is a bit of documentation online about the pairings, so "oh both our systems are seeing a hand here. Would like would you like to communicate with me?" But it has never been successfully reproduced, at least publicly. And we know that it's using an unknown and encrypted protocol that uses the secret AES key that we can now get. So let's reverse the protocol. First, well, let's reverse the pairing and replicate it. So it's fairly easy to understand: You have both peers, the client and the master and before communicating they randomize their console ID and their MAC address. Then the client sends a bunch of probe requests with our bundle specific tag, containing a list of the applications that have StreetPass activated. And then eventually the master received that public list and analyzes it. It's checked if an application from the client that has StreetPass activated matches one of it's own applications with StreetPass activated. If it's the case, it sends the probe response to the client, which will do the same. And if both peers agree that they can exchange data, they will start communicating after deriving a common key. So replicating the pairing is not super odd if you know what tool to use. I tried to reproduce the pairing using a monitor mode, but it's really hard because you have to deal with all the action item frames et cetera. So I used nl80211 which lets you register some specific callback for some specific frames and send custom frames and everything is handled by your wifi adapter driver. So at that point the 3DS starts sending encrypted data and we have to decrypt them. So let's review the encryption. They do this in two passes, the first one they use an HMAC-SHA1 over both consoles CIDs and both MAC addresses and the output of this pass is used as an input counter for on AES-CTR using the AES key slot we can now get. And the output of this encryption is used as a session key for the communication. So nl80211 lets you register CCMP keys so it's quite easy to send and receive encrypted packets using it. So now we can start reversing the protocol. Let's take a look at the structure of packets before doing any reverse engineering. So I put some packets I was able to receive and the first one is one of the smallest one you can actually observe. So first you have a header and then you have some data and you can spot some magic values here. Actually, it's easy to spot them because CECD is using really recognizable magic values. It's always the same byte repeated twice. Once you know the structure of the packets, you can view that there are actually two protocols. The first one is SPTCP. It's an equivalent of TCP, but for local communication. It's mainly designed to ensure reliability and data segmentation. And then you have SPMTP which is built over SPTCP and handles all the exchange of stricter data and StreetPass messages. So we have two protocols and we need to review both of them. Let's start with SPTCP. Actually, there is not much to say because you only basically have to reverse and understand the header. You have a magic value and some constants. But the most important field here is the flag field because if you can understand what are the flags, you can understand the meaning of the packets you are sending and receiving. And so you can basically understand the protocol. And fortunately, in this case, they're using the same flags as TCP, so it was really easy to understand the protocol and how it worked. And what about SPTCP security? Actually, it's OK. I did not find any bug. But the attack surface is really small. We can basically only tamper with the header and that's it. So SPMTP should be much more interesting. Let's take a look at the structure of SPMTP packets, because there are actually two different packet types. The first one is an info packet. It's basically used in the handshake and it's only here to share information between both peers. And then you have message box packets which are much more interesting because they contain actual StreetPass data and you can even spot the CECD message via magic value, which means that we actually reach actual game data and SPMTP is the last layer of encapsulation of the whole protocol. So once you figure out how SPMTP works, you can reimplement the protocol. So let's first review info packets. There's a bunch of things in here. Many fixed size data like friend codes, MAC addresses, et cetera. It's not much interesting when you're looking for vulnerabilities. There are variable size data, which are much more interesting. They are sending application lists, metadata lists, and it's much more interesting because when you process them, you can fail your parser. And if there is some vulnerability here, we might exploit them to get remote execution. So let's take a look at one of this parser. This is a function that parses meta data lists. So let's focus on the for-loop. They are actually copying a list of entries to the stack. The destination is on the stack and they do not check the number of entries in the list. So this is clearly a buffer overflow, but is it exploitable? Let's illustrate this with a diagram. So this is a regular copy. So you have your packet buffer. And you have memcopy called on each entry and everything's is all right here. But if you had more entries, you have a bunch of entries, compete on the stack, that overwrite a bunch of things. But there's a problem here, because the packet buffer is not large enough for us to reach the return address on the stack. So we are probably copying uncontrol data. So I was like, it's too bad, we can't do anything with this, but let's check the buffer next to our packet buffer. Maybe there are some control data in there. And actually, yes, it's this buffer just next to the packet buffer, dedicated to a list that we sent just before. So actually we can rewrite the return address. So, how do we exploit it now? On the 3DS, you have the NX bit, but there is no stack cookies or no ASLR, so it's pretty straightforward. You can just embed a ROP- chain, a small ROP-chain, and then send another one in some kind of packets and stack-pivot to it. And then you get remote code execution in CECD. So this one was quite easy. Let's move on to message box packets. Message box packets are packets to send a list of StreetPass messages for some specific applications. They are actually stored in some temporary files for avoiding delays and they are parsed once the communication is over. So they are parsed. So let's take a look at the parser. This is the function that actually loads a temp file into an associated structure on the stack and whoops, they do not check the number of messages in the box. So this is another buffer overflow. You are basically overflowing the message pointers array and the message sizes array. So let's treat this with another diagram. So you have on the right the temp file and on the left the stack and you see that you have this structure on the stack we can see that there is the message pointers with pointer pointing to your temp file buffer and you have the message sizes. And if you add another message in the temporary file, you overflow both arrays and start overwriting some data on the stack. We are a bit concerned because we are writing partially or uncontrolled data on the stack. Obviously you cannot control the message pointers and you can not still control message size because you can not put some arbitrary values in there. You'd have to send gigabytes of messages and you can not do that. So what can we do? What you can see here is that you can actually set the last message size to an arbitrary value because they are checking if the current message being parsed is actually inside of the temporary file, a buffer. And if the current message pointer goes out of the buffer, they break the loop without returning an error. So what you can do is set the last message size to an arbitrary value and then the pointer will go out of the buffer and you will write one 32-bit value on the stack. But we need to know what to write. You cannot, unfortunately, you cannot directly overwrite the return address because remember that we are writing mainly uncontrolled data and reaching the return address would require you to overwrite the whole stack frame with uncontrolled or partially uncontrolled data. So the only thing I was able to rewrite without crashing the system is this particular variable. It's a pointer to a critical section and it's used for signed synchronization and mutual exclusion. And you can see it's used after the temporary file has been parsed. So maybe we can do something with it. This is the leave_critical_section call at the end of the loop iteration. And you can see that they're using the pointer to decrement some kind of count. So it's basically the number of threads that are using the critical section and we can override the lock pointer. So by overwriting it, we can decrement an arbitrary value in memory, but we need to find what to overwrite, that would give us more control of the memory and control the execution flow. So I've been looking for something like this and I found something interesting in the function that deinitialized the structure associated to temporary files. This is the function for the structure deinitialization. And you can spot this variable. They actually implemented some kind of allocation mode. And if it's equal to pointer mode, it will not try to free the pointer. The pointers in the message pointers array. But if it's not pointer mode, they will free all of them. And while this value should be pointer mode in any case. But we can decrement it using the the vulnerability we've seen before. So we can get some pointer freed. And since we control everything at the location pointed by message pointers, we can try to make it free some crafted and fake chunks. But there is another problem because they're actually resetting the allocation mode each time a temporary box is passed. So we have to find a solution to this. And what you can do is try to make that function return early before the allocation mode is restored. But this implies making it return an invalid return code. But actually, it's not a problem because they're not checking the return code. So what can we do so far with this? So you can send a first temporary box. This will overwrite the lock variable in the stack and decrement the allocation mode. Then you can send your invalid second temorary box and the parser will return early and the message pointers array will not be updated. And in the end, all the pointers in that particular array will be freed. But since the message pointers array is not updated, the pointer in that particular array are still pointing to the first temporary file buffer which has been freed. That's not a problem. If you send a xecond temporary box with the same size, the buffer will be re-allocated for that second temporary file and we eventually free up pointers to control the buffer. So what's next? We can craft some fake heap chunks. We can have the application free them. What do we do? The free, yes, it is actually really insecure. You can exploit the classic unsafe linker vulnerability, so you get one arbitrary write for each chunk you can free. And you still need to know what to overwrite. But you can just rewrite the heap free list head pointer. So the next malloc call will return a pointer to wherever you want, and you can especially put a pointer to the stack in there. So the next malloc call will return a pointer to the stack and it will be used to store your third temporary file. So it's a bit hard to understand. So let's again illustrate this with a diagram. So first you have your first temporary file loaded in memory. So on the right it's parsed and the associated structure is written in stack and it overwrites the lock pointer to make it point to the alloc mode in memory. In the end, leave_critical_section is called. So you have your temporary buffer freed and your location mode decremented. Then your second temporary file is loaded in memory. The buffer used for the first file is relocated and the pointers in the structure still point to our controlled data and especially our fake chunks. So your second temporary file is loaded and parsed. Then all the chunks are freed and the field it is at is moved to point on the stack. And finally, you can see that your last temporary file is read in on the stack so we can overwrite the return address and put a ROP-chain in there. So this gives us a second remote code execution vulnerability in CECD. And this one this one was quite trickier. So what's next? Another one. Yeah. Again, there is another vulnerability in the message parser. It's actually an SDK function. So any application that uses SteetPass is vulnerable, not only CECD but all application and games that use StreetPass are vulnerable for this one. But I'm not going to talk about it and explain everything. It's up to you to exploit it. So this gives us a third Remote Code Execution in CECD and you can get Code Execution in any application using StreetPass. And this also give us a persistent backdoor in CECD because of CECD usually parses all the messages in the in and out boxes at startup. So you can trigger the vulnerability once the system boots. So we've got a Remote Code Execution in CECD, what can we do? No, actually, CECD does not have much privileges. It's only a userspace application. And it's pretty well sandboxed. You can not access the internet, for example or not the SD card. So if you want more privileges and we want more privileges, you need to take care of something else. And your best choice would be trying to take over ARM11 Kernel, which is the kernel for the userland processor. This this would give you total control over this processor. And if you want really full system control, you'd like to also take over the ARM9 security processor. So this is the processor that do all the encryption and signature stuff. And we will see this later. So let's first try to take over the ARM11 kernel. But first, I need to talk about IPC and especially what are called static buffers. So when you are doing IPC, you need to sometimes send data from a sender process to a receiver process and on the 3DS, you can do this in multiple ways. The first one is if you want to send large regular buffers, you can map parts of the sender's memory into the receivers, but you can also use what are called static buffers. If you want to send some small buffers, the receiver can register static buffers and the ARM11 kernel will do the copy for you to that particular buffer. And sometimes you need some buffers to be sent to the ARM9 processor. So the ARM11 kernel need to write some pairs of physical addresses and size to the static buffers because the ARM9 does not have an MMU so it's only using physical addresses and the copy of data is eventually done by the Process9, which is the only process running on the ARM9 side. So let's talk about a vulnerability now. So it's called LazyPixie and it has been found by TuxSH. So it's not me. How does the kernel handle the PXI buffers case because it seems a bit complicated. So first they check the alignment of the destination state buffer, they check the size of the destination static buffer. They check the permissions for the source buffers. Then they do cache operations, they copy metadata. So the physical address and the size of the static buffer to the destination and then the copy is done by the ARM9 side. But I think there is something missing here because they do not check the permissions for the destination buffer. So what you can do is use an arbitrary address as a destination. And so you can just overwrite the MMU table and make your kernnel read, write and execute, which is obviously enough to take it over. So at that point, the ARM11 Kernel has fallen and we have the full control of that processor. But we would like a bit more privileges because why not? We want the full system control. So let's take the road to full system control and see why taking over CECD was one of the best ideas ever. So I am going to talk about SAFEHAX. Maybe some of you know what SAFEHAX is because it's a really cool vulnerability. It's actually race a condition in the firmware header parsing you can take over the ARM9 side if you control the ARM11 kernel. It has been fixed in the system version 9.5 for the regular native firmware and fixed in the safe mode firmware, which is basically the recovery firmware if something went wrong for your console. So people have been exploiting it both on the native firmware and the safe mode firmware and it has been mitigated in version 11.3 and 11.4. So it does not work anymore, but it has only been mitigated and not patched. So let's take a look at that mitigation because how do they prevent us to exploit that vulnerability? So this so-called mitigation is a boolean flag that has been added on the ARM9 side and when it's set to 1 the system just panics. When you try to launch the safe mode firmware. So this flag is actually set to 1 whenever you try to launch an application, so this was the usual way to exploit it, you were launching the homebrew menu through an application and then exploiting the ARM11 kernel and then running SAFEHAX. So they set the flag to 1 whenever you try to launch a specific application, except some of them because your reconnection ARMs needs some applications to run. So this is there is an exception for the home menu and the system modules. And guess what? We are exploiting CCD, which is a system module and we are getting Remote Code Execution in CCD. So the the flag is never set to 1 when we are getting code executing on the CCD. So with that kind of exploit. You can easily replicate the initial SAFEHAX exploit. So then you get a full control, remote code execution without any user interaction. And it's StreetPass and it's doing all of this thing in the background and on any firmwre version at the time this was developed because Nintendo patched it with firmware version 11.12. So I guess it's time for a little demo. I'm not going to do it live because I don't want to some exploits in the air. So I have a little video. So I'm running my exploit on my laptop and you can see the LED is turned on to see that the exploit is running in CCD. And then you once you're you can exploit and you can launch the installer for the Boot ROM exploit, for example. applause Thanks. So now, some some takeaways. Well, you'd better check your return value, really, because there's a second vulnerability would have been really, really out to exploit without that mistake. And really, you should not hide behind cryptography because one day your encryption will be broken and this might come sooner than you think. And for this specific case, there was a bunch of dumb mistakes and basically all vulnerabilities were only buffer overflows. Then, assessing hard-to-reach features is really arduous. I spent a lot of time doing this, especially figuring out how to replicate all the features, parts and all the different protocols involved. But eventually, you can get some really interesting results like this. Then, I'd say please fix your flows, and do not implement some poor mitigation, like for SAFEHAX. And there's things still to do on the 3DS. I think I was able to show this today. There is, this is an amazing system you can start to work on and do some practical things. And there's still things to document on the open source wiki, so feel free to contribute. So, in the end, I would like to thank @TuxSH for the LazyPixie and helping me getting this full chain exploit done, and @hedgeberg for recurring support with a lot of things. So now, if you have some questions, feel free to ask. Herald: Thank you very much. applause Herald: We are very, very much on time. So ask any questions, but please do ask them at a microphone. Go ahead. No, I thought there was going to ask a question. No questions? Oh, the Internet has one. Great. Signal angel: So, yes, we have two questions. The first one is what tools and environments do you use for your research? For example, someone mentioned how do you get all the source code? nba::yoh: Oh, everything on the 3DS is closed source. So you have to reverse engineer everything. I used IDA and Ghidra to reverse the binaries of CCD and, yeah, that, that's it. Signal angel: OK. Thank you. We have a second question: Is there any procedure for the Switch that is compatible with all what you've done? nba::yoh: Sorry, could you repeat that question? Signal angel: Well, all the things you have done, all the code. Is there anything similar for the Switch? nba::yoh: I don't think there is something similar on the Switch, at least something that looks like the StreetPass feature. But I don't really know how the Switch works, I've only done things on the 3DS. Herald: OK, first question for the room. Microphone: Thanks for the talk, great. Did you really need all the three exploits? And which one did you use in the end for the full chain? Thanks. nba::yoh: Could you repeat the question? Microphone: Did you need all the three exploits that you had or could you just use the easiest one? And which one did you use in the end? nba::yoh: Well, no, you do not need all three exploits, at least in CCD. You only need one basically to get remote code execution. But I found it fun to just show all the exploits for CCD. Herald: Next question. Microphone: Are the StreetPass messages passed to the applications even when those applications are not running? So, for example, when you have like Pokémon or something installed... nba::yoh: Could you speak louder, please? Microphone: Okay. Are the applications parsing the messages even if they are not running? Like, is there some sort of a handler being run by the OS even if you don't have an application running, just installed? So that if you have a vulnerable application with the old SDK built in there, will it automatically parse the corrupted message? nba::yoh: Could you reformulate your question? I don't understand. Microphone: Okay. In your tree exploitation method, you mentioned the third method that mentions the SDK being broken. nba::yoh: Yeah. Microphone: And if you have an application built with that old SDK, does it automatically parse the message even if it's not running, so that even if you have a patched OS, but not patched applications, it will still get exploited? nba::yoh: Yeah, all the applications using the SDK should be updated to fix the vulnerability. So the exploit is triggered when the application parsed the messages. So you have to run the application to exploit it. CCD has been patched, so there is no more remote code execution in CCD, nor a permanent backdoor in CCD, that automatically runs, when the system is started. But you can probably still exploit games and applications that use the old SDK. Microphone: Okay, thanks. Herald: There's a question over there. Microphone: Yes. Can you go back to the slide where you showed how the encryption for the packets worked? nba::yoh: The encryption? Microphone: Yes, the encryption. Yeah. Yeah. That one. So my question is, if all you're, if the only thing that you're changing is the counter, and the data is constant and the key is constant, and it's CTR, then you're basically just XOring a known block with your HMAC output. So why do you even need the key here? nba::yoh: Well, the counter changed every time you start a new StreetPass communication, because the CID's are randomized and the MAC address is, the MAC address is also randomized before starting a new communication. Microphone: Right. But I guess what I'm asking is, why do you need key slot 2E? In my mind, having the CCD HMAC key would be enough, because you can just XOR the, you know, output of that with the final output, and that removes, you know, the CTR part, and now you have the raw output of the null block encrypted with key slot 2E, which is always going to be constant, and then you can just XOR whatever output to get the final result, right? nba::yoh: Yeah, well I'm not super familiar with all the cryptography, but maybe we could talk about it. I was just putting this for, for people to reproduce it if they want. Herald: Okay. Are there any more questions? Thank you so much. nba::yoh: Thanks. applause postroll music subtitles created by c3subtitles.de in the year 2020. Join, and help us!