Microcorruption 0x08 - Montevideo

Prev: 0x07 Whitehorse
Next: 0x09 Santa Cruz

This level's manual is a little vague and mentions that some code was "reworked" to conform to their security standards, but doesn't explain much else beyond that.

If we look into "login," however, we can see that there are new calls to "strcpy" and "memset" prior to the "conditional_unlock_door" function.


If we start with a break before the call to "strcpy" and watch the Live Memory Dump while stepping through the instructions, it's pretty clear to see what happens: although the "getsn" call places our input at address 2400, "strcpy" is used to place it onto the stack and "memset" is used to clear everything at address 2400. Then, "conditional_unlock_door" looks at the copied string on the stack.

What does this mean for us? Well, funnily enough, this doesn't affect us if we use the first technique from the last level: overwriting the return to main with a call to "INT," followed by the value "7f" so that the function thinks it was placed onto the stack organically as the argument for "INT."

If we want, we can solve this level now with either "4141414141414141414141414141414160447f" (return to a call to "INT") or "414141414141414141414141414141414c4541417f" (return to the start of "INT").

But we aren't satisfied with reusing old solutions since there's clearly more that should be learned here, and it becomes apparent when we try to use our third solution from the last level: only part of our input gets copied to the stack during "strcpy."

If you have any prior experience with generating shellcode for arbitrary code execution in other programs, the issue here is very apparent: our input contains a null byte ("00"), which is treated as a null-terminator/the end of the string when passed to "strcpy." Once "strcpy" hits the null byte, it assumes the string has concluded.

The null byte comes from the "push 0x7f" instruction, which is treated more like "push 0x7f00." How can we remove this? Well, if you've been paying attention to the MSP430 opcodes, or if you recall my sidebar in the New Orleans write-up, you may be reminded of the ".b" modifier which works with bytes as opposed to words (words are two bytes). If we change the "push" instruction to a "push.b" instruction, it doesn't matter what we replace the null byte with in the "0x7f00" value as it won't be copied.

However, there's still a problem here: even though only the single "7f" byte will be pushed onto the stack, there may still already be a non-null value as the second byte where sp is pointing. If we run the program and test this, we can see that there's a "43" there already, and our shellcode fails as a result.


We may be on the right track with the ".b" modifier, but "push" may not be the best instruction. Let's look at the "INT" function for more ideas.


Right off the bat, we notice the first "mov" instruction which places two bytes into r14. If only it were "mov.b," our shellcode would have worked. But what if we skip this instruction? Could we write our own "mov.b" which places 0x7f into the r14 register, and then we return to 4550, the second instruction of "INT," instead of 454c at the start of "INT?" Let's hop into the site's assembler and give it a shot.


One thing to note: despite entering "mov.b 0x417f," the assembler notices that the instruction is a "mov.b" and discards the second byte, replacing "41" with "00." Before using this shellcode, you'll want to switch the null back to a dummy byte.

Now, we can create our password input: our 8-byte shellcode, plus 8 dummy bytes, plus a return address for the second instruction of "INT" (which is 4550).

Enter "7e407f41b01250454141414141414141ee43" and we're in!

Prev: 0x07 Whitehorse
Next: 0x09 Santa Cruz