*33C3 preroll music*
Herald: Good evening, everyone. In a few minutes, the Nintendo Hacking 2016 talk
will start. This talk will will be translated into German, and there are
English subtitles available. Anyway, without much further ado. These are
derrek, naehrwert and nedwill. They are three students that have been working on
hacking Nintendo platforms for a while now, and please give them a warm applause.
*applause*
naehrwert: Hi guys. So, welcome to our talk about Nintendo Hacking 2016. Let me
quickly introduce the other guys. This is derek, and that's ned, and I think I can
speak for the three of us to say that I am really happy that you guys are here today
and we are happy that we can be here today to tell you everything about what we did
in the past one and a half years. I will start with the state of the Wii U. I hope
a lot of you guys have seen failOverflow's talk in 2013 about hacking the Wii U. Not
much happened afterwards, until 2015 there is a public webkit exploit released and
this time we started looking into the Wii U. And, we wanted more access, right? Than
just user mode and because there is also the kernel running on a PowerPC and then
there is this other ARM processor that runs IOSU. Also user mode and kernel mode.
I am not going to consider the user mode today. Because I think there are currently
exploits that are way more fun. So, let's start with PowerPC kernel very quick. It
has all standard basic security measures, though it doesn't have any ASLR which
makes our lives easier. It has about 140 syscalls. And we don't really.. We can't
really name them from start, right? Kinda need to reverse them. But there's a nice
thing. So, the Wii U uses this RPL mechanism for dynamic libraries. And
there's this really nice library. It's called coreinit.rpl and it contains a lot
of syscalls, shims and symbol names. So we can name all syscalls straight away
without much hassle and, it is important to know that all the syscalls use the safe
copy in/copy out mechanism to get data from the user space into the kernel space.
So we start reversing each syscall and we start looking for bugs And what we came
out with, at first, this is what we call I/O controlled VHAX Or, why indirections
are hard. It's actually a bug in the IPCKDriver_SubmitRequest syscall so what
this syscall is used for is: you want to submit requests from user mode to this
other processor running which I'm going to talk about later. And, so you submit this
kind of request structures and the kernel uses copy in to fetch the request
structure from user mode into kernel mode but there's a certain type of request
structure which contains an indirection like a second layer, right? And, well,
they just ignore that for the second level and hope for the best. So, let's look at
the relevant part. I'm really sorry I'm showing you this code here, but it's not
much more than that. So, there is something that is called ios packet in the
second line which is kind of this request that we submit from user mode into kernel
mode And in the top line there's this special request entry, so it contains a
physical address, a buffer size and a virtual address. And what we do from user
mode is we submit it filled out with the virtual address and the size. and the
kernel does this convenient thing for us. It kind of.. changes the virtual address
to the physical address. So we can see, it copies in these packets from user mode
into kernel mode using the safe mechanism and then it goes through all the entries
and fixes up the physical addresses for us but we can see in this line that it
doesn't use to the safe mechanism at all it doesn't care about whatever address we
put in there so this gives us some kind of right primitive to wherever we want
basically and this looks hard to exploit, right? Because the right kind of going
through this conversation but we actually only need one byte to exploit the kernel
and we do this by noting that this KIEffectiveToPhysical conversion function
actually returns 0 for any garbage input we get and there's a pretty high chance of
the input to the function to being garbage if we point to any part inside kernel data
so the strategy here is that we go into syscall handler address table and we
overwrite the last byte for one particular syscall handler and we hope that the new
address actually points to some usable gadget so we hope for the best basically
and the other important thing to note here is that our user mode code is running from
what we call the JIT area and what's really stupid is that the JIT area is
actually executable from kernel mode for some reason so that's nice too. Okay,
let's look at the relevant structures so this is the kernel and we should read this
from the bottom to the top. Ok, like in the last line the button we see this entry
to KeLoaderCall and then we can look at the last byte there it's hex F0. And what
we will do now is overwrite this last byte with 0 and what happens is that now this
syscall will actually point to this very usable gadget up there where it loads
this register r28 into the link register and just branches there the nice thing is
that we control our 28 from user mode so this gives us a way to just jump anywhere
basically so how do we exploit this. Well, we have our k-mode function there then we
just call ioctlv to this shifted address and from this point on we have this nice
syscall that just comes to anywhere we want and then we call it basically and
this calls our k-mode function. So, the Wii U starts out with full four hearts and
this gives us PowerPC kernel mode code execution so we subtract one hard and it's
quite nice but we can and need to go deeper and for that let's look at the IOSU
architecture. So IOSU is present as one big ELF file and this includes the kernel
and all the services and it's running on the Starbuck it, has a hardware way to
enforce no execute and again no ASLR, making our lives easier and it's a
microkernel design that has about a 140 syscalls so another thing to notice that
the kernel spawns all these services as user mode processes so before we can
exploit the kernel we actually have to exploit one of these user mode processes
which we did but i'm not going to talk about and to look into the kernel, we
began by reversing all of the syscalls and search for bugs and what we came up with
is called MQHAX or message queue hax it contains another nice bug class that
apparently never dies. Integer overflows. And let's look at the code again so
there's this syscall, it's called create message queue you pass it a buffer and a
number of buffer entries and what they assumed was that each buffer entry is four
bytes so when they check the address range to just multiply the number of entries
with four bytes so does anyone see the integer overflow here and then a nice
thing is that it just to use the number of entries for the maximum number of entries
for the message queue and our right primitive again is the send message
syscall. So, I told you about this hardware NX right? So IOSU should be
enforcing that no executable memory is writeable and if you look at the kernel
section flags we actually see that KERNEL_TEXT is read execute and
KERNEL_DATA is read-write but these permissions are all lies. Ok so our
exploit strategy: well, let's look at the relevant part of the IOSU kernel so we see
that KERNEL_TEXT starts at this lower address, at hex 0x08120000 and
conveniently for us there is a syscall there and the addresses before that are
all valid so we create a message queue, I'm starting at minus eight bytes and this
magic hex 0x400- whatever-2 number and from this point on we just push two
messages and then ARM instruction to branch out three and what this does is it
actually causes the start of text section to be overwritten with branch R3 and let's
just look at the integer overflow right four times this value truncated to 4 bytes
gives 8 bytes so what kind of things is that the message queues is only bytes but
we can just push any messages we want ok so this gives us IOSU kernel-mode
execution and the nice thing about this is that we actually have full control over
the console unit now right so we can dump the console's OTP which contains all the
keys except for boot1 which we will come back to later because unfortunately the
pieces for boot1 are locked out as we have already seen. And now we want to make
everything persistent so how do we do that? We find that title content is only
verified at title install time but never at boot time because at boot time they
only verify the title binary so what you can do is you can actually start to mess
with the metadata of titles and overwrite it and what we did was to overwrite the
ROM for a DS game, exploited the emulator and got user mode code
execution again and another thing is that the console contains this config file
which tells it to boot into which title to boot so what you can do is you
overwrite the title ID with your modified DS emulator title and the next time you
start up the console it actually boots into the exploited game and yeah so just
gives us persistent code execution and cold boot with full control over to
console whatsoever so game over
*applause*
derrek: So, as we just saw, the kernel it's like pretty broken, right? So, what
is missing and I just copied this slide from failoverflow's talk as you can see we are
using the same d14 thing for our slides and basically the boot1 key which is the
second stage bootloader on Wii U and this key is still unknown and they tried to get
it somehow with some side-channel attacks thing but I think it never worked
so it would be nice to get this key and the first thing we did was to make a NAND
tracer so we can basically sniff all the traffic between NAND and boot1 to see what
boot1 reads from flash and so we get some nice addresses and we could compare this
with the file system on the / to see what file it is reading and we also kind of
mess around with some files on this file system and we found out that boot1
actually parses a file that is called system.xml and I don't know, it doesn't
really feel safe to parse an XML file in such a really early boot process I mean
there's a lot of stuff that could go wrong. So, we tried to attack this and we
tried some blind exploitation stuff but yeah unfortunately it didn't really work
so let's try something else. So, there's boot1, which of course boots this.. Sorry
we've got boot0 and this boots boot1 and failoverflow found out that this boot0
which is a bootrom of the security processor can be re-enabled again in
virtual Wii mode and you can just dump it so let's look at boot1... boot0 I'm sorry
and we can see that it reads boot1 key from OTP and then it locks out boot1 key
forever and this happens really early but it's basically kept in memory all the time
until it's done until it has launched boot1 or just panicked. So, this means
that we have to exploit boot0 to get the boot1 key and unfortunately, boot0 is
pretty safe it's kind of surprising because this is Wii U and basically this
gives us this question: How can you exploit something that has no bugs? So,
the answer is we have to introduce our own bugs - *laughter* - and we're doing this
by using fault injection and maybe you have heard of it already it's basically
you introduce an error into device by a glitching the clock, voltage, the reset
line you can also do electromagnetic injections. There are many ways. But
basically what you want to get is a mutated instruction, or instruction skip
or some corrupted registers and what you don't want is just a stupid lock up where
it just crashes and yeah that's all really useful so we want to glitch boot0 and to
do this we have to find a nice target like the weak spot of boot0 so let's take a
look what boot0 does first thing it does is it copies itself to ram for some
unknown reason I mean there's no good reason to do this but it's nice for us
because it copies itself to RAM and just executes from there and then it copies the
boot1 key to memory it locks out the auto key slot initializes some other stuff and
flash controller and then it starts reading the boot1 image and it does that
by just reading its header to this address and then they read the size from the
header field and they also do some max size check on this and please note that
the header itself is not encrypted and they also don't do any signature
verification here at this step so they use the size and reads the whole boot1 image
using size and then they do a real signature verification to make sure that
the image is not corrupted it then decrypts the boot1 code using the key from
RAM and then it clears the key and jumps to boot1entry point ok so what is the weak
spot here and I mean if you look at this you can pretty much already tell what it
is and of course it's this size check so what we can do is we can write our own
modified version of boot1 into flash with some really really large size in the
header so it reads the header and then it's supposed to do a size check and this
is exactly where we wanted to glitch it and eventually it will just skip the
instruction or something else happens and then basically the size check is bypassed
so when it's reading the boot1 image using this size it will actually overflow the
buffer and we have some jump instructions at the end so when it returns from the
flash read function it will eventually jump to our code and this is actually
boot0 code execution
*applause*
ok so we have boot0 code execution and you know we can just dump the boot1 key from
RAM and we didn't even need an exploit for this right so it's just boot0 is actually
pretty safe right but when it comes to pitching it's kind of fragile
because boot0 code is writeable and also the boot1 image buffer is in front of boot0
buffer so we can just overflow it and also the setup that I had was also surprisingly
stable so it works like fifty percent of the entire time so let's finally look at
boot1 and boot1 is able to understand the Wii U file system it uses real file path
strings to load the firmware image and of course the first
thing we did was to look at the xml parser and well unfortunately it seems pretty
safe and yeah but maybe we found a bug we're not really sure and we haven't
really tried to exploit it. Interest kind of faded out because you know it's after
all it's just the Wii U so that's it for Wii U and now I will hand over to nedwill.
He's talking about 3DS
*applause*
nedwill: Hi, everyone, I'm ned. I started 3DS this year and I'm basically a software
person so I'm going to be showing some of the homebrew side of 3DS where that's at
right now so just to reiterate from last year these guys broke userland, kernel and
the security processor they also broke the secret hardware key scrambler and since
then Nintendo has been kind of mad about this they released a lot of system updates
and they started a bug bounty program so there's a lot of bugs getting patched but
because of the amount of the level of exploitation we got last year it's
actually really easy to find new bugs and exploits so what I want to emphasize here
is that even though it's like a cat-and-mouse game because we have so much
control we can exploit more difficult books on the latest firmware so starting
with user space. This is where all homebrew comes from so already it's pretty
good like this has always been a huge focus for the homebrew community because
it's kind of where you know user space is where you want to be running your own
custom games you know modifying stuff so we have a bunch of game entry points and a
bunch of browser exploits but there's a couple limitations to leads and that's
that game carts cost money and they frequently are.. like the games that are
exploited are usually somewhat rare and unusual and so the price goes way up as
demand soars and for the browser every time we release a new browser exploit,
Nintendo can actually enforce that you're on the latest firmware, because before we
fetch any web page it will check that the system is on the latest version. So, they
can kind of remotely cut off web browser exploits. So looking at this I thought it
might be fun to look at if any of the system titles can be exploitable as
primary entry points and I found something called SOUNDHAX so just the basic like the
two probably most obvious things to look at are the image loader because it's got
JPEG parsing and also the music player. But, when I looked at the music player I
saw that they're parsing actually a lot of formats and maybe even have their own
custom playlists format and if they make a single mistake anywhere it's it's over so
then I was trying to compare with like open source implementations I didn't find
any overlap. It seemed like everything was custom. So that was pretty promising. So,
over the course of about a month, I found a bunch of bugs and I was trying to like
chain together little like logical bugs and it wasn't really working and then I
just found one that was really critical. So, I'm going to demonstrate that here.
So, actually studied mp3 for the whole month MPEG was like the
last day so I looked at it and they actually malloc 256 byte buffer for the
song name and then when they go to load it if they see a unicode BOM marker they just
memcpy the thing and that tag size is totally controlled so you know that's
that's it so this is like it was pretty great but it's a few pics place that's a
little tricky but this is what it looks like so we have our name chunk that we're
about to overflow and then like I'm a CTF player, so I put A's there and then the
next thing that happens is this gets freed and so this victim chunk that we have
overridden it's actually the way the 3DS heap works they actually track they have a
linked list of what things are currently allocated so this gives us the classical
heap unlink arbitrary write and so at this point we have a 4-byte write and we want
to get ROP out of it so we'll probably do a stack pivot so I looked at the binary
and there's only one pivot gadget and then i looked at the the thumb pivots, there
are actually a lot but because this CPU was too old didn't support the wide
instructions where all the pivots come up so unfortunately that one pivot
instruction has some arithmetic conditions on it specifically it was that in order to
you know load all your registers from memory the condition flags had to satisfy
less than and everywhere where we return from the function it had just checked that
like if this pointer is not null free it and so the comparisons wouldn't ever be
satisfied because nothing is mapped up in the negative area so of course CTF
workarounds. We can still do this so I overwrite the heap freelist head with the
stack address and so on the next malloc we just return that stack address and read
into it so there's a couple of constraints on this and the first one is really normal
like this is every pivot to stack heap thing you have to make sure that you have
a heap chunk on the stack and luckily this is actually pretty easy because all you
need is a size followed by two null pointers representing next and previous so
when malloc goes to look there it seems like the size is big enough and then
nothing else is in the queue so just return this and then this worked so we
memcpy the next tag to the stack and like we just specify that size and malloc some
*unintelligible* for us and then from there we're done because we can just do a
little little ROP chain, we memcpy the shellcode to the heap and then use an
existing exploit gspwn which has been around for a long time to override the
text section and jump there so there's the first heart so you can't really talk about
homebrew without also talking about kernel because we want to get access to more
syscalls like the 3DS actually sandboxes a lot of the syscalls away from you and so
as an attacker, your goal is to call some syscalls that are restricted a really nice
example would be you want to map some executable memory for like a JIT emulator
so it's kind of a tricky situation because you're inside the sandbox you want to
break out you have to find bugs in like pretty restricted syscalls so I looked at
last year's talk here and like what had been done so far and it seemed like there
are a lot of attacks on that memory mapping but I didn't see much about the
sync primitives or anything related to use after free and i had just got a pretty bad
grade on my OS project because i had a lot of those so I knew this is a good place to
look so I noticed the design flaw when I was reversing the ref counting so it's not
so much that they couldn't possibly get this right but generally when you're
designing an API you want to make it really hard to abuse and this is just not
really true for how they do ref counting so I'll go ahead and bring these up yeah
so basically they whenever the user fetches a kernel object to perform some
operation on it meaning you call this syscall that does something using the
current object it does the correct inc ref and then dec ref for you but I was looking
at it and thinking well like a lot of times the kernel actually is using these
objects internally to do stuff so I mean I spelled it but like I mean I was like a
week I found like 3 use after frees and they're all following the same pattern.
The kernel's using an object internally without maintaining the reference count
correctly and then some people ask me like advice on kernel hacking maybe like at
home I definitely recommend looking here I'm sure that there's plenty more so the
one going to talk about today is the the timer object so this is a pretty simple
API with the kernel you can have it create a timer for you you can set the timer you
can wait on it it's like a normal synchronization primitive so like I said I
was looking for these use after frees I saw this I thought it's kind of
interesting that this one called pulse is here because what's happening with this
one is when you set the timer to pulse like every period it's signaling
everything that's waiting on it and then it like resets itself and then if you wait
on it the next period comes around you get a signal again and so was thinking like
it's definitely doing some stuff with this object internally that's like a bit more
complicated than some of the other modes and the other kernel objects so i looked
at how they did the pulse like you know every every second whatever, when it
pulses like what's actually getting executed and if you look here they do some
pretty good locking and then they signal and then what happens here is basically
when they signal they go through and everyone that was waiting gets rescheduled
- made runnable - and then at the end they reset the timer state and just say like
okay everyone that waits on this again has to wait for the next cycle so and then
this also looks pretty good like they they're locking the scheduler here this
would work but nothing is preventing you from just closing this from another call
so I have FASTHAX which is just 3 syscalls and that's it. That's the entire exploit
there's a lot of setup which we will get to but you just create the timer set it to
run really fast and then close the handle and then if it was pulsing and you closed
it it will use after free so what's nice about this is if you lose the race it's
just the timer is just on schedule you're fine and then it actually happens quite
often and I didn't even really specifically try to win this to like I
just.. Once it was within a second I don't worry about those parameters are probably
not optimal so we should look at how do we exploit this basically this is a little
bit of a more complicated view of it. I'll show a diagram in a second but this is
like where the use after free actually happens so like r7 is pointing to my timer
object and then it was freed before we reach this chunk here and then it's
loading r7 to r0, loading something from that and then branching to it so that's
like calling a use after free object. So, this is pretty exploitable on the 3DS
kernel because they use a slab heap to deal with allocating objects so this is the
normal situation when that first timer is allocated the vtable is pointing to the
you know the real KTimer vtable and then it wants to call that timer reset
function. It's totally fine but when we free it actually, that vtable pointer goes
to the next free timer object in the kernel so it's actually interpreting that
struct as a vtable and what's nice is it actually overlaps with the initial timer
value that we totally control and so it looks like okay we can just set the
initial timer value you know do this use after free, we're just calling user space
that's what I thought and then realized it wasn't that easy so because the race like
it because I was actually calling this is in a kernel thread we actually can't
guarantee that our user process is actually mapped in memory and in fact it's
on a different core so even if you open a process in the other core like ran a
thread there you can't get more than twenty-five percent of the time I think so
that's just super unstable also because it's a kernel thread we don't necessarily
want to crash it and we don't like crashes in general but this will just totally
break everything if the timer like sync thread dies so as long as we return to a
function do something cleanly, return it will be fine so it sounds like okay all we
have to do is find some kernel function we can call and we're done but there's
actually another issue and that's that kernel code is mapped at high addresses
and these are actually negative and that the set timer syscall actually checks if
your timer is negative so there's a pretty funny trick I found and that's that when
you set the timer you're saying like you know start I like one second from now
start pulsing obviously it's adding like the current time to the one second to know
like when do i trigger this timer so so SetTimer is the one that does that add for
you they don't check for overflow when installing it and timer schedule values
are signed which is also a bit weird so we can overflow and schedule into the past so
how this looks is that's my like disgusting set up call so what's happening
is like in the middle that's the start of the 3DS boot and then that range on the
right is what the 3DS will allow you to pass for your values for the initial and
like pulse period time and so what I do is I just put it right there at the end and
then it overflows and then on the next pulse I also control that and that's also
less than that range so then we can get it to line up on the kernel address we want
and so that's pretty good. Unfortunately, we're at the end like at this point is
pretty solid but there isn't like an obvious single thing we can call and it
seems like maybe you could race a bunch of times and call a bunch of different things
in the kernel and like you know that's a decent amount of control but because of
all this weird negative scheduling stuff it's actually pretty hard to do multiple
calls so I was trying to look for one thing that I can call that will give me
control and this is where it gets really tricky so if we look at how the memory
mapping on 3DS works in userspace you can access the FCRAM which is that first range
up there that's just where you know your heap goes there and then the kernel also
has a view of this heap it's you know a shared mapping so if we can write one of
those something in that range into the free pointer and allocate it, it actually
ends up in something we can see as the user so then I noticed this.. This is
actually a common instruction prefix in ARM so I jumped here and at this point
like we just did in C++, a vtable call on the use after free thing with one argument
so this means that r0 contains the address of the object and r1 contains the address
of where we just jumped to so that uh like B65C [0xFFF1B65C] is where r1 is pointing
so this is actually like some random linked lists lookup function but it's
actually looking down to the add instruction and loading it to r1 and then
we write that to the object and so at this point it looks like this it's pointing to
something in user space and then we just alloc two times we can look in user space
so they put the object there you control the vtable and from there it's pretty much
standard straightforward thing. So, there we go *unintelligible* userspace in kernel
and this is almost game over one more time
*applause*
derrek: So we've broken several parts of
the 3DS firmware including 3DS kernel and all software that's running on the
security processor what we haven't looked at yet are the 3DS bootroms and I'm
basically there's one bootrom for each processor for the ARM 11 and for the ARM 9
and I think there's probably, there are more bootroms in 3DS system-on-a-chip used
to for old Nintendo DS mode but we will focus on the 3DS bootroms here and what we
know is 3DS is somehow loading the firmware image from NAND flash and we also
know that the ARM9 bootrom does all the interesting stuff because only the ARM9
has access to the whole crypto hardware like the AES engine, RSA engine we also
know that the bootrom will initialize the secret keys for the AES key slots and yes
we would like to get those keys but um unfortunately the bootrom is disabled, it
disables itself before its launching of the firmware and 3DS bootroms also print
nice error screens like when the NAND is corrupted or something, it shows an error
screen so let's look how the bootroms are protected in detail and basically there
are two registers that we call CFG_SYSPROT9 and CFG_SYSPROT11 and the
bootrom writes to those registers and of course they are one shot you cannot
re-enable bootroms again because this is not the Wii U and basically when it's
disables the bootrom it only disables one half of it so what you get are two parts
of bootrom there's the unprotected part and protected part you can just dump the
unprotected part by taking over ARM9 from firmware but you can never see the
protected part and they were really clever and basically they put all the interesting
code in the protected part and if you look at the reset vector it just jumps directly
to protected part of the boot room so as you can't really figure out what is going
on when the 3DS is starting up but what you can do is you can look at the code
from the unprotected bootrom and who knows maybe we can find a bug so let's do this.
First of all of course there are no keys in in the unprotected bootrom, they put
all the keys in the protected part it's also mainly it's a lot of driver code.
Talks to some hardware like NAND flash, MMC, AES engine and also to SPI flash
which is kind of interesting because the SPI flash is some really tiny chip that is
soldered on the Wi-Fi socket and it's actually used for some Wi-Fi settings and
other user settings us by old Nintendo DS mode and yeah that's kind of interesting
uses the SPI flash and it also includes the ARM exception vector table and this is
actually just design that they have adopted from previous generations of the
Nintendo DS such as the DSi if you don't know ARM basically, you have something
that is called an exception vector table and this is located at this hardcoded
address in bootrom and basically every time when something weird happens or
something special on the CPU it will jump to those exception vectors like the reset
vector as we just so or when you're trying to read from an invalid address, it
returns to the prefetch abort or data abort vector and also when you receive an
interrupt it will jump to interrupt request vector so those are the exception
vectors and they're hardcoded in the bootrom and there's kind of a problem with
that because as a developer you don't want to put the exception in the routines in
the boot rom, you want to it'd be able to change the code right? So, what they do is
they just redirect all the exception execution flow from bootrom to another
jumptable that is located in ARM9 memory so it looks like this. What you can see
here are the bootrom vectors and it's basically just a jump instruction to the
RAM vectors and the RAM vectors are also just another jump instruction to the
actual firmware handler and this is so things look like when the firmware is
running but what about cold boot well on cold boot you get this and this looks
kinda interesting because you have the bootrom vectors that still point to ARM9
memory but since this is cold boot, the RAM is not initialized so this is
interesting but it is it's not really a bug because at some point the bootrom will
initialize those RAM vectors so but let's cheat a little bit here and say let's just
assume we could somehow trigger a really early exception even before the bootrom is
able to initialize the RAM vectors well probably it was just crash because on
exception it will just jump to uninitialized memory and there's probably
no valid instruction there so this is not very useful but there's a really nice
hardware flaw and we found this by just writing to some memory reboot, and see
what what happened basically we found out that some RAM is actually not cleared on
reboot and this also includes ARM9 so the basic idea is we can set up some custom
exception vectors in RAM that regenerate execution flow to some dumper code so when
we reboot we get this and this is really interesting because if you look at this
this means all we need to do now is trigger a really early exception and then
the bootrom will jump to our dumper code so, how can we trigger an exception? Well
if you look at here, the exception vector table again there are some exceptions that
we can trigger like because they are hardcoded like reset and they won't jump
to ARM9 memory and you also can't use the interrupt vector because interrupts are
disabled on reset and yeah this won't work so what's left is these 3 here interesting
exceptions and if you look at those and they normally don't happen right undefined
instruction is pretty rare and it shouldn't happen so I don't know about
this reminds me kind of like it's a really nice use case for doing for injection
again because you can corrupt registers and getting mutated instruction so it's
really likely that it will trigger an exception so this is the vector glitch
hack and basically we set up some vectors in RAM, trigger reboot then do some
glitching magic and then we reset again and let it boot up normally and hopefully
our dumper code got executed and just wrote a copy of the bootrom in memory so
we can just dump it. All this stuff is not very stable but it works for me.
*applause*
Wo okay we got the bootrom and Nintendo is losing a life there so before we look at
the bootrom I have a little problem for you and basically in early 2014 an FCC
document became public. There it is, and basically it says that Nintendo has changed
the CPU of the Nintendo 2DS and there's one really interesting sentence that
basically says, they have changed security function of the initial program loader
that is installed in each model so the initial program loader is probably bootrom
so obviously there must be some really huge bug in the bootrom, right? So so
that's it let's look at the bootrom. Basically there are some boot methods and
you can boot from NAND, that's what it normally does but alternatively you can
also boot from SPI flash which is the Wi-Fi flash and it will only boot firmware
images that are signed and encrypted there's no freaky development backdoor
that we can exploit it also uses two different sets of keys for NAND and non
NAND boot methods and also for our retail and dev mode so even when stuff gets
leaked you cannot use it on your retail console so let's do a small boot walk
through and it's pretty straightforward actually so the first thing it does is it
selects a boot device then it loads the firmware header and RSA signature from it
it's just one block and then it hashes the header and extract the hash from the
signature and compares it, so basically a basic signature verification header
verification and then assumes yeah the header is safe and then it starts loading
the firmware sections and the firmware images are pretty simple format and like
you have some entries in the header that tells you okay take the data from this
offset and there there's a section with the size load it to that address. It's
pretty simple so we know from Nintendos past that they like to mess up RSA
signature checks so let's look as how RSA is done on 3DS so for the 3DS firmware
they're using RSA signatures in the PKCS standard PKCS is basically a bunch of
standards that tell you how your signatures have to look like and they are
using the 2048-bit version of RSA which is safe and in the signature you have a SHA-2
hash and this is encoded using ASN.1 and ASN.1 it's some really complex structure
it's basically it's similar to the mp3 structure so you have little chunks of
data and those chunks have little headers and the headers have tag bytes and length
bytes and basically this ASN.1 stuff is used to tell the parser which hashing
algorithm is used and well since the SHA-2 hash is only 20 hex [0x20] bytes in size
you have some remaining space in the signature that you have to fill and PKCS
says you need a padding and this padding should be deterministic it should only
contain FF bytes so when you're trying to forge signatures it's it's really
difficult because of this padding that really long and when you compare the
signatures of different firmware images you'll actually notice that only the hash
will change and the rest of the data is always the same for all signatures but
well for some reason they decided to write a signature parser for this stuff so what
you get now is RSA the Nintendo way again so the first thing it does is it tries to
parse the padding and this part is totally messed up like there is a flag byte that
tells you if the padding should be checked and if it's one then it is checked it
should be all FF but but if it's two then it will just skip the padding and it also
has some really weak bounds checking it make sure that it will not when it's
passing the padding it make sure that it will not go out of bounds but they forget
to verify that the hash will actually fit in there as well so next thing they do is
parsing this really complicated ASN.1 structure and this process is also really
simplified so we know ASN.1 has some length fields and there's no bounds
checking so eventually it will add the length to the current pointer in the
signature and then they stop parsing and say okay we parsed all the data and now
there should be the hash and yet they are not checking this length and this pointer
is used to do the hash comparison so all in all you can say it only checks a few
bytes in the signature because the padding parser is messed up and also the ASN.1
parser is really simplified so what we can do is we can bruteforce the perfect
signature where the final pointer when it's done parsing the padding and the
ASN.1 data that this final pointer matches the pointer of the calculated hash of
bootrom so what it does then this it does a mem compare [memory compare] with the
calculated hash and the calculated hash like and this never fails, right? So it
will always succeed and this is SIGHAX.
*applause*
So the SIGHAX is a bootrom exploit for 3DS and basically we can sign our own
firmwares and there are over 60 million vulnerable devices and basically in new
3DS and 2DS basically all models are affected and of course since this is the
bootrom, Nintendo can't fix it so that's very nice but that's one heart remaining
so something is missing what we haven't done yet is we haven't dumped the ARM11
bootrom. It's probably not really interesting but for sake of completeness
you would like to get it and in theory we can just do a vector glitch hack again
because it has the same flaw but know that we can sign our own firmwares let's try
something else so if you look at the unprotected part of the ARM11 bootrom you
can see there are a lot of references to ARM11 memory so maybe now that we can sign
our own firmwares and we can set up our own firmware sections maybe we can
overwrite some bootrom data so but they're the bootrom developers were kind of clever
and the ARM9 bootrom checks the firmware sections and they have some kind of
blacklist and unfortunately you can't just overwrite boot9 data sections sections but
for some reason they forgot to blacklist all the boot11 data regions so we can just
overwrite boot11 stack or the exception vectors and well you can dump the ARM11
bootrom.
*applause*
yeah that was pretty easy and now I get to tell you something, all this stuff about
the bootrom we did this in summer 2015 so we could have talked about this already
last year but since we are kind of friendly hackers we held this bug so long
so yeah Nintendo should be thankful and ok so that's it 3DS is pretty game over and
here's a picture of Nintendo Switch and our body is ready *laughter*
*applause*
Herald: Thank you very much there's about five minutes left for questions and are
there any questions from the internet? No no no okay?
Signal Angel: Yes there's actually one question from the internet and that is the
internet wants to know if we can get DSP code execution maybe sometime soon
Herald: Can you repeat the question?
yeah very hard to understand here
Signal Angel: Ok I'm the internet wants to know if we can get a DSP code execution?
derrek: Yes well the DSP of the 3DS runs its own firmware and that is included in
some kernel module and basically when you can sign your own firmware you can also
make it load another DSP firmware so yes you can do this
Herald: Ok people who are leaving please do so quietly and people entering please
do so quietly. There was a question on microphone 3 I think but no longer okay.
Does the internet have more questions?
Signal Angel: Yes it does. The internet wants to know if you or how you glitch the
Wii U to get execution
derrek: Well I don't want to worry how I did it in detail but there are some basic
fault injection attacks and my setup was I think kind of complicated you had to
modify a lot of stuff on the Wii U mainboard to get it to work so I guess you
have to figure out yourself, sorry.
Herald: Ok there's a question upstairs microphone five I think?
Mic 7: Seven but it's okay. Yeah well you said that you broke all the 2DS but
actually you showed that the 2DS changed in the boot process so did you verify that
that work for the first version as well
derrek: Yes so the new 3DS was released after the 2DS and the new 3DS is also
vulnerable and basically all the Nintendo 2DS consoles are also also vulnerable as
well. Yes we did verify this and we don't really know what this FCC document is
about we got some really new 2DS from store and and basically yes, no difference
for the bootrom at all, so yes everything is vulnerable.
Mic 7: Nice to know, thanks.
derrek: ok *applause*
Herald: Final question from microphone 3?
Mic 3: Yeah just a fun question out of interest when you're going to buy such a
device do you also plan to play games on it? Or is it just going to check if the
other kernel works?
naehrwert: Personally for the Wii U, I own 0 games so
Mic 3: Great, thanks.
*applause*
I also didn't pirate any so i never played a game on my Wii U.
*33c3 postroll music*
subtitles created by c3subtitles.de in the year 2017. Join, and help us!