In this level we’ll discover and apply one of the most common, famous and basic memory corruption techniques. Keep reading to find it out :)
When you enter the level, the manual that pops up states the following:
We have fixed issues with passwords which may be too long.
This is Software Revision 02. We have improved the security of the lock by removing a conditional flag that could accidentally get set by passwords that were too long.
As always, we start inspecting the code from the
main function. Just like the previous level, Hanoi, it simply calls
If we take a closer look to
login’s code, we can see there’s nothing special about it.
4500 <login> 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> 4514: 3e40 3000 mov #0x30, r14 4518: 0f41 mov sp, r15 451a: b012 9645 call #0x4596 <getsn> 451e: 0f41 mov sp, r15 4520: b012 5244 call #0x4452 <test_password_valid> 4524: 0f93 tst r15 4526: 0524 jz #0x4532 <login+0x32> 4528: b012 4644 call #0x4446 <unlock_door> 452c: 3f40 d144 mov #0x44d1 "Access granted.", r15 4530: 023c jmp #0x4536 <login+0x36> 4532: 3f40 e144 mov #0x44e1 "That password is not correct.", r15 4536: b012 a645 call #0x45a6 <puts> 453a: 3150 1000 add #0x10, sp 453e: 3041 ret
There is a call to
getsn. We can see, once again, the number of bytes to read is 0x30 (48 decimal), our input will be stored starting at
sp (remember in the previous level we had
mov #0x2400, r15 instead
mov sp, r15), a call to
test_password_valid and afterwards some testing on
r15. Depending on
r15’s value the door will or will not be unlocked. So far it looks exactly like the previous level
4452 <test_password_valid> 4452: 0412 push r4 4454: 0441 mov sp, r4 4456: 2453 incd r4 4458: 2183 decd sp 445a: c443 fcff mov.b #0x0, -0x4(r4) 445e: 3e40 fcff mov #0xfffc, r14 4462: 0e54 add r4, r14 4464: 0e12 push r14 4466: 0f12 push r15 4468: 3012 7d00 push #0x7d 446c: b012 4245 call #0x4542 <INT> 4470: 5f44 fcff mov.b -0x4(r4), r15 4474: 8f11 sxt r15 4476: 3152 add #0x8, sp 4478: 3441 pop r4 447a: 3041 ret
After some operations, a call to
INT is made at instruction
0x446c. It takes
0x7d as a parameter, just like the previous level.
So far it seems there’s no way for us to know the correct password. Let’s, then, execute the program and see what happens.
As soon as we execute it, we can see there are some instructions printed out:
Wait a second, how come password must be between 8 and 16 characters when we’ve inspected the code and already stated that they can be up to 48 chars? Well, once again, the moral is to
Let’s then stress the program, let’s see what happens if we input more than 16 chars. I will input exactly 48 x A.
The password is obviously not correct.
But we got some precious information. We can see the message insn address unaligned in the debugger console. If we take a look at Live Memory Dump:
We’ll notice the
sp register is pointing at some memory whose content is what we just provided as input. If we take a look again at the code, we’ll se the following:
Instructions starting at address
0x4400 have been overwritten. If we look again at Live Memory Dump we can indeed see how that memory address is now fullfilled with our input.
Well, what happened?
pc (Program Counter) also known as
I will first briefly explain it and then reference some good reads for you to go deeply into this matter.
Buffer Overflow happens, basically, because stack grows towards lower addresses of memory and memory writes are done towards higher addresses of memory. Everytime an element is inserted into the stack, it is inserted towards lower addresses of memory. That’s why we say the stack grows towards lower addresses of memory, towards the heap. You can read more about the stack here.
Everytime a function is called, the
Now, when the funcition finished, the
Please, if you have never faced buffer overflow nor worked with them, read the following articles. There are tons of articles and entries about this very topic, I will mention some. There are even thousands of research papers you can find using the search engine of you choice, like Google Scholar.
- Buffer Overflow Explit
- Security flaws: The buffer overflow
- Buffer overflow: The Basics
- If the stack grows downwards, how can a buffer overflow overwrite content above the variable?
Now that we know what a buffer overflow is and how to exploit it, we will overwrite Instruction Point to take advantage of this vulnerability.
The return address we want to overwrite is the return address of
login. In order to do that, we will set a breakpoint right at instruction address
0x453e in order to see where the
sp is at that very moment.
login the function whose retaddr must be overwritten? Simple. Remember memory writes are made towards higher addresses of memory and the stack grows towards lower addresses. WE cannot overwrite a function that has been declared after the declaration of our buffer.
main is the function that calls
login and at some point the
login our buffer is declared and, after that declaration, the rest of the calls. Since writing into the buffer will grow toward higher memory addresses, the only retaddr we can overwritte is the
First of all we must know how many padding bytes we need before actually writting into memory the address we want to jump to. As we can see, at the moment of
sp points to
Since our buffer starts at address
0x43ee, it is as simply as counting the bytes.
0x10 (16 decimal). We must insert 16 padding bytes.
Now we must figure out what address we want to jump to. If we take a close look, in
main there is the function that unlocks the door and solves the level,
unlock_door. Its address is
0x4528 and that’s where we want to jump to.
0x4528 will become
0x2845 in order for the little-endian machine to actually read it as we want.
So, the solving input will be (hex encoded):
We’ve seen, once again, how important is to not trust what printed instructions say and only believe in code. We’ve seen what buffer overflow is and how we can use this vulnerability to overwrite Instruction Pointer and hijack the program’s execution flow.