|
For those who only care about one thing: [the PoC is here.](https://rol.im/kpwned.zip) Mirror: https://github.com/offensive-security/exploit-database-bin-sploits/raw/master/sploits/41021.zip ## Overview Cemu is a closed-source Wii U emulator developed by Exzap. New versions are released to those who donate to him via his Patreon first, then to the public one week later. According to its official website, Cemu "is not intended for general use yet", however it can run some games well. It HLEs the Wii U OS APIs. For those who don't know, the Wii U runs executables in a modified ELF format that include additional PE-like import and export sections. Basically, the HLE here means each exported function from each shared library has been reimplemented, and runs in native code. That's a pretty large attack surface! So, when looking for bugs, I decided to start there. ## Finding bugs in Cemu HLE API emulation Obviously, the first thing to do is to find where the API exports are set up so all of them can be annotated in IDA. I found a function at `0x1400AEDC0` (before relocation, cemu.exe is compiled with ASLR) that I labeled `set_up_emulated_API`. It takes three arguments: a pointer to a hashed (or obfuscated) shared library name, a pointer to a hashed (or obfuscated) exported function name, and a pointer to the function used for implementation. This function has a nice debug `printf` where it printed out the library name and exported function name, so I did things the long way and set a breakpoint there in x64dbg and labeled all the ~620(!) functions by hand. This took the better part of a day (however I did take breaks.) Once I had all the functions labeled, I could go ahead and start looking for bugs. It was nice from my perspective that the emulated API functions did all the grunt work of endianness conversion of arguments and return values, so I didn't have to do anything of the sort myself. I first decided to check the more interestingly (for me) named functions, not long later I'd found a bug. ### sysapp!_SYSGetSystemApplicationTitleId ```c uint64_t _SYSGetSystemApplicationTitleId(uint32_t index); ``` The implementation of this function just sets up a large array of title IDs (a title ID is a 64 bit integer that identifies "something that runs on the console", like a system application, firmware component or game, this has been used by Nintendo since the Wii and DSi, on console and handheld respectively) on the stack, then indexes it using the provided argument **without checking** and returns the array[index] to the emulator. What a perfect infoleak, to defeat ASLR later! Exploiting this seems easy, just get the return address from the stack (index `37`), but it seems this isn't totally reliable, so instead I make a dummy call, then use index `52`, which seems to return an address inside the `cemu.exe` `.text` more reliably. ### padscore!KPADSetConnectCallback ```c uint32_t KPADSetConnectCallback(uint32_t index,uint32_t value) ``` With an infoleak obtained, I just needed to find some (semi-)arbitrary write, and this took annoyingly longer to find. I found a few bugs that seemed promising but ultimately turned out to be unexploitable. Finally, after checking some of the functions not related to the OS, I found this function. Basically, it writes to an array of 32-bit integers (obviously the intended use of that array is function pointers inside the emulated system), in the `.data` section, with no checking of the provided index. Even better, it returns the old value (although I never needed to use this functionality when exploiting). The array is unfortunately near the end of `.data`, but that doesn't really matter, as it's stored *before* a nice array of KPAD C++ objects with vtables that I can clobber -- and if a pointer inside one of the objects happens to not be NULL, this same function makes a vtable call twice! Even better! ## Exploitation My PoC clobbers the first KPAD object (player 1 gamepad): it nulls out the checked pointer so no vtable calls are made while things are being overwritten, it overwrites the vtable pointers, sets up the ROP chain, sets up the stack pivot, makes that pointer non-NULL, and makes a dummy call to `KPADSetConnectCallback` to get ROP. Heh, I just made that sound easy. It wasn't. Let's see, it was annoying to find a stack pivot in the first place? But then I found the perfect pair of gadgets: ``` 0x000000014015d404 : add rcx, 0x10 ; jmp qword ptr [rax] 0x0000000140228371 : push rcx ; pop rsp ; ret ``` When the first one gets called, `rcx` has the address of the vtable array, and `rax` has the address of the first element of the vtable array (which isn't actually used, so it's a perfect place to put a gadget address). The ROP chain is written using `KPADSetConnectCallback` just like everything else, all this is written into a part of memory that contains UTF-16LE strings for controller mappings, that can only be seen if you open the controller settings. The ROP chain itself just grabs the address of the shellcode inside emulated RAM, `memcpy`s it to RWX memory allocated for the dynamic recompiler, and jumps there. Sure, it doesn't work if you deliberately disable the dynamic recompiler, but firstly, who even does that?!, and secondly, I'll leave the making of a ROP chain that uses `VirtualAlloc` to someone else if they wish. The shellcode itself is just metasploit `windows/x64/exec` running `calc.exe`. Nothing special. One final thing: when testing, I noticed that the emulator crashed if controller one was set up properly. It's because I initially thought the pointer that got checked for being NULL was a boolean or something else, and I'd only zeroed out the lower 32 bits of it. Whoops. ## Compiling the PoC Linked at the top of the page is an archive including the PoC itself as `calc.rpx` plus source plus modified and additional import library dependencies (as source and binaries). I used [wut](https://github.com/decaf-emu/wut) to make the PoC which obviously depends on [devkitPro/devkitPPC](http://devkitpro.org/). After compiling wut successfully I had to make library additions, as both of the vulnerable functions were not included in the library set. Luckily enough it was very easy to make additions to the import libraries. ## Timeline 2016-12-30: started reversing 2016-12-31: found exploits 2017-01-01: made PoC, made initial contact with developer 2017-01-02: developer replies, said fixes have been made 2017-01-02: asked for release date 2017-01-02: reply: release date unknown, "in 1-2 weeks maybe" 2017-01-09: release to patrons, public disclosure
|
|
|