07 Microcorruption - Montevideo
From Canada to the capital of Uruguay, Montevideo
Manual
Lockitall LOCKIT PRO r c.03
______________________________________________________________________
User Manual: Lockitall LockIT Pro, rev c.03
______________________________________________________________________
OVERVIEW
- Lockitall developers have rewritten the code to conform to the
internal secure development process.
- This lock is attached the the LockIT Pro HSM-2.
DETAILS
The LockIT Pro c.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 HSM-2. 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 2 stores the login password,
ensuring users can not access the password through other means.
The LockIT Pro can send the LockIT Pro HSM-2 a password, and the
HSM will directly send the correct unlock message to the LockIT
Pro Deadbolt if the password is correct, otherwise no action is
taken.
This is Hardware Version C. 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-2 should be
connected to port 2.
This is Software Revision 03. We have received unconfirmed reports
of issues with the previous series of locks. We have reimplemented
much of the code according to our internal Secure Development
Process.
(c) 2013 LOCKITALL Page 1/1
This lock also has the HSM-2, and they apparently got an internal secure development process. I wonder what that means.
Enumeration
Nothing interesting happens in the prologue, we are back at the initial stack pointer is 0x4400
Main
β int main(int argc, char **argv, char **envp);
β° 0x4438 call #login
I am starting to see a pattern here π
Login
β login();
β 0x44f4 add #0xfff0, sp
Again we calculate the stack pointer 0x4400 - 0x2 + 0xfff0 = 0x143ee
, the new stack pointer is 0x43ee
this again give us 16 byte stack space for login
and the return address in byte 17 and 18, I guess that is no in the internal secure development process π
β 0x44f8 mov #0x4470, r15
β 0x44fc call #puts
β 0x4500 mov #0x4490, r15
β 0x4504 call #puts
Two prints, we have seen this before.
β 0x4508 mov #0x0030, r14
β 0x450c mov #0x2400, r15
β 0x4510 call #getsn
And again reading 48 bytes, but not to the stack, instead to 0x2400
, so we do actually not overwrite the return address π€
β 0x4514 mov #0x2400, r14
β 0x4518 mov sp, r15
β 0x451a call #strcpy
This is new, a function called strcpy
(string copy) using the address of our password and the stack pointer.
β 0x451e mov #0x0064, r13
β 0x4522 clr r14
β 0x4524 mov #0x2400, r15
β 0x4528 call #memset
This is also new, a memset
function, with three arguments, last one being our password input.
β 0x452c mov sp, r15
β 0x452e call #conditional_unlock_door
β 0x4532 tst r15
β ββ< 0x4534 jeq $+0x0008
β β 0x4536 mov #0x44c5, r15
β βββ< 0x453a jmp $+0x0006
β ββ°β> 0x453c mov #0x44d5, r15
β β°ββ> 0x4540 call #puts
Back to some familiar code, we do a conditional_unlock_door
call and prints depending on the result from conditional_unlock_door
β 0x4544 add #0x0010, sp
β° 0x4548 ret
Lastly some stack cleanup and return.
Memset
The memset
function is not too interesting, it takes three arguments
- How many bytes to set
- What value to set them to
- Where the bytes are
The use here will set 0x64
bytes at address 0x2400
(where our password input is written) to zero, this function just writes zeros to clear our password input from memory.
Strcpy
But before we call memset
we did a call to strcpy
so lets see what this function does. Keep in mind that our input is R14 = 0x2400
and R15 = sp
β char *strcpy(char *dest, const char *src);
β 0x45dc mov r15, r13
β ββ< 0x45de jmp $+0x0006
β βββ> 0x45e0 inc r14
β ββ 0x45e2 inc r13
β ββ°β> 0x45e4 mov.b @r14, r12
β β 0x45e6 mov.b r12, 0x0(r13)
β β 0x45ea tst.b r12
β β°ββ< 0x45ec jnz $-0x000c
β° 0x45ee ret
Through some extra steps, the code end up copying bytes from R14
to R15
so in our case from 0x2400
to SP
, and this loop keeps running until a byte is zero, because the conventions is that strings end with a null byte. But we can actually still overwrite the return address with our input because this just blindly copy our input to the stack.
If we look at the byte code from the last lock
push #0x007f 30 12 7f 00
call #INT b0 12 32 45
We can see that the push
instruction we want to use contains a null byte, so the strcpy
function will stop copying bytes when we reach this byte. We need to figure out how to avoid the zero byte in our payload. There are a lot of ways to avoid zero bytes, so there are a lot of ways to hack this lock.
Letβs look at one way
mov #0xff80, r15 3f 40 80 ff
xor #0xffff, r15 3f e0 ff ff
push r15 0f 12
call #INT b0 12 32 45
If we move the value 0xff80
into R15
and then xor
it with the value 0xffff
, R15
will then contain the value 0x007f
, this value then is pushed to the stack, and we call the INT
function.
We now have a new payload without zero bytes, we then need to pad it to 16 bytes and the address of our payload as in the previous lock.