blog/03-microcorruption

03 Microcorruption - Hanoi

We now take a trip from Sydney up to Hanoi

Manual
Lockitall                                            LOCKIT PRO r b.01
______________________________________________________________________

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


OVERVIEW

    - This lock is attached the the LockIT Pro HSM-1.
    - We have updated  the lock firmware  to connect with the hardware
      security module.

DETAILS

    The LockIT Pro b.01  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 01,  allowing it to communicate with the
    LockIT Pro HSM-1


(c) 2013 LOCKITALL                                            Page 1/1

Reconnaissance

The manual here states that this lock is now connected to some external hardware, the HSM-1 (Hardware Security Module). If we take a look in the Lockitall Manual1 we find the following about the HSM-1

HSM-1

This is great new for them, much better to not hard-coded the password in the code, it does however present a challenge for us. We want to open the lock, and as before we don’t know the password, but this time we will not be able to find the password in the code, so we have to find a way to open the lock without the password.

Enumeration

Let’s see if we can find some way to do this by looking at the code

Main

We start in main

int main(int argc, char **argv, char **envp);
0x4438      call  #login
0x443c      clr   r15

Well, that fast easy, lets look at login

login

╭ login();
0x4520      clr.b &0x2410

Here we clear a byte a 0x2410, this seems a bit strange. Nothing has touched this byte before this function, let’s keep 0x2410 in mind

0x4524      mov   #0x447e, r15
           ; "Enter the password to continue."
0x4528      call  #puts
0x452c      mov   #0x449e, r15
           ; "Remember: passwords are between 8 and 16 characters."
0x4530      call  #puts
0x4534      mov   #0x001c, r14
0x4538      mov   #0x2400, r15
0x453c      call  #getsn

This part we have seen before, the code prints two times, a new part tho is that we now get a hint about the password length being between 8 and 16 that is new. After the prints the code asks us to input a password. Notice the 0x2400 argument to the getsn function. This is 16 bytes before the 0x2410 byte that this function cleared in the start, and our password limit is 16, seems interesting.

0x4540      mov   #0x2400, r15
0x4544      call  #test_password_valid
0x4548      tst   r15

Next we pass the password buffer to test_password_valid and test if R15 is zero, here R15 must be the return value of the test_password_valid function, and whether the password was valid or not

│       ╭─< 0x454a      jeq   $+0x0008
│       │   0x454c      mov.b #0x006d, &0x2410
│       ╰─> 0x4552      mov   #0x44d3, r15
0x4556      call  #puts

If test_password_valid return a zero in R15 we jump over one instruction. This instruction is messing with the 0x2410 address we saw in the start, moving 0x6D into its place. Afterward we do another print.

0x455a      cmp.b #0x0002, &0x2410
│       ╭─< 0x4560      jnz   $+0x0010
│       │   0x4562      mov   #0x44f1, r15
│       │   0x4566      call  #puts
│       │   0x456a      call  #unlock_door
│       │   0x456e      ret
│       ╰─> 0x4570      mov   #0x4501, r15
0x4574      call  #puts
0x4578      ret

The last piece of the code compare this mystery address with the value 0x02 which seem a bit strange. This function started by clearing it, so it contains zero, then depending on the result of test_password_valid it will contain either 0x6D or keep the zero. Reading forward we see that we need this comparison to be true for the code to call unlock_door

test_password_valid

Let’s take a look at test_password_valid to see if this function will write 0x02 to 0x2410

╭ test_password_valid();
0x4454      push  r4
0x4456      mov   sp, r4
0x4458      incd  r4
0x445a      decd  sp
0x445c      clr.b 0xfffc(r4)
0x4460      mov   #0xfffc, r14
0x4464      add   r4, r14
0x4466      push  r14
0x4468      push  r15
0x446a      push  #0x007d
0x446e      call  #INT
0x4472      mov.b 0xfffc(r4), r15
0x4476      sxt   r15
0x4478      add   #8, sp
0x447a      pop   r4
0x447c      ret

It does not look like this code is doing anything with the value in 0x2410

Exploit

Remember that the lock tells us that the password length is between 8 and 16, and the 0x2410 is 16 bytes after the where our password is stored. What if we input a password that has 17 bytes? Then we would be the ones writing to that 0x2410 address. This kind of vulnerability is known as an overflow. We are inputting more data than the code expects, and the code does not check and handle that case, so the input is just written to memory.

Let’s try to use the web debugger and input the character ‘A’ 17 times

0160: 0000 0000 0000 0000 0000 0000 0000 0000   ................
0170: *
2400: 4141 4141 4141 4141 4141 4141 4141 4141   AAAAAAAAAAAAAAAA
2410: 4100 0000 0000 0000 0000 0000 0000 0000   A...............
2420: 0000 0000 0000 0000 0000 0000 0000 0000   ................
2430: *
43f0: 8e45 0000 d845 0200 0024 1c00 4045 3c44   .E...E...$..@E<D

Looking at the Live Memory Dump in the web debugger, right after we have inputted the A’s we can see them starting at address 0x2400 and surprise, the last ‘A’ is at the 0x2410. Recall from the login we want a 0x02 here, so if we input 16 characters and then a 0x02 the unlock_door should be called. NOTE: there is a checkbox when inputting the password where we can tell it to take raw hex input.

Door unlocked

From my reverse engineering this code will no work even with the correct password, nothing in the code sets address 0x2410 to 0x02, if you see that I have missed something please write me


1

Lockitall manual

/microcorruption/