sighax and boot9strap Presentation by SciresM

A Short Summary At 33c3, we learned the following from derrek: boot9 has a broken RSA verification implementation.

It's broken because the ASN.1 parser incorrectly verifies at least one of the length fields.

We can't perform sighax ourselves, because we can't get the details required from boot9's parser, because we don't have boot9. What can we do with that?

A Blast from the Past Nintendo loves reusing concepts and code. Firmware has to parse RSA signatures, too.

Initial examinations of NATIVE_FIRM, TWL_FIRM and AGB_FIRM look not vulnerable – though the ASN.1 parser looks very similar to what was described at 33c3, there are stringent padding checks in place.

Checks against the sighax vulnerability are present in firmware as early as 0.14 (1.0.0-0), from January 2011.

The checks aren't present in firmware earlier than that, including 0.13, which is factory firmware.

Factory firmware is vulnerable to sighax.

Factory firmware RSA verification The checks were added in firmware 1.0.0-0. This means Nintendo knew about the vulnerability when making the New 3DS, and did not fix it.

Exploiting a parser, blindly The parser in factory firmware isn't exactly the same as the one in boot9, as learned when a "perfect" signature for factory firmware's parser failed on boot9. What's next?

Testing a signature that overflows the factory firmware parser into data-aborting causes the console to show a black screen instead of bootrom error. This means we can crash the bootrom.

On factory firmware, the "calculated" hash is on the stack near the signature being parsed. This is probably the case for boot9.

Exploiting a parser, blindly There are only 128 possible locations, relative to the signature, that can be brute forced in reasonable time. It has to be one of those.

Sure enough, brute forcing signatures for each location shows the "calculated" hash is immediately after the signature on the stack. So we have sighax.

For those interested in the (complex) math behind optimizing the sighax brute-force, Myria made an additional presentation.

The bad ASN.1 Parser

A "Perfect" Signature

How it looks to the parser

So we have sighax. Now what? We dump the bootroms, of course!

Exfiltrating boot9 So we can fakesign our own FIRMs.

Meaning we can copy our payload almost anywhere.

boot9 has a blacklist of ranges... but we know it's not perfect.

From 33c3, only the boot9 data regions are blacklisted.

Can we find a region that isn't a boot9 data region but is still dangerous?

ARM9 Memory Map Region Address Size Description 0 0x20000000 0x08000000 FCRAM 1 0x10000000 0x10000000 I/O Registers 2 0x08000000 0x00100000 ARM9-only internal memory ("arm9mem") 3 0x08000000 0x00000400 arm9mem (different permissions, details irrelevant) 4 0xFFF00000 0x00004000 Data tightly-coupled memory (DTCM) 5 0x07FF8000 0x00008000 Instruction tightly-coupled memory (ITCM) 6 0xFFFF0000 0x00010000 Boot9 7 0x1FFFE000 0x00000800 AXI WRAM

NDMA We can copy anything almost anywhere.

This includes I/O registers.

The NDMA engine is a memory mapped I/O register. This means we can copy data over the NDMA registers, triggering DMA, letting us copy anywhere. Oh.

NDMA Parameters For an NDMA copy request, we need to set: the global control register to high priority ,

, the source address ( 0xFFFF8000 , the address of the protected boot9),

, the address of the protected boot9), the destination address (any safe place in arm9mem will do),

how much data to transfer (32 KiB, or 8192 words)

KiB, or 8192 words) some timing data

how much to transfer per cycle

And now we just copy that to 0x10002000 for a copy request!

Works for me, too SHA-512 (boot9): 5addf30ecb46c624fa97bf1e83303ce5

d36fabb4525c08c966cbaf0a397fe4c3

3d8a4ad17fd0f4f509f547947779e1b2

db32abc0471e785cacb3e2dde9b8c492

But wait, there's more!

boot9strap: Reliable boot9/boot11 code execution We can copy data anywhere during firm loading.

Including: the exception vectors (using NDMA to bypass the blacklist), and NULL.

That's all we need for a data abort, isn't it?

It is!

boot9strap: Big picture idea Section 0: Copy an ARM11 payload into AXI WRAM.

Section 1: Copy an ARM9 payload into arm9mem.

Section 2: Copy a payload over the NDMA registers that overwrites the data abort vector in arm9mem.

Section 3: Load anything to NULL.

???

Profit!

boot9strap: Technical implementation Getting execution during boot9 via data abort is really cool. But it'd also be nice to get execution under boot11. How can we?

boot9 dereferences some function pointers from DTCM, and calls them if they aren't NULL (they normally are).

Our poisoned data abort vector can overwrite two of these to point at our code, then return to boot9 and let it resume normally.

boot9strap: Technical implementation Later on, boot9 will call the first of those function pointers ( 0xFFF00058 ). This will wait for boot11 to finish a task by watching axiwram, then overwrite a function pointer ( 0x1FFE802C ) it will call later.

). This will wait for boot11 to finish a task by watching axiwram, then overwrite a function pointer ( ) it will call later. Immediately before lockout, boot9/boot11 will each dereference function pointers we have poisoned ( 0xFFF0005C , 0x1FFE802C respectively).

, respectively). We can execute arbitrary code before bootrom lockout under both boot9 and boot11.

Bootrom dumps for all!

Works for me, 2: Electric Boogaloo SHA-512 (boot11): c3f5044321f1ec5a33e09dd021e1117b

1b663e37673222944a06b119ea70af92

fc6de8547129582131fb9f8896edef7e

9a8ef77295c627e0f1cb360b15b533b4

Bonus fail Upon disassembling boot9, we notice another huge flaw in the bootrom that wasn't mentioned at 33c3.

Before trying to boot from NAND, the bootrom checks to see if a key combination (Start + Select + X) is being held, and whether the shell is closed.

If so, it tries to boot from an inserted NTR (Nintendo DS) cartridge.