Addis Ababa
At this point, I decided to see if the same kind of code exists as did in the last level:
448a: 8193 0000 tst 0x0(sp)
448e: 0324 jz #0x4496 <main+0x5e>
4490: b012 da44 call #0x44da <unlock_door>
4494: 053c jmp #0x44a0 <main+0x68>
4496: 3012 1f45 push #0x451f "That entry is not valid."
449a: b012 c845 call #0x45c8 <printf>
449e: 2153 incd sp
44a0: 0f43 clr r15
44a2: 3150 1600 add #0x16, sp
Maybe not, there is no final < ret > call that uses the value on the stack, instead the code falls through to
44a6 <__stop_progExec__>
It looks like they finally patched things. However there is one place that if we could get a non-zero value onto the stack, we could open the door.
448a: 8193 0000 tst 0x0(sp)
448e: 0324 jz #0x4496 <main+0x5e>
4490: b012 da44 call #0x44da <unlock_door>
Specifically that address being tested in 4286. 4288 is the starting address of our user input.
Looking at the code some more we see that they are using printf – the format string function in C – to display user input. This is probably what the game designers want us to attack.
The format string vulnerability has been around for more than a decade, but so much code is written in C, and it is such a powerful exploit, that it is worth learning about.
The format string function takes an unspecified amount of arguments and an unspecified amount of format string parameters – and they don't have to match in number. Additionally, one of the format string parameters %n allows you to write to memory.
I suppose at some point this was a neat idea; I wish I had been there for that conversation.
Basically you ask for user input and give the user the power to write to memory of the program – even if you don't want them to. For more information about format string check out owasp, wikipedia or stackoverflow.
So let's combine the knowledge that we have:
the power to write to memory
an address the is checked for non-zero
Writing a specific value to that memory might be a problem, but all we really need to do is write any non-zero number. So, we provide the address we want to write to, then write to it. After which it is tested for non-zero and the door is unlocked.
86 42 25 78 25 6E
--address (little endian)---- % x --- % s –
That's it. Printf will write a number (that number being the number of bytes printed) to the address specified.
Try using some of the other format string parameters to see if you can get a better cycle time.