This thread is for an in-depth technical review of the ARM9Loader hack.
These first posts will be edited to reflect updated information from community members. Credit will be given for corrections in the changelog, unless they were given to me via PM under condition of anonymity.
Table of Contents:
Introduction, BootRom, ARM9Loader Theory
ARM9Loader v1
ARM9Loader v2 (1/3 and 2/3)
ARM9Loader v2 (3/3), Conclusions
OTP dumping progress post / summary
Plailect's OTP Dumping Guide (external link)
Arm9LoaderHax source code (GitHub link)
Summary of differences from prior *hax (1/3)
Summary of differences from prior *hax (2/3)
Summary of differences from prior *hax (3/3)
Introduction
The description is initially based on the presentation by plutoo at 32C3, on December 27, 2015, in combination with information from the 3DS HomeBrew site, http://3dbrew.org/wiki/3DS_System_Flaws, some of my own ideas, and lots of my own ignorance thrown in. (In other words, errors are likely!)
The end goal is for a deep understanding of how and why the security broke down. Interestingly, if Nintendo had fixed some well-documented low-impact security issues (e.g., not clearing RAM on reboot, March 2014; etc.), then ARM9Loader might not have been practically exploitable.
BOOTROM
The jobs of the BOOTROM include to set some super-secret encryption keys, load firmware into memory, validate it's cryptographic signature, and BRANCH (JMP) to the firmware's entry point.
The 3DS includes both a primary firmware (FIRM0) and a second firmware (FIRM1). The second firmware (FIRM1) is used when the first firmware (FIRM0) fails the cryptographic signature check for any reason. This makes sense, as it provides a fail-safe for situations that cannot be entirely eliminated (e.g., power-loss during update FIRM0, NAND sector corruption, etc.).
Conceptually, the BootRom does the following:
Minor BootROM flaw
If the cryptographic signature of a firmware fails validation, the bootrom does not clear the memory that was written to when loading that (invalid) firmware. This allows FIRM0 to be used to load attacker-controlled contents ... up to the size of the largest Nintendo-signed firmware (because header must be signed before loading that size firmware).
So, if FIRM1 is smaller in size than FIRM0, then the attacker can still control the contents of at least some memory during FIRM1's loading.
ARM9Loader Theory
a.k.a. How it is supposed to work
ARM9Loader is an additional layer of security which was added only to the N3DS. The ARM9Loader is part of the firmware binary, and thus will only execute if the firmware itself was properly signed. The purposes of the ARM9Loader include using additional console-unique data to:
These first posts will be edited to reflect updated information from community members. Credit will be given for corrections in the changelog, unless they were given to me via PM under condition of anonymity.
Table of Contents:
Introduction, BootRom, ARM9Loader Theory
ARM9Loader v1
ARM9Loader v2 (1/3 and 2/3)
ARM9Loader v2 (3/3), Conclusions
OTP dumping progress post / summary
Plailect's OTP Dumping Guide (external link)
Arm9LoaderHax source code (GitHub link)
Summary of differences from prior *hax (1/3)
Summary of differences from prior *hax (2/3)
Summary of differences from prior *hax (3/3)
Introduction
The description is initially based on the presentation by plutoo at 32C3, on December 27, 2015, in combination with information from the 3DS HomeBrew site, http://3dbrew.org/wiki/3DS_System_Flaws, some of my own ideas, and lots of my own ignorance thrown in. (In other words, errors are likely!)
The end goal is for a deep understanding of how and why the security broke down. Interestingly, if Nintendo had fixed some well-documented low-impact security issues (e.g., not clearing RAM on reboot, March 2014; etc.), then ARM9Loader might not have been practically exploitable.
BOOTROM
The jobs of the BOOTROM include to set some super-secret encryption keys, load firmware into memory, validate it's cryptographic signature, and BRANCH (JMP) to the firmware's entry point.
The 3DS includes both a primary firmware (FIRM0) and a second firmware (FIRM1). The second firmware (FIRM1) is used when the first firmware (FIRM0) fails the cryptographic signature check for any reason. This makes sense, as it provides a fail-safe for situations that cannot be entirely eliminated (e.g., power-loss during update FIRM0, NAND sector corruption, etc.).
Conceptually, the BootRom does the following:
- Lots of top-secret stuff first
- Load FIRM0 firmware from NAND (firmware partition) into memory
- Check the cryptographic signature of the loaded FIRM0 in memory
- If the cryptographic signature is verified, jump to FIRM0's entrypoint
- Else....
- Load FIRM1 firmware from NAND into memory
- Check the cryptographic signature of the loaded FIRM1 in memory
- If the cryptographic signature is verified, jump to FIRM1's entrypoint
- Else... PANIC (no towel)
Minor BootROM flaw
If the cryptographic signature of a firmware fails validation, the bootrom does not clear the memory that was written to when loading that (invalid) firmware. This allows FIRM0 to be used to load attacker-controlled contents ... up to the size of the largest Nintendo-signed firmware (because header must be signed before loading that size firmware).
So, if FIRM1 is smaller in size than FIRM0, then the attacker can still control the contents of at least some memory during FIRM1's loading.
ARM9Loader Theory
a.k.a. How it is supposed to work
ARM9Loader is an additional layer of security which was added only to the N3DS. The ARM9Loader is part of the firmware binary, and thus will only execute if the firmware itself was properly signed. The purposes of the ARM9Loader include using additional console-unique data to:
- further decrypt the KERNEL9 binary (using OTP & sector 150)
- perform additional key initialization prior to handing control to Process9
- Calculate OTP_HASH
- SHA256 hash of the OTP areas
- As you know, the OTP registers are console-unique data
- OTP appears to be *THE* foundational secret for ARM9Loader
- OTP_HASH was not cleared in some early firmware...
- Read encrypted sector 150 (0x96)
- Decrypt the sector using the OTP_HASH
- Use a 16-byte blob as Normal-key for keyslot 0x11
- Generate dependent keys using that keyslot
- Dependent keys are generated using a cryptographically secure one-way function
- Thus, the exposure of any dependent keys would not expose the parent key
- For example, first 16 bytes used for keyslots 0x15 and 0x18
- Verify the keyslot (e.g., keyslot 0x11) by encrypting a fixed test-vector
- This prevents accidental use of a corrupted NAND sector
- Clear the keyslot (e.g., keyslot 0x11)
- This prevents any later use of the keyslot, such as by ARM9, to regenerate the dependent keys
- Decrypt the ARM9 binary
- Jump to the ARM9 entrypoint
Last edited by Selver,