 The following talk is titled, it's not safe on the streets, especially for your 3DS, and it's about exploring a new attack surface on the 3DS and the speaker is NBA Joe. Hello. Hi everyone, I'm NBA and today I'm going to talk about 3DS hacking and especially about protocol, an undocumented protocol and I'm going to see, we're going to see OI attacked the protocol and got remote code execution on the system. But before seeing OI did that, I would like to do a quick recap of the state of 3DS hacking in 2019, because there have been a lot of user-learn exploits, a lot of patched kernel flows 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 case framework and they managed to dump the boot ROMs. And as a result, anyone who know how the boot ROM can derive all the secret keys of the system. And as a bonus, they were able to find a permanent and patchable boot ROM exploit. So at that point, you might be wondering what's left to do on 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 OI exploited and see what's possible to do once you get the application. 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 accurate point of view, we'd like to replace one of those 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 remote communication on foreign systems. But for doing that we need to know how the StreetPass feature works. So it's quite simple. It acts like a mailbox. So you have CCD, which is a system module. It's the only one that manages all the StreetPass feature. So your applications have an inbox and an associated outbox in the CCD 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 part we could try to attack. The first one you might think about are application parses, 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 execution in such an application. But the most interesting one would be to try to attack CCD's parser. And this would give us remote execution in a system module, which would be nice. But for doing that we need to figure out how the StreetPass protocol works. Nobody really knows how it works. There is a bit of documentation online about the pairing. So both systems are saying, hey, I'm here. 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 encrypted protocol that uses the secret AS key that we can get. So let's reverse the protocol. First, 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 one of those specific tags containing a list of applications that have StreetPass activated. And then eventually the master receives that probe request and analyzes it. It checks if an application from the client that has StreetPass activated matches one of its own applications with StreetPass activated. If it's the case, it sends a 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 command 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 actual instruments, 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 Wi-Fi adapter driver. So at that point, the 3D 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 SHA-1 over both console CIDs and both MAC addresses. And the output of this pass is used as an input counter for an 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 CMP 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've put some packets I was able to receive. And the first one is one of the smallest ones. 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 CCD is using really recognizable magic values. It's always the same batch repeated twice. And once you know the structure of the packets, you can figure 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 those all the exchange of structured data and street pass 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 magic values and some constants, but the most important field here is the flag fields. 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 SPTCP, so it was really easy to understand the protocol and how it worked. And what about SPTCP security? Actually, it's okay. I did not find any bug, but the attack surface is really small. You can basically only temple with the header, and that's it. So SPMTP should be much more interesting. So let's take a look at the structure of SPMTP packets. Because there are actually two different packet types. So the first one is InfoPackets. It's basically used in the handshake. And it's only here to share information between both peers. And then you have MessageBox packets, which are much more interesting because they contain actual street pass data. And you can even spot the CCD message file 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 InfoPackets. There's a bunch of things here. Many fixed-size data like friend codes, MAC addresses, et cetera. But it's not much interesting when you're looking for vulnerabilities. And there are viable-sized data, which are much more interesting. There are sending application lists, metadata, metadata lists. And it's much more interesting because when you pass 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 those parser. This is a function that passes metadata lists. So let's focus on the for loop. They are actually compiling 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 flow, but is it explodable? Let's illustrate this with a diagram. So this is a regular copy. So you have your packet buffer. And you have a main copy called on each entry. And everything is all right here. But if you had more entries, you have a bunch of entries copied 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 compiling uncontrolled data. So I was like, it's too bad. We can do anything with this. But let's check the buffer next to our packet buffer. Maybe there are some controlled data in there. And actually, yes, this buffer just next to the packet buffer is 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 index bit. But there is no stack cookies or no ASLR. So it's pretty straightforward. You can just send a small work chain and then send another one in some kind of packets and stack pivot to it. And then you get a remote execution in CCD. So this one was quite easy. Let's move on to message box packets. Message box packets are packets to send a list of 3D pass messages for some specific applications. They are actually stored in some temporary files for avoiding delays. And there are parts once the communication is over. So there are parts. 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 oops, they do not check the number of messages in the box. So this is another buffer of a flow. 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 the structure on the stack that we can see that there's 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. But we are a bit concerned because we are overwriting partially or uncontrolled data on the stack. Obviously, you cannot control on the message pointers. And you cannot totally control a message size because you cannot put some arbitrary values in there. You'd have to send gigabytes of messages and you cannot 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 passed is actually inside of the temporary file 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 synchronization and mutual exclusion. And you can see it's used after the temporary file has been passed. So maybe we can do something with it. This is the left critical section called at the end of the loop iteration. And you can see that they are using the pointer to decrements of some kind of count. So it's basically the number of threads that are using the critical section. And we can overwrite the lock pointer. So by overwriting it, we can decrement an arbitrary value in memory. But we need to find what to write that would give us more control over 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 initialized the stricter associated to temporary files. This is the function for the stricter, the initialization. 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 pointers in the message pointers array. But if it's not pointer mode, they will free all of them. And well, this value should be pointer mode in any case. But we can decrement it using the vulnerability we've seen before. So we can get some pointer feed. And since we control everything at the location pointed by message pointers, we can try to make it free some crafted and fake hipchanks. But there is another problem, because they're actually residing the allocation mode. Each time, temporary box is paused. 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. And then you can send your invalid second temporary 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. But it's not a problem if you send a second temporary box with the same size. The buffer will be relocated for that second temporary file. And we eventually free pointers to our controlled buffer. So what's next? We can craft some fake IP chinks. We can have the application freedom. What do we do? The 3DS heap is actually really insecure. You can exploit the classic and safe and link 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 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 paused. And the associated structure is written in stack. And it overwrites the lock pointer to make it point to the lock 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 control data, and especially or fake chunks. So your second temporary file is loaded and paused. Then all the chunks are freed. And the free list is moved to point on the stack. And finally, you can see that your last temporary file is written in the stack. So we can overwrite the return address and put our up chain in there. So this gives us a second remote code execution of an ability in CECD. And this one was quite trickier. So what's next? Another one. Again, there is another vulnerability in the message parser. It's actually an SDK function. So any application that uses StreetPass is vulnerable. Not only CECD, but all application in games that uses StreetPass are vulnerable to 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 gives us a persistent backdoor in CECD because CECD usually parses all the messages in and out boxes at startup. So you can trigger the vulnerability once the system boots. So we've got remote code execution in CECD. What can we do now? Actually, CECD does not have much privileges. It only uses space applications. And it's pretty well-sunboxed. You cannot access the internet, for example, nor the SD card. So if you want more privileges and we want more privileges, you need to take over something else. And your best choice would be trying to take over the ARM 11 kernel, which is the kernel for the user-land processor. 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 online 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 ARM 11 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 their 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 ARM 11 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 ARM 11 kernel need to write some pairs of physical addresses and size to the static buffers because the ARM9 does not have a MMU, so it's only using physical addresses. And the copy of data is eventually done by Process9, which is the only process running on the ARM9 site. So let's talk about a vignorability now. So it's called LazyPixie, and it has been found by Texas H. So it's not me. Oh, there's the kernel and all the PXI buffers case because it seems a bit complicated. So first, they check the alignment of the destination static buffer. They check the size of the destination static buffer. That checks 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 site. 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 kernel read, write, and execute, which is obviously enough to take it over. So at that point, the ARM113 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 role to full system control and see why taking over CCD was one of the best idea ever. So I'm going to talk about safe access. Maybe some of you know what safe access is because it's really hold vulnerability. It's actually risk condition in the firmware header parsing. You can take over the ARM9 site if you control the ARM11 kernel. But it has been fixed in the system version 9.5 for the regular native firmware and remains unfixed in the safe mode firmware, which is basically the recovery firmware if something went wrong for your console. So people have been exploring 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 headed on the ARM9 site. And when it's set to R1, the system just panics when you try to launch the safe mode firmware. So this flag is actually set to R1 whenever you try to launch an application. So this was the usual way to exploit it. You were launching the onboard menus through an application and then exploiting the ARM11 kernel and then running safe acts. So they set the flag to R1 whenever you try to launch a specific application, except some of them because your recovery firmware needs some applications to run. So there is an exception for the home menu and the system modules. And guess what? We are exploiting CCD, which is a stem module. And we are getting remote execution in CCD. So the flag is never set to R1 when we are getting code executed under CCD. So with an 11 kernel exploit, you can easily replicate the initial safe acts exploit. So in the end, you get a full control remote code execution without any user interaction since it's StreetPass and it's doing all this thing in the background. And on any firmware version, at the time this was developed because Nintendo patched it with a firmware version even 0.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 send 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 launch your kernel exploit and you can launch the installer for the boot from exploit, for example. Thanks. So some takeaways. Well, you'd better check your return value, really, because the second vulnerability would have been really hard 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 the vulnerabilities were only before the full. Then assessing how to reach features is really just I spend a lot of time doing this, especially figuring out how to replicate all the features, thoughts, 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 mitigations like for safe acts. And there's still things to do on the 3DS. I think I was able to show this today. This is an amazing system you can start to work on and do some practical things. And there is still things to document on the open source wiki, so feel free to contribute. So in the end, I'd like to thank Tuxesh for the lazy pixie of vulnerability and helping me getting this full chain exploit done. And Edgeberg, which is a recurring support with a lot of things. So now, if you have some questions, feel free to ask. Thank you very much. We are very, very much on time. So ask any questions. But please do ask them at the microphone. Go ahead. No, I thought I was going to ask a question. No questions? Oh, the internet is on. Great. 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? Oh, everything on the 3DS is closed source. So you have to reverse engineer everything. I used AIDA and Gidra to reverse the binaries of CECD. And yeah, that's it. OK, thank you. We have a second question. She doesn't. Is there any procedure for the switch that is compatible with all what you've done? So could you repeat that question? Well, all the things you have done are the code. Is there anything similar for the switch, for the internet switch? I don't think there is something similar on the switch. At least something that looks like the StreetPass feature. But I don't know. I don't really know all the switch work. I've only done things on the 3DS. OK, first question for the room. 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. Could you repeat the question? 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? Well, no, you do not need all three exploits. At least in CECD, you only need one, basically, to get remote code execution. But I found it fun to just show all three exploits for CECD. Next question. Are the StreetPass messages passed to the applications, even when those applications are not running? So for example, when you have Pokemon or something installed? Could you speak louder, please? OK, 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 build in there, will it automatically parse the corrupted message? Could you reformulate your creation? OK. In your three exploitation methods, you mentioned the third method that mentions the SDK being broken. 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. 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 application that use the old SDK. OK, thanks. There's a question over there. Yes, can you go back to the slide where you showed how the encryption for the packets work? The encryption? Yes, the encryption. Right, yeah, that one. So my question is, if the only thing that you're changing is the counter and the data is constant and the keys 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? Well, the counter changed every time you start a new sweet pass communication because the CIDs are randomized. And the MAC addresses are also randomized before starting a new communication. 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 output of that with the final output, and that removes 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? Yeah, well, I'm not super familiar with all the cryptography, but maybe we could talk about it. Yeah, let's talk off. I was just putting this for people to reproduce it if they want. OK, any more questions? Thank you so much. Thanks.