WEBVTT
00:00:00.000 --> 00:00:19.781
36C3 preroll music
00:00:22.710 --> 00:00:26.439
Herald: The following talk is titled "It's
Not Safe in the Streets, especially for
00:00:26.439 --> 00:00:31.430
your 3DS" and it's about exploring a new
attack surface on the 3DS. And the speaker
00:00:31.430 --> 00:00:36.270
is nba::yoh. The show is yours.
00:00:36.270 --> 00:00:42.190
applause
00:00:43.297 --> 00:00:49.879
nba::yoh: Hi, everyone. I'm nba::yoh and
today I'm going to talk about 3DS hacking
00:00:49.879 --> 00:01:01.109
and especially about a protocol, an
undocumented protocol. And we're gonna see
00:01:01.109 --> 00:01:10.580
how I attacked the protocol and got remote
code execution on the system. But before
00:01:10.580 --> 00:01:18.229
before saying, oh, I did that, I'd like to
do a quick recap of the state of 3DS
00:01:18.229 --> 00:01:27.100
hacking in 2019, because there have been a
lot of userland exploits, a lot of patched
00:01:27.100 --> 00:01:33.030
kernel flaws and there's a lot of
documentation online about the system. And
00:01:33.030 --> 00:01:41.420
during the last few years, people have
been working on it and broke the hardware
00:01:41.420 --> 00:01:49.509
keyscambler. And they managed to dump the
bootroms. And as a result, anyone who now
00:01:49.509 --> 00:01:57.899
have the bootrom can derive all the secret
keys of the system. And as a bonus, they
00:01:57.899 --> 00:02:03.700
were able to find a permanent unpatchable
bootrom exploit. So at that point, you
00:02:03.700 --> 00:02:11.040
might be wondering what's left to do in
the system. And actually, I wonder if it
00:02:11.040 --> 00:02:16.620
would be possible to use those keys to
attack features that were protected until
00:02:16.620 --> 00:02:22.475
then by encryption. So that's why today
I'm going to talk about StreetPass.
00:02:25.059 --> 00:02:30.650
First, I'm going to do a quick introduction about
the feature and then we'll see how I
00:02:30.650 --> 00:02:39.240
expoited it and see what's possible to do
once you get code execution. So what is
00:02:39.240 --> 00:02:45.790
StreetPass? This is a local and wireless
communication feature. The basic idea
00:02:45.790 --> 00:02:51.980
behind StreetPass was that users would
take their 3DS with them and go out and it
00:02:51.980 --> 00:02:59.989
would automatically communicate with other
people's systems. The point of the feature
00:02:59.989 --> 00:03:07.180
was to share data between applications
like custom levels for your games or
00:03:07.180 --> 00:03:14.800
messages, avatars, et cetera. So this is
quite an interesting feature for players,
00:03:14.800 --> 00:03:21.930
but also for hackers. So this is the
player point of view so you can send your
00:03:21.930 --> 00:03:29.209
messages and other people will be able to
receive them. But we'd like to - from an
00:03:29.209 --> 00:03:34.510
hacker point of view - we'd like to
replace one of these systems with a PC to
00:03:34.510 --> 00:03:40.629
tamper with the protocol, for example. And
eventually it would be nice if we could
00:03:40.629 --> 00:03:48.021
send some corrupted messages and see if we
can get code execution on foreign systems.
00:03:49.621 --> 00:03:54.663
But for doing that, you need to know how
the street the StreetPass feature works.
00:03:55.845 --> 00:04:01.319
So it's quite simple. It acts like a mailbox.
So you have CECD, which is a system
00:04:01.319 --> 00:04:10.829
module, and it's the only one that manages
all this StreetPass feature. So all your
00:04:10.829 --> 00:04:18.370
applications have an inbox and an
associated outbox in the CECD file system
00:04:18.370 --> 00:04:27.320
and they can put and get messages from and
to these boxes via IPC. Then messages in
00:04:27.320 --> 00:04:32.390
these boxes are used to craft packets
which are then sent using the StreetPass
00:04:32.390 --> 00:04:40.610
protocol. And we can already see on this
diagram which path we could try to attack.
00:04:40.610 --> 00:04:47.220
The first one you might think about are
our application boxes because it's very
00:04:47.220 --> 00:04:53.750
likely that you'll be able to find some kind
of game or application that have a float
00:04:53.750 --> 00:05:02.890
parser. So we might take and get remote
code execution in such an application. But
00:05:02.890 --> 00:05:10.960
the most interesting one would be to try
to attack CECDs parser. And this would
00:05:10.960 --> 00:05:19.290
give us remote code execution in a system
module, which would be nice. But for doing
00:05:19.290 --> 00:05:25.060
that, we need to figure out how the
StreetPass protocol works and nobody
00:05:25.060 --> 00:05:31.069
really knows how it works. There is a bit
of documentation online about the
00:05:31.069 --> 00:05:36.419
pairings, so "oh both our systems are
seeing a hand here. Would like would you
00:05:36.419 --> 00:05:42.410
like to communicate with me?" But it has
never been successfully reproduced, at
00:05:42.410 --> 00:05:49.600
least publicly. And we know that it's
using an unknown and encrypted protocol
00:05:49.600 --> 00:05:58.900
that uses the secret AES key that we can
now get. So let's reverse the protocol.
00:05:58.900 --> 00:06:08.100
First, well, let's reverse the pairing and
replicate it. So it's fairly easy to
00:06:08.100 --> 00:06:15.360
understand: You have both peers, the
client and the master and before
00:06:15.360 --> 00:06:23.169
communicating they randomize their console
ID and their MAC address. Then the client
00:06:23.169 --> 00:06:32.460
sends a bunch of probe requests with our
bundle specific tag, containing a list of
00:06:32.460 --> 00:06:37.940
the applications that have StreetPass
activated. And then eventually the master
00:06:37.940 --> 00:06:45.110
received that public list and analyzes it.
It's checked if an application from the
00:06:45.110 --> 00:06:50.419
client that has StreetPass activated
matches one of it's own applications with
00:06:50.419 --> 00:06:55.680
StreetPass activated. If it's the case, it
sends the probe response to the client,
00:06:55.680 --> 00:07:02.160
which will do the same. And if both peers
agree that they can exchange data, they
00:07:02.160 --> 00:07:11.430
will start communicating after deriving a
common key. So replicating the pairing is
00:07:11.430 --> 00:07:20.810
not super odd if you know what tool to
use. I tried to reproduce the pairing
00:07:20.810 --> 00:07:28.470
using a monitor mode, but it's really hard
because you have to deal with all the
00:07:28.470 --> 00:07:38.009
action item frames et cetera. So I used
nl80211 which lets you register some
00:07:38.009 --> 00:07:44.470
specific callback for some specific frames
and send custom frames and everything is
00:07:44.470 --> 00:07:53.590
handled by your wifi adapter driver. So at
that point the 3DS starts sending
00:07:53.590 --> 00:08:00.827
encrypted data and we have to decrypt
them. So let's review the encryption. They
00:08:00.827 --> 00:08:09.979
do this in two passes, the first one they
use an HMAC-SHA1 over both consoles CIDs
00:08:09.979 --> 00:08:18.270
and both MAC addresses and the output of
this pass is used as an input counter for
00:08:18.270 --> 00:08:28.659
on AES-CTR using the AES key slot we can
now get. And the output of this encryption
00:08:28.659 --> 00:08:37.570
is used as a session key for the
communication. So nl80211 lets you
00:08:37.570 --> 00:08:45.530
register CCMP keys so it's quite easy to
send and receive encrypted packets using
00:08:45.530 --> 00:08:56.470
it. So now we can start reversing the
protocol. Let's take a look at the
00:08:56.470 --> 00:09:04.100
structure of packets before doing any
reverse engineering. So I put some packets
00:09:04.100 --> 00:09:09.544
I was able to receive and the first one is
one of the smallest one you can actually
00:09:09.544 --> 00:09:19.450
observe. So first you have a header and
then you have some data and you can spot
00:09:19.450 --> 00:09:26.830
some magic values here. Actually, it's
easy to spot them because CECD is using
00:09:26.830 --> 00:09:35.890
really recognizable magic values. It's
always the same byte repeated twice. Once
00:09:35.890 --> 00:09:40.520
you know the structure of the packets, you
can view that there are actually
00:09:40.520 --> 00:09:49.340
two protocols. The first one is SPTCP.
It's an equivalent of TCP, but for local
00:09:49.340 --> 00:09:55.380
communication. It's mainly designed to
ensure reliability and data segmentation.
00:09:55.380 --> 00:10:03.790
And then you have SPMTP which is built
over SPTCP and handles all the exchange of
00:10:03.790 --> 00:10:11.060
stricter data and StreetPass messages. So
we have two protocols and we need to
00:10:11.060 --> 00:10:18.290
review both of them. Let's start with
SPTCP. Actually, there is not much to say
00:10:18.290 --> 00:10:29.090
because you only basically have to reverse
and understand the header. You have a
00:10:29.090 --> 00:10:33.570
magic value and some constants. But the
most important field here is the flag
00:10:33.570 --> 00:10:39.100
field because if you can understand what
are the flags, you can understand the
00:10:39.100 --> 00:10:45.760
meaning of the packets you are sending and
receiving. And so you can basically
00:10:45.760 --> 00:10:53.710
understand the protocol. And fortunately,
in this case, they're using the same flags
00:10:53.710 --> 00:11:01.950
as TCP, so it was really easy to
understand the protocol and how it worked.
00:11:01.950 --> 00:11:13.590
And what about SPTCP security? Actually,
it's OK. I did not find any bug. But the
00:11:13.590 --> 00:11:19.140
attack surface is really small. We can
basically only tamper with the header and
00:11:19.140 --> 00:11:31.460
that's it. So SPMTP should be much more
interesting. Let's take a look at the
00:11:31.460 --> 00:11:40.420
structure of SPMTP packets, because there
are actually two different packet types.
00:11:40.420 --> 00:11:49.900
The first one is an info packet. It's
basically used in the handshake and it's
00:11:49.900 --> 00:11:56.920
only here to share information between
both peers. And then you have message box
00:11:56.920 --> 00:12:03.120
packets which are much more interesting
because they contain actual StreetPass
00:12:03.120 --> 00:12:11.360
data and you can even spot the CECD
message via magic value, which means that
00:12:11.360 --> 00:12:17.650
we actually reach actual game data and
SPMTP is the last layer of encapsulation
00:12:17.650 --> 00:12:26.050
of the whole protocol. So once you figure
out how SPMTP works, you can reimplement
00:12:26.050 --> 00:12:33.660
the protocol. So let's first review info
packets. There's a bunch of things in
00:12:33.660 --> 00:12:40.440
here. Many fixed size data like friend
codes, MAC addresses, et cetera. It's not
00:12:40.440 --> 00:12:46.750
much interesting when you're looking for
vulnerabilities. There are variable size
00:12:46.750 --> 00:12:51.560
data, which are much more interesting.
They are sending application lists,
00:12:51.560 --> 00:12:59.450
metadata lists, and it's much more
interesting because when you process them,
00:12:59.450 --> 00:13:06.260
you can fail your parser. And if there is
some vulnerability here, we might exploit
00:13:06.260 --> 00:13:14.720
them to get remote execution. So let's
take a look at one of this parser. This is
00:13:14.720 --> 00:13:23.700
a function that parses meta data lists. So
let's focus on the for-loop. They are
00:13:23.700 --> 00:13:33.740
actually copying a list of entries to the
stack. The destination is on the stack and
00:13:33.740 --> 00:13:41.110
they do not check the number of entries in
the list. So this is clearly a buffer
00:13:41.110 --> 00:13:48.420
overflow, but is it exploitable? Let's
illustrate this with a diagram. So this is
00:13:48.420 --> 00:13:57.130
a regular copy. So you have your packet
buffer. And you have memcopy called on
00:13:57.130 --> 00:14:08.770
each entry and everything's is all right
here. But if you had more entries, you
00:14:08.770 --> 00:14:15.690
have a bunch of entries, compete on the
stack, that overwrite a bunch of things.
00:14:15.690 --> 00:14:21.810
But there's a problem here, because the
packet buffer is not large enough for us
00:14:21.810 --> 00:14:32.680
to reach the return address on the stack.
So we are probably copying uncontrol data.
00:14:32.680 --> 00:14:39.430
So I was like, it's too bad, we can't do
anything with this, but let's check the
00:14:39.430 --> 00:14:44.900
buffer next to our packet buffer. Maybe
there are some control data in there. And
00:14:44.900 --> 00:14:54.260
actually, yes, it's this buffer just
next to the packet buffer, dedicated to a
00:14:54.260 --> 00:15:03.240
list that we sent just before. So actually
we can rewrite the return address. So, how
00:15:03.240 --> 00:15:09.940
do we exploit it now? On the 3DS, you have
the NX bit, but there is no stack cookies
00:15:09.940 --> 00:15:15.500
or no ASLR, so it's pretty
straightforward. You can just embed a ROP-
00:15:15.500 --> 00:15:22.790
chain, a small ROP-chain, and then send
another one in some kind of packets and
00:15:22.790 --> 00:15:31.230
stack-pivot to it. And then you get remote
code execution in CECD. So this one was
00:15:31.230 --> 00:15:40.350
quite easy. Let's move on to message box
packets. Message box packets are packets
00:15:40.350 --> 00:15:48.290
to send a list of StreetPass messages for
some specific applications. They are
00:15:48.290 --> 00:15:55.010
actually stored in some temporary files
for avoiding delays and they are parsed
00:15:55.010 --> 00:16:02.080
once the communication is over. So they
are parsed. So let's take a look at the
00:16:02.080 --> 00:16:15.370
parser. This is the function that actually
loads a temp file into an associated
00:16:15.370 --> 00:16:24.290
structure on the stack and whoops, they do
not check the number of messages in the
00:16:24.290 --> 00:16:35.010
box. So this is another buffer overflow.
You are basically overflowing the message
00:16:35.010 --> 00:16:43.050
pointers array and the message sizes
array. So let's treat this with another
00:16:43.050 --> 00:16:55.430
diagram. So you have on the right the temp
file and on the left the stack and you see
00:16:55.430 --> 00:17:02.001
that you have this structure on the stack
we can see that there is the message
00:17:02.001 --> 00:17:08.311
pointers with pointer pointing to your
temp file buffer and you have the message
00:17:08.311 --> 00:17:17.520
sizes. And if you add another message in
the temporary file, you overflow both
00:17:17.520 --> 00:17:26.980
arrays and start overwriting some data on
the stack. We are a bit concerned because
00:17:26.980 --> 00:17:31.830
we are writing partially or uncontrolled
data on the stack. Obviously you cannot
00:17:31.830 --> 00:17:39.440
control the message pointers and you can
not still control message size because you
00:17:39.440 --> 00:17:44.910
can not put some arbitrary values in
there. You'd have to send gigabytes of
00:17:44.910 --> 00:17:56.510
messages and you can not do that. So what
can we do? What you can see here is that
00:17:56.510 --> 00:18:02.490
you can actually set the last message size
to an arbitrary value because they are
00:18:02.490 --> 00:18:10.790
checking if the current message being
parsed is actually inside of the temporary
00:18:10.790 --> 00:18:15.810
file, a buffer. And if the current message
pointer goes out of the buffer,
00:18:15.810 --> 00:18:17.250
they break the loop
00:18:17.250 --> 00:18:24.110
without returning an error. So what you
can do is set the last message size to an
00:18:24.110 --> 00:18:30.200
arbitrary value and then the pointer will
go out of the buffer and you will write
00:18:30.200 --> 00:18:39.920
one 32-bit value on the stack. But we
need to know what to write. You cannot,
00:18:39.920 --> 00:18:44.990
unfortunately, you cannot directly
overwrite the return address because
00:18:44.990 --> 00:18:51.810
remember that we are writing mainly
uncontrolled data and reaching the return
00:18:51.810 --> 00:18:59.100
address would require you to overwrite the
whole stack frame with uncontrolled or
00:18:59.100 --> 00:19:07.890
partially uncontrolled data. So the only
thing I was able to rewrite without
00:19:07.890 --> 00:19:17.350
crashing the system is this particular
variable. It's a pointer to a critical
00:19:17.350 --> 00:19:26.150
section and it's used for signed
synchronization and mutual exclusion. And
00:19:26.150 --> 00:19:31.690
you can see it's used after the temporary
file has been parsed. So maybe we can do
00:19:31.690 --> 00:19:36.870
something with it. This is the leave_critical_section
call at the end of the loop
00:19:36.870 --> 00:19:42.910
iteration. And you can see that they're
using the pointer to decrement some kind
00:19:42.910 --> 00:19:49.320
of count. So it's basically the number of
threads that are using the critical
00:19:49.320 --> 00:19:55.970
section and we can override the lock
pointer. So by overwriting it, we can
00:19:55.970 --> 00:20:03.000
decrement an arbitrary value in memory,
but we need to find what to overwrite,
00:20:03.000 --> 00:20:12.860
that would give us more control of the
memory and control the execution flow. So
00:20:12.860 --> 00:20:18.690
I've been looking for something like this
and I found something interesting in the
00:20:18.690 --> 00:20:26.610
function that deinitialized the structure
associated to temporary files. This is the
00:20:26.610 --> 00:20:34.900
function for the structure
deinitialization. And you can spot this
00:20:34.900 --> 00:20:42.920
variable. They actually implemented
some kind of allocation mode. And if it's
00:20:42.920 --> 00:20:49.820
equal to pointer mode, it will not try to
free the pointer. The pointers in the
00:20:49.820 --> 00:20:58.480
message pointers array. But if it's not
pointer mode, they will free all of them.
00:20:58.480 --> 00:21:04.390
And while this value should be pointer
mode in any case. But we can decrement it
00:21:04.390 --> 00:21:13.850
using the the vulnerability we've seen
before. So we can get some pointer freed.
00:21:13.850 --> 00:21:22.380
And since we control everything at the
location pointed by message pointers, we can
00:21:22.380 --> 00:21:31.030
try to make it free some crafted and fake
chunks. But there is another problem
00:21:31.030 --> 00:21:38.950
because they're actually resetting the
allocation mode each time a temporary box
00:21:38.950 --> 00:21:48.290
is passed. So we have to find a solution
to this. And what you can do is try to
00:21:48.290 --> 00:21:55.410
make that function return early before the
allocation mode is restored. But this
00:21:55.410 --> 00:22:06.200
implies making it return an invalid return
code. But actually, it's not a problem
00:22:06.200 --> 00:22:15.690
because they're not checking the return
code. So what can we do so far with
00:22:15.690 --> 00:22:23.510
this? So you can send a first temporary
box. This will overwrite the lock variable
00:22:23.510 --> 00:22:29.920
in the stack and decrement the
allocation mode. Then you can send your
00:22:29.920 --> 00:22:38.460
invalid second temorary box and the
parser will return early and the
00:22:38.460 --> 00:22:43.090
message pointers array will not be
updated. And in the end, all the pointers
00:22:43.090 --> 00:22:51.370
in that particular array will be freed.
But since the message pointers array is
00:22:51.370 --> 00:22:57.750
not updated, the pointer in that
particular array are still pointing to the
00:22:57.750 --> 00:23:05.850
first temporary file buffer
which has been freed. That's not a
00:23:05.850 --> 00:23:11.580
problem. If you send a xecond temporary
box with the same size, the buffer will be
00:23:11.580 --> 00:23:15.760
re-allocated for that second
temporary file and we eventually free
00:23:15.760 --> 00:23:25.930
up pointers to control the buffer. So
what's next? We can craft some fake heap
00:23:25.930 --> 00:23:32.920
chunks. We can have the application free
them. What do we do? The free, yes, it is
00:23:32.920 --> 00:23:39.070
actually really insecure. You can exploit
the classic unsafe linker vulnerability,
00:23:39.070 --> 00:23:47.650
so you get one arbitrary write for each
chunk you can free. And you still need to
00:23:47.650 --> 00:23:56.730
know what to overwrite. But you can just
rewrite the heap free list head pointer. So the
00:23:56.730 --> 00:24:04.350
next malloc call will return a pointer to
wherever you want, and you can especially
00:24:04.350 --> 00:24:10.470
put a pointer to the stack in there. So
the next malloc call will return a
00:24:10.470 --> 00:24:20.990
pointer to the stack and it will be used
to store your third temporary file. So
00:24:20.990 --> 00:24:29.460
it's a bit hard to understand. So let's
again illustrate this with a diagram. So
00:24:29.460 --> 00:24:35.670
first you have your first temporary file
loaded in memory. So on the right it's
00:24:35.670 --> 00:24:49.440
parsed and the associated structure is
written in stack and it overwrites the
00:24:49.440 --> 00:24:57.510
lock pointer to make it point to the alloc
mode in memory. In the end,
00:24:57.510 --> 00:25:05.070
leave_critical_section is called. So you have
your temporary buffer freed and your location
00:25:05.070 --> 00:25:13.540
mode decremented. Then your second
temporary file is loaded in memory. The
00:25:13.540 --> 00:25:19.160
buffer used for the first
file is relocated and the pointers in the
00:25:19.160 --> 00:25:26.180
structure still point to our
controlled data and especially our fake
00:25:26.180 --> 00:25:39.480
chunks. So your second temporary file is
loaded and parsed. Then all the chunks are
00:25:39.480 --> 00:25:49.100
freed and the field it is at is moved to
point on the stack. And finally, you can
00:25:49.100 --> 00:25:54.360
see that your last temporary file is
read in on the stack so we can overwrite
00:25:54.360 --> 00:26:00.890
the return address and put a ROP-chain in
there. So this gives us a second remote
00:26:00.890 --> 00:26:10.070
code execution vulnerability in CECD. And
this one this one was quite trickier. So
00:26:10.070 --> 00:26:18.650
what's next? Another one. Yeah. Again,
there is another vulnerability in the
00:26:18.650 --> 00:26:29.880
message parser. It's actually an SDK
function. So any application that uses
00:26:29.880 --> 00:26:33.970
SteetPass is vulnerable, not only CECD but
all application and games that use
00:26:33.970 --> 00:26:36.360
StreetPass are vulnerable for this one.
00:26:36.360 --> 00:26:41.010
But I'm not going
to talk about it and explain everything.
00:26:41.010 --> 00:26:50.590
It's up to you to exploit it. So this
gives us a third Remote Code Execution in
00:26:50.590 --> 00:26:57.450
CECD and you can get Code Execution in any
application using StreetPass. And this
00:26:57.450 --> 00:27:06.260
also give us a persistent backdoor in CECD
because of CECD usually parses all the
00:27:06.260 --> 00:27:15.260
messages in the in and out boxes at startup.
So you can trigger the vulnerability
00:27:15.260 --> 00:27:25.270
once the system boots. So we've got a
Remote Code Execution in CECD, what can we
00:27:25.270 --> 00:27:34.730
do? No, actually, CECD does not have much
privileges. It's only a userspace
00:27:34.730 --> 00:27:41.090
application. And it's pretty well
sandboxed. You can not access the
00:27:41.090 --> 00:27:49.230
internet, for example or not the SD card.
So if you want more privileges and we
00:27:49.230 --> 00:27:57.131
want more privileges, you need to take
care of something else. And your
00:27:57.131 --> 00:28:04.980
best choice would be trying to take over
ARM11 Kernel, which is the kernel for the
00:28:04.980 --> 00:28:13.590
userland processor. This this would give
you total control over this processor.
00:28:13.590 --> 00:28:18.490
And if you want really full system
control, you'd like to also take over the
00:28:18.490 --> 00:28:25.600
ARM9 security processor. So this is the
processor that do all the encryption and
00:28:25.600 --> 00:28:34.590
signature stuff. And we will see this
later. So let's first try to take over the
00:28:34.590 --> 00:28:46.470
ARM11 kernel. But first, I need to
talk about IPC and especially
00:28:46.470 --> 00:28:55.640
what are called static buffers. So when
you are doing IPC, you need to sometimes
00:28:55.640 --> 00:29:03.460
send data from a sender process to a
receiver process and on the 3DS, you can
00:29:03.460 --> 00:29:12.170
do this in multiple ways. The first one is
if you want to send large regular
00:29:12.170 --> 00:29:20.020
buffers, you can map parts of the sender's
memory into the receivers, but you can
00:29:20.020 --> 00:29:27.020
also use what are called static buffers.
If you want to send some small buffers,
00:29:27.020 --> 00:29:34.670
the receiver can register static buffers
and the ARM11 kernel will do the copy for
00:29:34.670 --> 00:29:42.010
you to that particular buffer. And
sometimes you need some buffers
00:29:42.010 --> 00:29:51.870
to be sent to the ARM9
processor. So the ARM11 kernel need to
00:29:51.870 --> 00:29:59.000
write some pairs of
physical addresses and size to the static
00:29:59.000 --> 00:30:05.560
buffers because the ARM9 does not have an
MMU so it's only using physical addresses
00:30:05.560 --> 00:30:14.970
and the copy of data is eventually done by
the Process9, which is the only process
00:30:14.970 --> 00:30:23.760
running on the ARM9 side. So let's talk
about a vulnerability now. So it's called
00:30:23.760 --> 00:30:32.997
LazyPixie and it has been found by TuxSH.
So it's not me. How does the kernel handle the
00:30:32.997 --> 00:30:44.604
PXI buffers case because it
seems a bit complicated. So first
00:30:44.604 --> 00:30:48.790
they check the alignment of the
destination state buffer, they check the
00:30:48.790 --> 00:30:54.250
size of the destination static buffer.
They check the permissions for the source
00:30:54.250 --> 00:31:01.100
buffers. Then they do cache operations, they
copy metadata. So the physical address and
00:31:01.100 --> 00:31:09.480
the size of the static buffer
to the destination and then the copy is
00:31:09.480 --> 00:31:15.830
done by the ARM9 side. But I think
there is something missing here because
00:31:15.830 --> 00:31:23.870
they do not check the permissions for the
destination buffer. So what you can do is
00:31:23.870 --> 00:31:30.440
use an arbitrary address as a destination.
And so you can just overwrite the MMU
00:31:30.440 --> 00:31:37.860
table and make your kernnel read, write and
execute, which is obviously enough to take
00:31:37.860 --> 00:31:48.890
it over. So at that point, the ARM11
Kernel has fallen and we have
00:31:48.890 --> 00:31:58.740
the full control of that processor. But we
would like a bit more privileges because
00:31:58.740 --> 00:32:07.640
why not? We want the full system control.
So let's take the road to full system
00:32:07.640 --> 00:32:15.770
control and see why taking over CECD was
one of the best ideas ever. So I am going
00:32:15.770 --> 00:32:22.410
to talk about SAFEHAX. Maybe some of you
know what SAFEHAX is because it's a really
00:32:22.410 --> 00:32:31.870
cool vulnerability. It's actually race a
condition in the firmware header parsing
00:32:31.870 --> 00:32:38.410
you can take over the ARM9 side if you
control the ARM11 kernel. It has
00:32:38.410 --> 00:32:47.170
been fixed in the system version 9.5 for
the regular native firmware
00:32:47.170 --> 00:32:52.020
and fixed in the safe mode firmware, which
is basically the recovery firmware if
00:32:52.020 --> 00:32:58.330
something went wrong for your console. So
people have been exploiting it both on the
00:32:58.330 --> 00:33:04.780
native firmware and the
safe mode firmware and it has been
00:33:04.780 --> 00:33:12.960
mitigated in version 11.3 and 11.4. So it
does not work anymore, but it has only
00:33:12.960 --> 00:33:19.800
been mitigated and not patched. So let's
take a look at that mitigation because
00:33:19.800 --> 00:33:26.559
how do they prevent us to exploit that
vulnerability? So this so-called
00:33:26.559 --> 00:33:36.820
mitigation is a boolean flag that has been
added on the ARM9 side and when it's set to
00:33:36.820 --> 00:33:48.559
1 the system just panics. When you try to
launch the safe mode firmware. So this
00:33:48.559 --> 00:33:53.140
flag is actually set to 1 whenever you try
to launch an application, so this was the
00:33:53.140 --> 00:33:59.490
usual way to exploit it, you were
launching the homebrew menu through an
00:33:59.490 --> 00:34:07.070
application and then exploiting the ARM11
kernel and then running SAFEHAX. So they
00:34:07.070 --> 00:34:13.549
set the flag to 1 whenever you try to
launch a specific application, except some
00:34:13.549 --> 00:34:22.240
of them because your reconnection ARMs needs some
applications to run. So this is there is
00:34:22.240 --> 00:34:29.270
an exception for the home menu and the
system modules. And guess what? We are
00:34:29.270 --> 00:34:35.270
exploiting CCD, which is a system module
and we are getting Remote Code Execution
00:34:35.270 --> 00:34:43.090
in CCD. So the the flag is never set to 1
when we are getting code executing on the
00:34:43.090 --> 00:34:52.630
CCD. So with that kind of exploit. You can
easily replicate the initial SAFEHAX
00:34:52.630 --> 00:35:02.830
exploit. So then you get a full control,
remote code execution without any user
00:35:02.830 --> 00:35:10.130
interaction. And it's StreetPass and it's
doing all of this thing in the background
00:35:10.130 --> 00:35:16.320
and on any firmwre version at the time
this was developed because Nintendo
00:35:16.320 --> 00:35:28.520
patched it with firmware version 11.12. So
I guess it's time for a little demo. I'm
00:35:28.520 --> 00:35:37.550
not going to do it live because I don't
want to some exploits in the air. So I
00:35:37.550 --> 00:35:46.300
have a little video. So I'm running my
exploit on my laptop and you can see the
00:35:46.300 --> 00:35:52.850
LED is turned on to see that the exploit
is running in CCD. And then you once
00:35:52.850 --> 00:35:59.700
you're you can exploit and you can launch
the installer for the Boot ROM exploit,
00:35:59.700 --> 00:36:10.460
for example.
applause
00:36:10.460 --> 00:36:24.140
Thanks. So now, some some takeaways. Well,
you'd better check your return value,
00:36:24.140 --> 00:36:28.960
really, because there's a second
vulnerability would have been really,
00:36:28.960 --> 00:36:41.800
really out to exploit without that
mistake. And really, you should not hide
00:36:41.800 --> 00:36:47.910
behind cryptography because one day your
encryption will be broken and this might
00:36:47.910 --> 00:36:59.650
come sooner than you think. And for this
specific case, there was a bunch of dumb
00:36:59.650 --> 00:37:09.190
mistakes and basically all vulnerabilities
were only buffer overflows. Then,
00:37:09.190 --> 00:37:16.900
assessing hard-to-reach features is really
arduous. I spent a lot of time doing this,
00:37:16.900 --> 00:37:26.480
especially figuring out how to replicate
all the features, parts and all the
00:37:26.480 --> 00:37:32.830
different protocols involved. But
eventually, you can get some really
00:37:32.830 --> 00:37:41.090
interesting results like this. Then, I'd
say please fix your flows, and do not
00:37:41.090 --> 00:37:50.760
implement some poor mitigation, like for
SAFEHAX. And there's things still to do on
00:37:50.760 --> 00:37:57.340
the 3DS. I think I was able to show this
today. There is, this is an amazing system
00:37:57.340 --> 00:38:03.830
you can start to work on and do some
practical things. And there's still things
00:38:03.830 --> 00:38:13.490
to document on the open source wiki, so
feel free to contribute. So, in the end, I
00:38:13.490 --> 00:38:25.220
would like to thank @TuxSH for the
LazyPixie and helping me getting this full
00:38:25.220 --> 00:38:39.270
chain exploit done, and @hedgeberg for
recurring support with a lot of things. So
00:38:39.270 --> 00:38:45.230
now, if you have some questions, feel free
to ask.
00:38:45.230 --> 00:38:50.930
Herald: Thank you very much.
00:38:50.930 --> 00:38:54.640
applause
00:38:54.640 --> 00:39:02.080
Herald: We are very, very much on time. So
ask any questions, but please do ask them
00:39:02.080 --> 00:39:13.609
at a microphone. Go ahead. No, I thought
there was going to ask a question. No
00:39:13.609 --> 00:39:21.200
questions? Oh, the Internet has one.
Great.
00:39:21.200 --> 00:39:29.230
Signal angel: So, yes, we have two
questions. The first one is what tools and
00:39:29.230 --> 00:39:34.220
environments do you use for your research?
For example, someone mentioned how do you
00:39:34.220 --> 00:39:40.970
get all the source code?
nba::yoh: Oh, everything on the 3DS is
00:39:40.970 --> 00:39:50.410
closed source. So you have to reverse
engineer everything. I used IDA and Ghidra
00:39:50.410 --> 00:39:57.390
to reverse the binaries of CCD and, yeah,
that, that's it.
00:39:57.390 --> 00:40:08.320
Signal angel: OK. Thank you. We have a
second question: Is there any procedure
00:40:08.320 --> 00:40:13.200
for the Switch that is compatible with all
what you've done?
00:40:13.200 --> 00:40:16.109
nba::yoh: Sorry, could you repeat that
question?
00:40:16.109 --> 00:40:23.330
Signal angel: Well, all the things you
have done, all the code. Is there anything
00:40:23.330 --> 00:40:28.430
similar for the Switch?
nba::yoh: I don't think there is something
00:40:28.430 --> 00:40:37.420
similar on the Switch, at least something
that looks like the StreetPass feature.
00:40:37.420 --> 00:40:44.420
But I don't really know how the Switch
works, I've only done things on the 3DS.
00:40:44.420 --> 00:40:51.930
Herald: OK, first question for the room.
Microphone: Thanks for the talk, great.
00:40:51.930 --> 00:40:57.800
Did you really need all the three
exploits? And which one did you use in the
00:40:57.800 --> 00:41:03.450
end for the full chain? Thanks.
nba::yoh: Could you repeat the question?
00:41:03.450 --> 00:41:07.870
Microphone: Did you need all the three
exploits that you had or could you just
00:41:07.870 --> 00:41:11.990
use the easiest one? And which one did you
use in the end?
00:41:11.990 --> 00:41:19.650
nba::yoh: Well, no, you do not need all
three exploits, at least in CCD. You only
00:41:19.650 --> 00:41:30.369
need one basically to get remote code
execution. But I found it fun to just show
00:41:30.369 --> 00:41:35.570
all the exploits for CCD.
Herald: Next question.
00:41:35.570 --> 00:41:40.080
Microphone: Are the StreetPass messages
passed to the applications even when those
00:41:40.080 --> 00:41:44.030
applications are not running? So, for
example, when you have like Pokémon or
00:41:44.030 --> 00:41:46.670
something installed...
nba::yoh: Could you speak louder, please?
00:41:46.670 --> 00:41:51.260
Microphone: Okay. Are the applications
parsing the messages even if they are not
00:41:51.260 --> 00:41:55.450
running? Like, is there some sort of a
handler being run by the OS even if you
00:41:55.450 --> 00:41:59.930
don't have an application running, just
installed? So that if you have a
00:41:59.930 --> 00:42:06.150
vulnerable application with the old SDK
built in there, will it automatically
00:42:06.150 --> 00:42:15.050
parse the corrupted message?
nba::yoh: Could you reformulate your
00:42:15.050 --> 00:42:19.050
question? I don't understand.
Microphone: Okay. In your tree
00:42:19.050 --> 00:42:24.930
exploitation method, you mentioned the
third method that mentions the SDK being
00:42:24.930 --> 00:42:26.930
broken.
nba::yoh: Yeah.
00:42:26.930 --> 00:42:31.490
Microphone: And if you have an application
built with that old SDK, does it
00:42:31.490 --> 00:42:36.280
automatically parse the message even if
it's not running, so that even if you have
00:42:36.280 --> 00:42:41.390
a patched OS, but not patched
applications, it will still get exploited?
00:42:41.390 --> 00:42:49.001
nba::yoh: Yeah, all the applications using
the SDK should be updated to fix the
00:42:49.001 --> 00:42:59.950
vulnerability. So the exploit is triggered
when the application parsed the messages.
00:42:59.950 --> 00:43:10.541
So you have to run the application to
exploit it. CCD has been patched, so there
00:43:10.541 --> 00:43:20.930
is no more remote code execution in CCD,
nor a permanent backdoor in CCD, that
00:43:20.930 --> 00:43:29.160
automatically runs, when the system is
started. But you can probably still
00:43:29.160 --> 00:43:34.430
exploit games and applications that use
the old SDK.
00:43:34.430 --> 00:43:39.160
Microphone: Okay, thanks.
Herald: There's a question over there.
00:43:39.160 --> 00:43:44.099
Microphone: Yes. Can you go back to the
slide where you showed how the encryption
00:43:44.099 --> 00:43:46.610
for the packets worked?
nba::yoh: The encryption?
00:43:46.610 --> 00:44:12.359
Microphone: Yes, the encryption. Yeah.
Yeah. That one. So my question is, if all
00:44:12.359 --> 00:44:18.720
you're, if the only thing that you're
changing is the counter, and the data is
00:44:18.720 --> 00:44:24.160
constant and the key is constant, and it's
CTR, then you're basically just XOring a
00:44:24.160 --> 00:44:33.770
known block with your HMAC output. So why
do you even need the key here?
00:44:33.770 --> 00:44:42.910
nba::yoh: Well, the counter changed every
time you start a new StreetPass
00:44:42.910 --> 00:44:50.440
communication, because the CID's are
randomized and the MAC address is, the MAC
00:44:50.440 --> 00:44:55.560
address is also randomized before starting
a new communication.
00:44:55.560 --> 00:45:01.270
Microphone: Right. But I guess what I'm
asking is, why do you need key slot 2E? In
00:45:01.270 --> 00:45:08.310
my mind, having the CCD HMAC key would be
enough, because you can just XOR the, you
00:45:08.310 --> 00:45:13.920
know, output of that with the final
output, and that removes, you know, the
00:45:13.920 --> 00:45:20.280
CTR part, and now you have the raw output
of the null block encrypted with key slot
00:45:20.280 --> 00:45:27.109
2E, which is always going to be constant,
and then you can just XOR whatever output
00:45:27.109 --> 00:45:32.600
to get the final result, right?
nba::yoh: Yeah, well I'm not super
00:45:32.600 --> 00:45:41.560
familiar with all the cryptography, but
maybe we could talk about it. I was just
00:45:41.560 --> 00:45:50.770
putting this for, for people to reproduce
it if they want.
00:45:50.770 --> 00:46:01.580
Herald: Okay. Are there any more
questions? Thank you so much.
00:46:01.580 --> 00:46:03.550
nba::yoh: Thanks.
00:46:03.550 --> 00:46:04.550
applause
00:46:04.550 --> 00:46:07.635
postroll music
00:46:07.635 --> 00:46:29.000
subtitles created by c3subtitles.de
in the year 2020. Join, and help us!