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!