-
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!