Microcorruption CTF Addis Ababa Write-up
- 11 minsSummary:
This is a write-up of my solution to the Microcorruption CTF challenge “Addis Ababa” (LOCKIT PRO r b.03).
Right off the bat, in the description of the challenge, we get a hint dropped:
OVERVIEW
- We have verified passwords can not be too long.
- Usernames are printed back to the user for verification.
- This lock is attached the the LockIT Pro HSM-1.
Let’s see exactly how the program is going to print back the usernames to the user…
| 0010 <__trap_interrupt> | |
| 0010: 3041 ret | |
| 4400 <__init_stack> | |
| 4400: 3140 da40 mov #0x40da, sp | |
| 4404 <__low_level_init> | |
| 4404: 1542 5c01 mov &0x015c, r5 | |
| 4408: 75f3 and.b #-0x1, r5 | |
| 440a: 35d0 085a bis #0x5a08, r5 | |
| 440e <__do_copy_data> | |
| 440e: 3f40 0000 clr r15 | |
| 4412: 0f93 tst r15 | |
| 4414: 0724 jz #0x4424 <__do_clear_bss+0x0> | |
| 4416: 8245 5c01 mov r5, &0x015c | |
| 441a: 2f83 decd r15 | |
| 441c: 9f4f f446 0024 mov 0x46f4(r15), 0x2400(r15) | |
| 4422: f923 jnz #0x4416 <__do_copy_data+0x8> | |
| 4424 <__do_clear_bss> | |
| 4424: 3f40 1400 mov #0x14, r15 | |
| 4428: 0f93 tst r15 | |
| 442a: 0624 jz #0x4438 <main+0x0> | |
| 442c: 8245 5c01 mov r5, &0x015c | |
| 4430: 1f83 dec r15 | |
| 4432: cf43 0024 mov.b #0x0, 0x2400(r15) | |
| 4436: fa23 jnz #0x442c <__do_clear_bss+0x8> | |
| 4438 <main> | |
| 4438: 3150 eaff add #0xffea, sp | |
| 443c: 8143 0000 clr 0x0(sp) | |
| 4440: 3012 e644 push #0x44e6 "Login with username:password below to authenticate.\n" | |
| 4444: b012 c845 call #0x45c8 <printf> | |
| 4448: b140 1b45 0000 mov #0x451b ">> ", 0x0(sp) | |
| 444e: b012 c845 call #0x45c8 <printf> | |
| 4452: 2153 incd sp | |
| 4454: 3e40 1300 mov #0x13, r14 | |
| 4458: 3f40 0024 mov #0x2400, r15 | |
| 445c: b012 8c45 call #0x458c <getsn> | |
| 4460: 0b41 mov sp, r11 | |
| 4462: 2b53 incd r11 | |
| 4464: 3e40 0024 mov #0x2400, r14 | |
| 4468: 0f4b mov r11, r15 | |
| 446a: b012 de46 call #0x46de <strcpy> | |
| 446e: 3f40 0024 mov #0x2400, r15 | |
| 4472: b012 b044 call #0x44b0 <test_password_valid> | |
| 4476: 814f 0000 mov r15, 0x0(sp) | |
| 447a: 0b12 push r11 | |
| 447c: b012 c845 call #0x45c8 <printf> | |
| 4480: 2153 incd sp | |
| 4482: 3f40 0a00 mov #0xa, r15 | |
| 4486: b012 5045 call #0x4550 <putchar> | |
| 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 | |
| 44a6 <__stop_progExec__> | |
| 44a6: 32d0 f000 bis #0xf0, sr | |
| 44aa: fd3f jmp #0x44a6 <__stop_progExec__+0x0> | |
| 44ac <__ctors_end> | |
| 44ac: 3040 f246 br #0x46f2 <_unexpected_> | |
| 44b0 <test_password_valid> | |
| 44b0: 0412 push r4 | |
| 44b2: 0441 mov sp, r4 | |
| 44b4: 2453 incd r4 | |
| 44b6: 2183 decd sp | |
| 44b8: c443 fcff mov.b #0x0, -0x4(r4) | |
| 44bc: 3e40 fcff mov #0xfffc, r14 | |
| 44c0: 0e54 add r4, r14 | |
| 44c2: 0e12 push r14 | |
| 44c4: 0f12 push r15 | |
| 44c6: 3012 7d00 push #0x7d | |
| 44ca: b012 3845 call #0x4538 <INT> | |
| 44ce: 5f44 fcff mov.b -0x4(r4), r15 | |
| 44d2: 8f11 sxt r15 | |
| 44d4: 3152 add #0x8, sp | |
| 44d6: 3441 pop r4 | |
| 44d8: 3041 ret | |
| 44da <unlock_door> | |
| 44da: 3012 7f00 push #0x7f | |
| 44de: b012 3845 call #0x4538 <INT> | |
| 44e2: 2153 incd sp | |
| 44e4: 3041 ret | |
| 44e6 .strings: | |
| 44e6: "Login with username:password below to authenticate.\n" | |
| 451b: ">> " | |
| 451f: "That entry is not valid." | |
| 4538 <INT> | |
| 4538: 1e41 0200 mov 0x2(sp), r14 | |
| 453c: 0212 push sr | |
| 453e: 0f4e mov r14, r15 | |
| 4540: 8f10 swpb r15 | |
| 4542: 024f mov r15, sr | |
| 4544: 32d0 0080 bis #0x8000, sr | |
| 4548: b012 1000 call #0x10 | |
| 454c: 3241 pop sr | |
| 454e: 3041 ret | |
| 4550 <putchar> | |
| 4550: 2183 decd sp | |
| 4552: 0f12 push r15 | |
| 4554: 0312 push #0x0 | |
| 4556: 814f 0400 mov r15, 0x4(sp) | |
| 455a: b012 3845 call #0x4538 <INT> | |
| 455e: 1f41 0400 mov 0x4(sp), r15 | |
| 4562: 3150 0600 add #0x6, sp | |
| 4566: 3041 ret | |
| 4568 <getchar> | |
| 4568: 0412 push r4 | |
| 456a: 0441 mov sp, r4 | |
| 456c: 2453 incd r4 | |
| 456e: 2183 decd sp | |
| 4570: 3f40 fcff mov #0xfffc, r15 | |
| 4574: 0f54 add r4, r15 | |
| 4576: 0f12 push r15 | |
| 4578: 1312 push #0x1 | |
| 457a: b012 3845 call #0x4538 <INT> | |
| 457e: 5f44 fcff mov.b -0x4(r4), r15 | |
| 4582: 8f11 sxt r15 | |
| 4584: 3150 0600 add #0x6, sp | |
| 4588: 3441 pop r4 | |
| 458a: 3041 ret | |
| 458c <getsn> | |
| 458c: 0e12 push r14 | |
| 458e: 0f12 push r15 | |
| 4590: 2312 push #0x2 | |
| 4592: b012 3845 call #0x4538 <INT> | |
| 4596: 3150 0600 add #0x6, sp | |
| 459a: 3041 ret | |
| 459c <puts> | |
| 459c: 0b12 push r11 | |
| 459e: 0b4f mov r15, r11 | |
| 45a0: 073c jmp #0x45b0 <puts+0x14> | |
| 45a2: 1b53 inc r11 | |
| 45a4: 8f11 sxt r15 | |
| 45a6: 0f12 push r15 | |
| 45a8: 0312 push #0x0 | |
| 45aa: b012 3845 call #0x4538 <INT> | |
| 45ae: 2152 add #0x4, sp | |
| 45b0: 6f4b mov.b @r11, r15 | |
| 45b2: 4f93 tst.b r15 | |
| 45b4: f623 jnz #0x45a2 <puts+0x6> | |
| 45b6: 3012 0a00 push #0xa | |
| 45ba: 0312 push #0x0 | |
| 45bc: b012 3845 call #0x4538 <INT> | |
| 45c0: 2152 add #0x4, sp | |
| 45c2: 0f43 clr r15 | |
| 45c4: 3b41 pop r11 | |
| 45c6: 3041 ret | |
| 45c8 <printf> | |
| 45c8: 0b12 push r11 | |
| 45ca: 0a12 push r10 | |
| 45cc: 0912 push r9 | |
| 45ce: 0812 push r8 | |
| 45d0: 0712 push r7 | |
| 45d2: 0412 push r4 | |
| 45d4: 0441 mov sp, r4 | |
| 45d6: 3450 0c00 add #0xc, r4 | |
| 45da: 2183 decd sp | |
| 45dc: 1b44 0200 mov 0x2(r4), r11 | |
| 45e0: 8441 f2ff mov sp, -0xe(r4) | |
| 45e4: 0f4b mov r11, r15 | |
| 45e6: 0e43 clr r14 | |
| 45e8: 0b3c jmp #0x4600 <printf+0x38> | |
| 45ea: 1f53 inc r15 | |
| 45ec: 7d90 2500 cmp.b #0x25, r13 | |
| 45f0: 0720 jne #0x4600 <printf+0x38> | |
| 45f2: 6d9f cmp.b @r15, r13 | |
| 45f4: 0320 jne #0x45fc <printf+0x34> | |
| 45f6: 1f53 inc r15 | |
| 45f8: 0d43 clr r13 | |
| 45fa: 013c jmp #0x45fe <printf+0x36> | |
| 45fc: 1d43 mov #0x1, r13 | |
| 45fe: 0e5d add r13, r14 | |
| 4600: 6d4f mov.b @r15, r13 | |
| 4602: 4d93 tst.b r13 | |
| 4604: f223 jnz #0x45ea <printf+0x22> | |
| 4606: 0f4e mov r14, r15 | |
| 4608: 0f5f add r15, r15 | |
| 460a: 2f53 incd r15 | |
| 460c: 018f sub r15, sp | |
| 460e: 0941 mov sp, r9 | |
| 4610: 0c44 mov r4, r12 | |
| 4612: 2c52 add #0x4, r12 | |
| 4614: 0f41 mov sp, r15 | |
| 4616: 0d43 clr r13 | |
| 4618: 053c jmp #0x4624 <printf+0x5c> | |
| 461a: af4c 0000 mov @r12, 0x0(r15) | |
| 461e: 1d53 inc r13 | |
| 4620: 2f53 incd r15 | |
| 4622: 2c53 incd r12 | |
| 4624: 0d9e cmp r14, r13 | |
| 4626: f93b jl #0x461a <printf+0x52> | |
| 4628: 0a43 clr r10 | |
| 462a: 3740 0900 mov #0x9, r7 | |
| 462e: 4a3c jmp #0x46c4 <printf+0xfc> | |
| 4630: 084b mov r11, r8 | |
| 4632: 1853 inc r8 | |
| 4634: 7f90 2500 cmp.b #0x25, r15 | |
| 4638: 0624 jeq #0x4646 <printf+0x7e> | |
| 463a: 1a53 inc r10 | |
| 463c: 0b48 mov r8, r11 | |
| 463e: 8f11 sxt r15 | |
| 4640: b012 5045 call #0x4550 <putchar> | |
| 4644: 3f3c jmp #0x46c4 <printf+0xfc> | |
| 4646: 6e48 mov.b @r8, r14 | |
| 4648: 4e9f cmp.b r15, r14 | |
| 464a: 0620 jne #0x4658 <printf+0x90> | |
| 464c: 1a53 inc r10 | |
| 464e: 3f40 2500 mov #0x25, r15 | |
| 4652: b012 5045 call #0x4550 <putchar> | |
| 4656: 333c jmp #0x46be <printf+0xf6> | |
| 4658: 7e90 7300 cmp.b #0x73, r14 | |
| 465c: 0b20 jne #0x4674 <printf+0xac> | |
| 465e: 2b49 mov @r9, r11 | |
| 4660: 053c jmp #0x466c <printf+0xa4> | |
| 4662: 1a53 inc r10 | |
| 4664: 1b53 inc r11 | |
| 4666: 8f11 sxt r15 | |
| 4668: b012 5045 call #0x4550 <putchar> | |
| 466c: 6f4b mov.b @r11, r15 | |
| 466e: 4f93 tst.b r15 | |
| 4670: f823 jnz #0x4662 <printf+0x9a> | |
| 4672: 253c jmp #0x46be <printf+0xf6> | |
| 4674: 7e90 7800 cmp.b #0x78, r14 | |
| 4678: 1c20 jne #0x46b2 <printf+0xea> | |
| 467a: 2b49 mov @r9, r11 | |
| 467c: 173c jmp #0x46ac <printf+0xe4> | |
| 467e: 0f4b mov r11, r15 | |
| 4680: 8f10 swpb r15 | |
| 4682: 3ff0 ff00 and #0xff, r15 | |
| 4686: 12c3 clrc | |
| 4688: 0f10 rrc r15 | |
| 468a: 0f11 rra r15 | |
| 468c: 0f11 rra r15 | |
| 468e: 0f11 rra r15 | |
| 4690: 1a53 inc r10 | |
| 4692: 079f cmp r15, r7 | |
| 4694: 0338 jl #0x469c <printf+0xd4> | |
| 4696: 3f50 3000 add #0x30, r15 | |
| 469a: 023c jmp #0x46a0 <printf+0xd8> | |
| 469c: 3f50 5700 add #0x57, r15 | |
| 46a0: b012 5045 call #0x4550 <putchar> | |
| 46a4: 0b5b add r11, r11 | |
| 46a6: 0b5b add r11, r11 | |
| 46a8: 0b5b add r11, r11 | |
| 46aa: 0b5b add r11, r11 | |
| 46ac: 0b93 tst r11 | |
| 46ae: e723 jnz #0x467e <printf+0xb6> | |
| 46b0: 063c jmp #0x46be <printf+0xf6> | |
| 46b2: 7e90 6e00 cmp.b #0x6e, r14 | |
| 46b6: 0320 jne #0x46be <printf+0xf6> | |
| 46b8: 2f49 mov @r9, r15 | |
| 46ba: 8f4a 0000 mov r10, 0x0(r15) | |
| 46be: 2953 incd r9 | |
| 46c0: 0b48 mov r8, r11 | |
| 46c2: 1b53 inc r11 | |
| 46c4: 6f4b mov.b @r11, r15 | |
| 46c6: 4f93 tst.b r15 | |
| 46c8: b323 jnz #0x4630 <printf+0x68> | |
| 46ca: 1144 f2ff mov -0xe(r4), sp | |
| 46ce: 2153 incd sp | |
| 46d0: 3441 pop r4 | |
| 46d2: 3741 pop r7 | |
| 46d4: 3841 pop r8 | |
| 46d6: 3941 pop r9 | |
| 46d8: 3a41 pop r10 | |
| 46da: 3b41 pop r11 | |
| 46dc: 3041 ret | |
| 46de <strcpy> | |
| 46de: 0d4f mov r15, r13 | |
| 46e0: 023c jmp #0x46e6 <strcpy+0x8> | |
| 46e2: 1e53 inc r14 | |
| 46e4: 1d53 inc r13 | |
| 46e6: 6c4e mov.b @r14, r12 | |
| 46e8: cd4c 0000 mov.b r12, 0x0(r13) | |
| 46ec: 4c93 tst.b r12 | |
| 46ee: f923 jnz #0x46e2 <strcpy+0x4> | |
| 46f0: 3041 ret | |
| 46f2 <_unexpected_> | |
| 46f2: 0013 reti pc |
This code is significantly larger than the last one. However, it’s very clear that they changed one major thing: the use of printf() instead of puts().
Let’s just play around with the inputs and see what the program spits back out…

It looks like whatever input string we give it (e.g. AAA:BBB), the program will print back. All signs are pointing to a format string vulnerability, but let’s verify that’s actually the case by throwing a few %x's at it and seeing if we get anything interesting back…

Sweet! Upon inputting AA%x%x, we get the output AA4141, which means that we are reading two 1-byte hex-encoded parameters from the stack (i.e. the A's at the beginning of our input). I won’t spend time explaining how format string vulnerabilities work in this writeup, but you can check out scut’s whitepaper “Exploiting Format String Vulnerabilities” for a useful guide.
Now let’s try and see if we can use %n to write to a location in memory. I’ll use the input value BA%x%n to start with. Also, I’ll set a breakpoint at memory location 0x46b2 inside of login(), which is the cmp.b #0x6e, r14 instruction. This should allow us to break on the handling of the %n (n == 0x6e) format string parameter and lets us examine the registers and memory during execution.
As you can see, by using the %n parameter, we were able to overwrite the memory address 0x4142 (e.g. BA, the first two bytes of our input) with the value that was in register r10 (i.e. 0x2, the number of bytes written out by printf()). Great!
Now, let’s take a step back and see exactly what we need to do to unlock the door…
4472: b012 b044 call #0x44b0 <test_password_valid>
4476: 814f 0000 mov r15, 0x0(sp)
447a: 0b12 push r11
447c: b012 c845 call #0x45c8 <printf>
4480: 2153 incd sp
4482: 3f40 0a00 mov #0xa, r15
4486: b012 5045 call #0x4550 <putchar>
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>
Inside of main(), we can see that after the call to printf() returns, the instruction tst 0x0(sp) will execute. This instruction will test the sp register against 0x0, and will jump over the unlock_door() call if it’s zero. Let’s set a breakpoint this on instruction and input AAAA and see what the registers look like…

Looks like 0x40c4 has a 0x0 value and indeed prevents the call to unlock_door() from executing. I wonder what will happen if we use our newly weaponized format string vulnerability and write a non-zero value to the sp register (location 0x40c4)…

![]()
Flag (mouse over to reveal)
c4402578256e