Monday, August 31, 2015

Microcorruption - Santa Cruz


It's been awhile since I published anything related to Embedded CTF, so here is another level that I had in the queue...

Santa Cruz is a little more cryptic in that functions are more poorly named.

There is still a lot of similarity between this level and the previous however. For example, both levels continue to have the very end of the login adjust the stack pointer to a potentially vulnerable spot and then return to the address stored at that spot. This is likely to be our vulnerability again.

On a lark I tried something different to start. I wondered what happened if we injected like 500 characters instead of say 50. My initial thinking was that I could inject enough garbage and overwrite one critical return point with a call to <unlock_door> where the beginning of <stop_progEXEC> occurs. The result would have been the last thing the program did after telling you that you failed and that your password was too long and then trying to quit on you would have been to unlock the door for you. It turns out however that the maximum amount of characters that will be read in is 100. I tried a direct approach of overloading with several hundred but it limited my maximum input. 

So maybe we should put that idea into our back pocket for some other time.

Inspection of the code shows that normal program execution never calls <__do_nothing> and also does not call <test_username_and_password_valid>

Some exploration with input yields the following behavior:

  • The full length of the username and password are copied (up too 100 characters each).
  • The start of the username is always address 0x43a2 regardless of username length.
  • The start of the password is always address 0x43b7 regardless of username or password length.
  • The code requires memory address 0x43c6 to be null.
  • The code requires memory address 0x4303 to be 0x08 - minimum length.
  • The code requires memory address 0x4304 to be 0x10 - max length.
  • A final call returns from 0x43cc if the password is not too long (this is the historical vulnerability).

Registers at about line 0x45d0
r11: 0x43b5

r15: 0x43b5 (start of pw)

r13: 0x43c6 (null delimiter put in by password)

r14: 0x43cc (houses return address)


Given that behavior and those requirements we can meet them with the following strategy:

usernameuse0812PASSWORD'\0'meusernameusernameSHELLCODESHELLCODESHELLCODE
<- fill ->< ^^REQD fill ^REQD><--- filler --><-- return point & code--->

where the password overwrites a portion of the user name in memory and is used to fullfill the requirement of the null delimiter at the correct address and the username is used to inject the code. As for the shell code itself we can use similar code to what we have previously been using. Likely we will have to alter it a bit as addresses have changed, but the basic tactic of either calling <unlock_door> directly or using the status register and the interupt trap will work.

Specifically you will need 42 characters of fill for the username after which shell code will start and a password of 15 charcters in length.

The following username and password entries will break the lock. Can you get better shell code based on the previous levels to get on the leaderboard?

Username: (hex code enabled)
4141414141414141414142424242424242081242434343434343434343434444444444444444444445454A44


length: 44, 12835 cycles

No comments:

Post a Comment