Unlock the SAFE Write-up Hacking Village 2019

During DefCamp 2019, certSIGN organised a competition in the Hacking Village called Unlock the SAFE. The challenge description was straight forward:

You have to unlock a SAFE. You know that the lock is radio controlled and uses encryption for payload. Reverse, listen, learn, disable.

Step 1 – Initial parameters

You get to listen to RF communication and a firmware image compiled for the NodeMCU 1.0. From the firmware we can see in the loop function of the code that there is a sequence of commands sent by the client and ACKs from the SAFE.

We identify also that encryption is used, with one “GeneralKey” and one “FlagKey” and also we can see that the frequency and modulation are modified during runtime using random values from a list.

Step 2 – Reconnaissance

Listening to the communication reveals the format of the packets: frequency, modulation, data. Every time the SAFE sends the ACK, the new parameters (frequency and modulation) are used for next packet. As we can see from the decompiled code we have two encryption mechanisms:

if (param_3 == '\x10') {
SetGeneralKey(this_00,pAVar1);
EncryptData(this_00,(Cipher *)(this->cryptoHelper).cbcaes128,pAVar1);
memcpy(param_2,(this->cryptoHelper).encryptor.ciphertext,(this->cryptoHelper).encryptor.datasize
);
}
else {
SetFlagKey(this_00,pAVar1);
EncryptData(this_00,(AuthenticatedCipher *)(this->cryptoHelper).gcmaes128,pAVar1);

specifically AES GCM 128 and AES CBC 128. From the function names we can see that CBC is a general key cipher and GCM is reserved for the flag.

Step 3 – Crypto parameters

In the constructor for the crypto class we can see that some variables are initialized with data from memory:

memcpy(this,&DAT_3ffe8540,0x14);
memcpy((void *)((int)this + 0x14),&DAT_3ffe8554,0x10);
memcpy((void *)((int)this + 0x24),&DAT_3ffe8554,0x10);
memcpy((void *)((int)this + 0x34),&DAT_3ffe8564,0x10);

A length of 0x14 means a usual authentication tag and a length of 0x10 is a key or IV length. We extract the data at the corresponding addresses.

Listening to the communication we identify also the IV for the communication but trying to decrypt the messages send between base and client with either keys does not work, however we can see that messages are repeating themselves each 4 cycles, and every cycle starts with 443 and OOK.

Step 4 – Disassembly of the commands

Knowing already that the cipher used for the usual communication is CBC we return to analysis of the decompiled/disassembled program trying to locate the messages. We can see that the constructor for RF_Core does some interesting operations on strings and reversing it we can find our commands:

0x588 -> 0x55 (U)
0x589 -> 0x4e (N)
0x58a -> 0x4b (K)
0x58b -> 0x4e (N)
0x58c -> 0x4f (O)
0x58d -> 0x57 (W)
0x58e -> 0x4e (N)
0x58f -> 0x0
.....
0x598 -> 0x48 (H)
0x599 -> 0x45 (E)
0x59a -> 0x4c (L)
0x59b -> 0x4c (L)
0x59c -> 0x4f (O)
.....
0x5a7 -> 0x0
0x5a8 -> 0x41 (A)
0x5a9 -> 0x43 (C)
0x5aa -> 0x4b (K)
....
0x5b7 -> 0x0
0x5b8 -> 0x41 (A)
0x5b9 -> 0x55 (U)
0x5ba -> 0x54 (T)
0x5bb -> 0x48 (H)
0x5bc -> 0x0
.....
0x5c8 -> 0x43 (C)
0x5c9 -> 0x4f (O)
0x5ca -> 0x44 (D)
0x5cb -> 0x45 (E)
....
0x5d7 -> 0x0
0x5d8 -> 0x43 (C)
0x5d9 -> 0x4f (O)
0x5da -> 0x4d (M)
0x5db -> 0x4d (M)
0x5dc -> 0x41 (A)
0x5dd -> 0x4e (N)
0x5de -> 0x44 (D)
....
0x5e7 -> 0x0
0x5e8 -> 0x55 (U)
0x5e9 -> 0x4e (N)
0x5ea -> 0x4b (K)
0x5eb -> 0x4e (N)
0x5ec -> 0x4f (O)
0x5ed -> 0x57 (W)
0x5ee -> 0x4e (N)
....
0x5f7 -> 0x0
0x5f8 -> 0x52 (R)
0x5f9 -> 0x45 (E)
0x5fa -> 0x41 (A)
0x5fb -> 0x52 (R)
0x5fc -> 0x4d (M)
0x5fd -> 0x0
....
0x607 -> 0x0
0x608 -> 0x44 (D)
0x609 -> 0x49 (I)
0x60a -> 0x53 (S)
0x60b -> 0x41 (A)
0x60c -> 0x52 (R)
0x60d -> 0x4d (M)
....
0x617 -> 0x0
0x618 -> 0x46 (F)
0x619 -> 0x4c (L)
0x61a -> 0x41 (A)
0x61b -> 0x47 (G)

And following loop code:

4020118b 31 e8 ff l32r a3=>s_send_HELLO_3ffe8685,PTR_s_send_HELLO_402 = "send HELLO"
402011c3 31 dd ff l32r a3=>s_no_ACK_for_Hello_3ffe8690,PTR_s_no_ACK_f = "no ACK for Hello"b8(j)
402011c9 31 dc ff l32r a3=>s_send_AUTH_3ffe86a1,PTR_s_send_AUTH_40201 = "send AUTH"
4020120b 31 ce ff l32r a3=>s_no_ACK_for_AUTH_3ffe86ab,PTR_s_no_ACK_fo = "no ACK for AUTH"
40201211 31 cd ff l32r a3=>s_send_CODE_3ffe86bb,PTR_s_send_CODE_40201 = "send CODE"
40201261 31 bb ff l32r a3=>s_no_ACK_for_CODE_3ffe86c5,PTR_s_no_ACK_fo = 3ffe86c5
                                                                         = "no ACK for CODE"
40201279 31 b6 ff l32r a3=>s_send_DISARM_3ffe86d5,PTR_s_send_DISARM_4 = "send DISARM"
                                                                         = "no ACK for COMMAND_DISARM"
                                                                         = "send FLAG"
                                                                         = "no ACK for COMMAND_FLAG"
                                                                         = "waiting for raw message"

Step 5 – Exploit AES CBC vulnerability

We now know that the last command is REARM and in order to disarm the safe we need to send instead the DISARM command followed by FLAG command.
In order to achieve that, we exploit the CBC bit flipping vulnerability and modify the IV of the last message to transform the command REARM
into two commands DISARM and FLAG.

Step 7 – Get the flag

Having computed this message, since every time there are more than 2 seconds between messages, we construct a program which follows the
commands from the client, shifting frequency and modulation starting from the initial state (OOK, 443). Between the third and fourth message,
immediately after the SAFE returns ACK, we inject our crafted packet, effectively DISARMING the SAFE.

Now, we can send the FLAG command and using the flagKey from the binary and the AES 128 GCM algorithm we can decrypt the flag.

    Related articles​

    Capture the Firmware Write-up Hacking Village 2019

    BY defcamp
    During DefCamp 2019, Garret Advancing Motion organised a competition in the Hacking Village called Capture the..

    🏁👀🚧🎁📵 Unleash your creativity in ..

    BY andra.zaharia
    Can you believe it’s almost November? 🙀 Just one month from now we’ll be opening the doors to the ..

    🙌 These D-CTF teams made it to the final!

    BY defcamp
    They gave it their best and made to the DefCamp Capture the Flag top 20!  On September 7, 2019, 500 teams ..