Wii U system flaws
This page lists publicly known vulnerabilities on the Wii U system.
Hardware
Summary | Description | Successful exploitation result | Fixed in hardware version | Discovered by |
---|---|---|---|---|
HW_SPARE1 is not clear-only, even in WiiMode | Much like on the Wii, the Wii U includes a register that can be cleared to unmap boot0. However, Nintendo forgot once again to make this register clear-only, which allows boot0 to be dumped, including in WiiMode. | Dumping of boot0 | None | marcan |
eFuse readout counter is not reset with NRST (de_Fuse) | In order to accommodate eFuse-based JTAG lockout (and due to other considerations), eFuse bits must be buffered into a register file immediately following NRST, before the internal reset can be released. The eFuse sense state machine latches at a rate of 4 bits per cycle, directly off the 27MHz XTALCLK. Every other rising edge, a byte is written into the register file, starting from the least significant byte of the current u32.
An internal counter is used to keep track of the remaining bytes to be read into the register file. While the eFuse register file is reset to zero with NRST, the internal counter is not: By asserting NRST after N bytes have been read, only 0x400-N bytes will be read on the subsequent boot. By asserting NRST just before the final byte has been read (1830 cycles), all eFuses will read entirely zero, including the JTAG lockout fuse. This allows trivial, unsigned and unencrypted boot1 execution, with no SEEPROM anti-rollback. Additionally, because SRAM is not cleared on reboot, and because boot1 verifies over the encrypted payload, the boot1 key can be extracted. By asserting NRST after 176 cycles and walking the delay width down cycle-by-cycle, code execution can be used to gather 16 failed decryptions of boot1: A zerokey-decrypted boot1, and 15 others with one more byte present in its boot1 key than the last. This allows a straightforward bruteforce of the boot1 key. |
Trivial arbitrary code execution as boot1;
boot1 AES key extraction; Recovery of SEEPROM-bricked Wii Us |
None | shinyquagsire23 |
boot0
Summary | Description | Successful exploitation result | Fixed in system version | Discovered by |
---|---|---|---|---|
Unsafe boot1 image's size check | Before boot0 loads boot1, it reads boot1 image's ancast header into memory and determines boot1 image's size by looking at a field inside the ancast header (see Ancast_Image#Header). This header is not signed, so the boot1 image's size can be modified externally.
boot0 immediately checks if this size is larger than 0xF800, rendering any software based attacks useless. However, an attacker may still be able to glitch boot0 via hardware fault injection attacks and, with precise timing, jump over this size check and force boot0 to read a larger boot1 image. While the boot1 image is signed, boot0 first reads it to SRAM and only then validates it's signature. Using a tampered boot1 image, an attacker can now overflow boot1's memory region (0x0D400000) into boot0's (0x0D410000), hijack the next code instruction and achieve code execution. By now, boot0 has already locked out the boot1 AES key in the OTP, but there is still a copy of it inside boot0's memory region and the attacker is now able to extract it. Additionally, the attacker can also read the rest of the OTP region and obtain the contents of the two blocks locked out by boot1 (which are currently unused). NOTE: A successful attack was implemented and demonstrated, to some extent, by derrek at the 33C3 convention. |
boot1 AES key extraction | None | derrek;
hexkyz (independently) |
boot1
Summary | Description | Successful exploitation result | Fixed in system version | Discovered by |
---|---|---|---|---|
boot1hax (unsafe "boot_info" pointer) | boot1 communicates with IOS-MCP using the "boot_info" structure. A pointer to this structure is stored in the PRSH/PRST section in MEM2 which is given back to boot1 on a warmboot.
Due to this pointer not being validated by boot1, an attacker can craft a malicious PRSH/PRST section where the "boot_info" pointer will point to anywhere inside boot1's memory region and thus achieving a semi-arbitrary write. |
warmboot boot1 code execution | None | derrek, plutoo, naehrwert, yellows8, shuffle2 and hexkyz |
isfshax (stack overflow while processing ISFS superblock directory entries) | Upon startup, boot1 loads and processes the latest SLC ISFS superblock. Directory entries are parsed using a recursive function without any limitation on recursion depth. A carefully crafted superblock with a sufficient directory depth can be used to overwrite memory preceding the boot1 stack and eventually gain arbitrary code execution. For example, it is possible to redirect FLA's FS device structure pointer to the superblock area, allowing an attacker to point structure's functions to a controlled memory location. | coldboot boot1 code execution | None | rw-r-r-0644 |
ARM software (IOSU)
ARM kernel
Summary | Description | Successful exploitation result | Fixed in system version | Discovered by |
---|---|---|---|---|
ioctlvhax (ioctlv TOCTOU) | This flaw technically is in the kernel, but it can be used to exploit a userland module.
It allows changing an ioctlv vector buffer address entry after it has been validated by the kernel. Any module not checking the number of ioctlv vectors is vulnerable. More information here. |
ROP under several IOSU modules | 5.2.0 | naehrwert and plutoo |
Bad memset in IOS_CreateThread syscall | The IOS_CreateThread system call fills the stack of a newly created thread without validating the supplied stack address from the calling IOSU module.
In firmware versions before 5.x.x, this memset was done using zeros. Doing ROP inside any IOSU module and calling IOS_CreateThread allowed to arbitrarily patch the IOSU kernel with NOP instructions (since 0x00000000 is interpreted as NOP in ARM) and, therefore, build a NOP sled in the IOSU kernel. In 5.x.x firmware versions, this was partially patched by using the random constant 0xFA5A5A5A in the unchecked memset. However, passing 0x02 as flags to the IOS_CreateThread system call results in an additional memset of the top 0x24 bytes (IPC buffer pool) to zeros again. Crafting a carefully placed NOP sled inside the IOSU's kernel is enough to achieve a kernel level write-what-where primitive and get code execution. |
ARM kernel code execution | None | plutoo and naehrwert;
Hykem (independently) |
get_process_name signed comparison fail | IOSU's syscall 0x06 (get_process_name) does a signed comparison for the pid parameter (r0) and does not check if the pid is negative, which allows an arbitrary 0x20 bytes kernel read to userland memory. | ARM kernel memory leak | None | plutoo (on September 11th, 2015);
Mrrraou (independently, on October 31th, 2016) |
IOS_CreateMessageQueue poor address range validation | IOS_CreateMessageQueue() syscall does not check the number of entries, allowing for an integer overflow that will bypass the address range validation. Using IOS_SendMessage(), one can overwrite IOSU kernel and achieve code execution. see here and here for impl. | ARM kernel code execution | None | derrek, nedwill and naehrwert ? |
ARM userland
Summary | Description | Successful exploitation result | Fixed in system version | Discovered by |
---|---|---|---|---|
uhshax (/dev/uhs/0 bad array index check) | The IOS-USB module manages the UHS (USB host stack) and exposes it through the node /dev/uhs/0.
IOCtl commands 0x12 and 0x13 (firmware versions 2.x.x), or 0x13 and 0x14 (firmware versions 3.x.x and 4.x.x), or 0x14 and 0x15 (firmware versions 5.x.x) are responsible for activating and deactivating (respectively) UHS root hubs (which are managed in internal structures inside the IOS-USB module's memory space). The single parameter that is passed to these IOCtl commands is the root hub number which can only be 0 or 1. IOS-USB module uses this number directly as an index for the internal root hub structures' array, but it doesn't check it properly (if index <= 2, proceed normally). Passing the index value 2 results in an useless array index overflow, but passing a negative value allows to redirect the array into a controllable PPC userland buffer. The IOCtl command responsible for activating a root hub (0x12, 0x13 or 0x14) registers two new IOS-BSP entities (CtrlProp and CtrlChicken) that become tied to the root hub. Attempting to exploit this particular IOCtl command always results in an uncontrollable memory write (the written data comes from IOS-BSP and cannot be changed). However, the IOCtl command responsible for deactivating a root hub can be exploited by carefully crafting a buffer that mimics a root hub structure. With it, we can eventually achieve a write-what-where primitive, overwrite the return address of the __uhsBackgroundThread thread (responsible for handling IPC requests to /dev/uhs/0) and achieve ROP inside IOS-USB. NOTE: After firmware version 5.5.0 a new check was added to the system call handler that verifies if the calling thread's stack pointer is valid. If an attacker plans on targeting IOSU syscalls from inside this ROP chain, then the thread's stack pointer can't be increased past the stack's top address. |
ROP under the IOS-USB module | None | Hykem |
Stack buffer overflow for received HID reports (BluuBomb) | The Wii U doesn't check the size of received HID reports in IOS-PAD. By emulating a Wii Remote an attacker can send reports larger than 58 bytes and overflow a buffer on the stack.
More information here. |
ROP under IOS-PAD | None | GaryOderNichts, yellows8 (independently: January 2021) |
Double fetch during USB configuration parsing causing out of bounds byteswap | The Wii U doesn't verify that the total length of the USB configuration descriptor matches the total length used to determine the buffer size. This allows placing endpoint descriptors outside of the allocated buffer which will be swapped. | Out of bounds byteswap in IOS-USB heap. Can lead to ROP, see this post. | None | GaryOderNichts |
Heap buffer overflow in DNS response processing | IOS-NET uses a modified version of NicheStack which is affected by CVE-2020-25928. Unlike described by the CVE, the IOS-NET implementation has an additional check for DNS PTR answers, which ensures the data isn't copied past the end of the buffer.
For additional PTR records pointing at the first answer name |
Out-of-bounds heap write. Can lead to ROP, see this post. | None | GaryOderNichts |
Espresso Boot ROM
Summary | Description | Successful exploitation result | Fixed in system version | Discovered by |
---|---|---|---|---|
Binary is not reverified before launching | The Espresso boot ROM does not check for modifications to the binary in main memory before launching it. By changing the first instruction from the Starbuck, the Espresso can be sent anywhere. | Arbitrary Espresso code booting | Unknown | marcan |
Reset vector is not always locked in L2 cache | The Espresso Boot ROM keeps an infinite loop at the reset vector to prevent unexpected code from executing. Most of the time, this is in the L2 cache, which prevents the Starbuck from overwriting it. Toward the end, it is no longer in the cache, so a custom jump can be done, before ROM access is disabled. | Espresso Boot ROM can be dumped | Unknown | marcan |
WiiMode flag is not set here | In WiiMode, the ancast images themselves are responsible for lowering the clock speed. If one of the above hacks is used to take control, it becomes possible to execute code in full Espresso mode. | WiiUMode privileges within the Espresso | Unknown | marcan |
PPC software (CafeOS)
PPC kernel
Summary | Description | Successful exploitation result | Fixed in system version | Discovered by |
---|---|---|---|---|
OSDriver race attack | The Cafe OS kernel implements a structure called an OSDriver, which can hold a 0x1000-byte cross-process data area. Accessing this data area is done through the CopyToSaveArea() and CopyFromSaveArea() syscalls. However, no lock on the OSDriver is held during the copy, allowing the save area to be freed and reallocated while the copy is taking place. With all 3 PPC cores, it is possible to copy over an OSDriver structure, and create a save area that points at the syscall table, giving PPC user mode code access to it. More information here. | PPC kernel code execution | 5.4.0 | libwiiu team (Marionumber1, TheKit, Hykem, comex, Relys and Mathew_Wi) |
GX2 unchecked memory read/write | The Wii U GPU (the GX2) has direct access to RAM for various operations. Using raw GPU commands it is possible to read/write memory in the PPC kernel heap, which is not blocked from GPU access. By redirecting the "next pointer" in the kernel heap into userspace it becomes possible to create a new OSDriver structure in userpsace and set it's save area to the kernel syscall table. From that point on, the OSDriver race attack can be reused. | PPC kernel code execution | None | libwiiu team (Marionumber1, Hykem and Mathew_Wi) |
PPC userland
Summary | Description | Successful exploitation result | Fixed in system version | Discovered by |
---|---|---|---|---|
RenderArena use-after-free | An iframe is removed from its parent in a beforeload event and freed, but accessed for a vtable call later. Using Javascript, a vtable pointer is sprayed, occupying the frame's previous memory. A forged vtable referred to by the pointer is also sprayed. When WebKit attempts the virtual call, it goes to the forged vtable, which starts a ROP chain. More information here. | ROP under the Internet Browser application | 5.1.0 | libwiiu team (Marionumber1, TheKit, Hykem, Relys and Mathew_Wi) |
JSStringJoiner heap overflow | When joining an array of strings, the lengths of the strings are summed to calculate the needed storage space. This summation is vulnerable to an integer overflow, which enables a heap overflow. As a result, a sprayed value from Javascript ends up as a vtable pointer, which can be used with a forged vtable to start a ROP chain. More information here. | ROP under the Internet Browser application | 5.3.2 | libwiiu team (Marionumber1, Hykem and Mathew_Wi) |
Stagefright ‘stsc’(?) MP4 atom integer overflow | Documented libstagefright MP4 integer overflow. | ROP under the Internet Browser application | 5.5.0 | zhuowei, Marionumber1 and Mathew_Wi |
Stagefright ‘tx3g’ MP4 atom integer overflow | Documented libstagefright MP4 integer overflow. See [1]. | ROP under the Internet Browser application | 5.5.2 | yellows8 |
Image input use-after-free | Use-after-free in <input type="image"> tags, see here | ROP under the Internet Browser application | None | JumpCallPop |
contenthax | The Wii U's data management system does not include provisions to validate the integrity of most title contents after installation. Any title contents using hash tables for verification (content type 0x0002 in tmd, using *.h3 files) are vulnerable. Generally, all contents are vulnerable apart from those in /code.
As such, any game or app's contents may be altered by attackers. In particular, attackers with IOSU code execution may use FSA commands to alter the content files in USB or MLC filesystems. Alternatively, an attacker with control over certain PPC usermode processes (such as home menu or system settings) may use commands such as MCP:CopyTitle to copy title contents over from SD to MLC or USB. |
Arbitrary title content modification | None | yellows8, smea (Early 2016);
WulfyStylez (Early 2016) |
contenthax2 (FailST) | Each title has a File System Table (FST) that describes the filesystem. However, its integrity is not checked at runtime by the Wii U. Once the title is installed and has at least one section with hash mode 2 (no runtime checks) all file entries can modified to point to this section and thus bypass runtime file integrity checks of this title. This can be easily used as a secondary entrypoint by replacing the titles binary, leading to arbitrary code execution. By modifying the cos.xml the application can also run with full permissions, allowing for example JIT or SD Card access. A detailed write up can be found here | Arbitrary title content modification | None | Maschell (April 2020) |
haxchi (variation of contenthax) | The Wii U Nintendo DS virtual console emulator is vulnerable to contenthax attacks. In particular, the ROM parsing code lets an attacker perform fully controlled arbitrary write operations, which very easily leads to ROP and code execution, because these titles are among the few that have JIT capabilities. | ROP under the Wii U Nintendo DS virtual console emulator title | None | smea (Early 2016) |
N64 VC contenthax (variation of contenthax) | The Wii U N64 VC emulator title("VESSEL") has two known vulnerabilities which can be attacked via contenthax. These vulnerabilities were tested on hardware, but actual exploitation wasn't tested.
Note that this title can only write to codegen (JIT) via using OSCodegenCopy(), unlike other titles. Currently this is the only known VC platform (N64) which is affected by any of these VESSEL vulnerabilities (not all platforms were checked for this). The .ini loading occurs much earlier during title boot than the font loading. These vulnerabilities (or at least the .ini one) trigger while the system is still displaying the application splash-screen(from the title's meta/ directory).
|
ROP under the Wii U N64 virtual console emulator title | None | yellows8 (Early 2016) |
ROBChain (variation of contenthax) | Super Smash Brothers for Wii U is vulnerable to contenthax attacks via a crafted moveset file that causes a buffer overflow from the moveset's stack buffer into the stored write index of said stack allowing for a contiguous relative read/write which can be used for an address leak to translate it into an arbitrary read/write. A proof of concept and write up can be found here. | ROP under Super Smash Brothers for Wii U | None | jam1garner |
DKCTF-Save-Exploit | Donkey Kong Country Tropical Freeze is vulnerable to a save exploit based around a crafted game save. The vulnerability is located in how achievemets are stored. The save contains a count for the number of items to read into a set length buffer located on the stack. Increasing this count past the length of this buffer writes directly to stack which can be used to immediately gain ROP. Proof of concept can be found Here | ROP under Donkey Kong Country Tropical Freeze | None | Kinnay |