Microcorruption CTF Addis Ababa Write-up

Microcorruption CTF Addis Ababa Write-up

- 11 mins

Summary:

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…

Addis Ababa Test Input 1

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…

Addis Ababa Test Input 2

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…

Addis Ababa Test Input 3

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)…

Addis Ababa Solve

:+1: :beers:

Flag (mouse over to reveal)

c4402578256e

jiva

jiva

Security guy, busticati, professional button-pusher

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