Microcorruption CTF New Orleans Write-up

Microcorruption CTF New Orleans Write-up

- 3 mins

Summary:

This is a write-up of my solution to the Microcorruption CTF challenge “New Orleans” (LOCKIT PRO r a.01).

Let’s begin by first taking a look inside 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 few things look interesting. First, a call to a function called create_password(), then eventually a call to a function called check_password(). We can see that after the call to check_password(), r15 is compared with zero. If r15 is not zero, execution will jump to 0x4462, which will print the access granted message and will call the unlock_door() routine. First, let’s see what create_password() is doing:

447e <create_password>
447e: 3f40 0024 mov #0x2400, r15
4482: ff40 4200 0000 mov.b #0x42, 0x0(r15)
4488: ff40 3c00 0100 mov.b #0x3c, 0x1(r15)
448e: ff40 5b00 0200 mov.b #0x5b, 0x2(r15)
4494: ff40 4600 0300 mov.b #0x46, 0x3(r15)
449a: ff40 5a00 0400 mov.b #0x5a, 0x4(r15)
44a0: ff40 4000 0500 mov.b #0x40, 0x5(r15)
44a6: ff40 4100 0600 mov.b #0x41, 0x6(r15)
44ac: cf43 0700 mov.b #0x0, 0x7(r15)
44b0: 3041

We can see that 8 bytes are being loaded into the memory location at 0x2400. Cool. Let’s keep this in mind and check out what’s going on inside check_password():

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

We can see that the instruction cmp.b @r13, 0x2400(r14) will compare the memory location pointed to from r13 (the location of the first byte of our input) with the byte located at memory address 0x2400 (the location of the memory containing 8 bytes set by the previous call to create_password()). These instructions will then loop, comparing each byte from memory with a byte from the input. If the comparison does not succeed, the following instruction jne #0x44d2 <check_password+0x16> will jump the execution to 0x44d2, which will clear the r15 register and return to main(). Because r15 contains 0 at this point, the subsequent tst instruction (in main()) will fail and execution will not reach unlock_door(). However, if the byte comparisons succeed, 0x1 will be loaded into r15, and execution will return to main() at which point the tst instruction will succeed. Let’s input the bytes that we noted from the call to create_password() and see what happens…

Microcorruption New Orleans Solved

Flag (mouse over to reveal)

B<[FZ@A

jiva

jiva

Security guy, busticati, professional button-pusher

rss hackthebox keybase facebook twitter github youtube mail spotify lastfm instagram linkedin google google-plus pinterest medium vimeo stackoverflow reddit quora quora