microcorruption - new orleans
Mar 3, 2018 · 4 minute read · Commentsctfexploitassemblymicrocorruptionnew orleans
The next post in the series of solving the microcorruption.com ctf challenges continues from the previous small tutorial challenge post. This challenge is titled New Orleans.
new orleans
This challenge no longer holds your hand in terms of a nice and easy to follow tutorial. Instead, you are presented with the machine code and the debugger. Lets get to it!
You will immediately notice that there are a lot of functions in the beginning of the code section that do some setup work. Although important, they are not always that interesting. Instead, we are almost always only really interested in what happens once we hit the main
function.
4438 <main>
4438: 3150 9cff add #0xff9c, sp
443c: b012 7e44 call #0x447e <create_password>
4440: 3f40 e444 mov #0x44e4 "Enter the password to continue", r15
4444: b012 9445 call #0x4594 <puts>
4448: 0f41 mov sp, r15
444a: b012 b244 call #0x44b2 <get_password>
444e: 0f41 mov sp, r15
4450: b012 bc44 call #0x44bc <check_password>
4454: 0f93 tst r15
4456: 0520 jnz #0x4462 <main+0x2a>
4458: 3f40 0345 mov #0x4503 "Invalid password; try again.", r15
445c: b012 9445 call #0x4594 <puts>
4460: 063c jmp #0x446e <main+0x36>
4462: 3f40 2045 mov #0x4520 "Access Granted!", r15
4466: b012 9445 call #0x4594 <puts>
446a: b012 d644 call #0x44d6 <unlock_door>
446e: 0f43 clr r15
4470: 3150 6400 add #0x64, sp
A quick look at the call
’s that get made, we can see the flow is pretty simple. First we run a create_password
routine, then get_password
, then do a check_password
. Depending on the contents of r15
once we have done that, we will jump to unlock the lock or not.
Lets take a closer look at create_password
. This seems like an odd method to have.
447e <create_password>
447e: 3f40 0024 mov #0x2400, r15
4482: ff40 2e00 0000 mov.b #0x2e, 0x0(r15)
4488: ff40 6700 0100 mov.b #0x67, 0x1(r15)
448e: ff40 3700 0200 mov.b #0x37, 0x2(r15)
4494: ff40 4d00 0300 mov.b #0x4d, 0x3(r15)
449a: ff40 4700 0400 mov.b #0x47, 0x4(r15)
44a0: ff40 4800 0500 mov.b #0x48, 0x5(r15)
44a6: ff40 2f00 0600 mov.b #0x2f, 0x6(r15)
44ac: cf43 0700 mov.b #0x0, 0x7(r15)
44b0: 3041 ret
The create_password
routine seems to be moving some bytes (using mov.b
) at incrementing offsets relative to 0x2400
. The final mov.b
instruction at 0x44ac
moves a null byte into the last memory location before returning the method call. I guess its obvious what is going on here already.
Lets take a look at check_password
too:
44bc <check_password>
44bc: 0e43 clr r14
44be: 0d4f mov r15, r13
44c0: 0d5e add r14, r13
44c2: ee9d 0024 cmp.b @r13, 0x2400(r14)
44c6: 0520 jne #0x44d2 <check_password+0x16>
44c8: 1e53 inc r14
44ca: 3e92 cmp #0x8, r14
44cc: f823 jne #0x44be <check_password+0x2>
44ce: 1f43 mov #0x1, r15
44d0: 3041 ret
44d2: 0f43 clr r15
44d4: 3041 ret
A quick read seems like 8 cmp.b
operations are performed from the same offset we have had when create_password
started writing those bytes. So, create_password
writes the password to memory, check_password
just compares those bytes to the ones entered by the user.
Lets debug this application and see what it looks like. First, set a breakpoint just after create_password
is done at 0x4440
with break 4440
. This will let us have a peek at 0x2400
to see what that the memory looks like there. The next break point that might be interesting would be where the character comparisons are occurring in check_password
at 0x44c2
, so add another break point with break 44c2
. Finally, hit c
to continue the CPU.
Right after we hit our first breakpoint, we can see that the bytes 2e67 374d 4748 2f00
were written from 0x2400
onwards.
Using a small one-liner, we can convert the bytes that were written to ASCII and confirm it matches the section in memory:
~ ยป python -c "print '2e67374d47482f00'.decode('hex')"
.g7MGH/
I am pretty sure this is the password, so continue the CPU and enter .g7MGH/
when the interrupt prompts you for a password. Continue the CPU again until we hit our next breakpoint to see the byte comparisons occur. The CPU should step all the way though the loop for the password and finally hit the mov
instruction at 0x44ce
which sets r15
to 0x1
for that tst
instruction in main
later.
The tst
instruction on register r15
should have a non-zero return in the state register sr
, resulting in a win condition. This means the password is .g7MGH/
!
solution
Enter a password of .g7MGH/
in ASCII or 2e67374d47482f00
as hex.
other challenges
For my other write ups in the microcorruption series, checkout this link