This is the sixth in a series. You might want to read the previous post before reading this.
This post is based on the Cusco level on microcorruption.com. Like last time, we’re trying to find an input to open a lock without knowing the correct password, using knowledge of assembly language.
You should know the drill by now. Let’s look at the
4500: 3150 f0ff add #0xfff0, sp 4504: 3f40 7c44 mov #0x447c "Enter the password to continue.", r15 4508: b012 a645 call #0x45a6 <puts> 450c: 3f40 9c44 mov #0x449c "Remember: passwords are between 8 and 16 characters.", r15 4510: b012 a645 call #0x45a6 <puts>
0xfff0 to the stack pointer decreases it by 16. That means adding 16 bytes to the stack for use by the current frame. Then the code writes out some text.
4514: 3e40 3000 mov #0x30, r14 4518: 0f41 mov sp, r15 451a: b012 9645 call #0x4596 <getsn>
This should look familiar too - familiar code with a familiar bug. The code gets input by calling
getsn, storing the result at the address of the stack pointer, and allowing up to 0x30 = 48 characters. Which is 32 more bytes than was just added to the stack frame to allow for it.
We’ve already seen in a previous episode that the first two bytes (on a 16-bit CPU) beyond the current stack frame are where the return address is stored. When
ret is called from a stack frame, it will be those two bytes that the CPU returns to.
And it’s those two bytes that will be the first we overwrite with a password beyond 16 characters. What address would we like the function to return to? Well,
0x 4446 sounds like a good candidate. We have to change the order of the bytes because addresses are stored in a little-endian way. So we just need an input with
0x4644 in the 17th and 18th bytes. I used
Lots of this was similar to code we’ve seen before. Buffer overflows from an input that wasn’t correctly sanitised, and overwriting return values. Next time: the myth of security through obscurity.