Technical Analysis - A Compromise of a Bluetooth Smart Lock
This article details the successful compromise of a commercially available Bluetooth-enabled smart lock supporting fingerprint and wireless unlocking. The analysis involves reverse engineering of the mobile application, manipulation of backend API calls, and interception of the lock’s Bluetooth Low Energy (BLE) communication protocol.
The investigation was conducted using dynamic instrumentation and a BLE man-in-the-middle toolkit. By combining multiple weaknesses in the system's architecture, we were able to register and control a lock without possessing or being near the physical device. This led to full compromise of its unlock functionality.
Overview
This research focused on two key components:
The communication between the Android mobile application and the remote API server.
The BLE communication between the mobile application and the lock itself.
Access was achieved by chaining together an insecure device binding API, static key cryptography, and a custom, unprotected BLE protocol. The BLE channel, although encrypted, lacked any meaningful integrity or replay protection.
All BLE traffic was intercepted and analyzed using BLE:Bit, a powerful BLE research platform and toolset that allowed live traffic monitoring and active command injection. The tool was essential in intercepting and replaying commands during this research. We originally developed this tool in-house to support our own security assessments, including research like this. It was later released as an open-source project to benefit the broader security community.
Registering a Lock Without Ownership
The Android app binds locks to user accounts via a simple HTTP POST request. This should only be permitted when the physical lock is nearby and discoverable via BLE. However, we discovered that the server permitted binding based solely on knowledge of the lock’s MAC address.
Example request (values redacted):
POST /lock/bind
Headers:
token: <redacted>
uid: <redacted>
Body:
{
"name": "lock1",
"userId": <redacted>,
"mac": "<redacted>"
}
This endpoint responded successfully even when sent from a device not in proximity to the lock and not previously associated with it. No cryptographic challenge, proximity validation, or ownership proof was required.
Extracting Lock Credentials via API
Once a lock is registered to a user account, the mobile application retrieves lock details from the API using another POST request:
POST /lock/getLockList
Body:
{
"userId": <redacted>
}
The server’s response includes a field named encryptedData
, which contains encrypted lock credentials. These credentials include the lock key (used for BLE encryption), the BLE password, and the MAC address.
Sample response:
{
"name": "lock1",
"mac": "<redacted>",
"encryptedData": "RUQ2RDJCODZFQ...=="
}
Decryption of encryptedData
Using a Static Key
Upon decompiling the application, we found the following decryption logic:
public void setData() {
String[] split = new String(
b.b(
c.a(new String(Base64.decodeBase64(this.encryptedData.getBytes()))),
c.a("58966742920123314112157843194045")
)
).split("&");
this.lockKey = split[0];
this.lockPwd = split[1];
this.mac = split[2].trim();
}
The AES key 58966742920123314112157843194045 was hardcoded and used to decrypt lock credentials. The app used AES in ECB mode with no padding (AES/ECB/NoPadding). This design is insecure and means every lock’s secret data can be decrypted offline by anyone with access to the app binary.
A decrypted payload produced:
lockKey: <redacted> lockPwd: <redacted> mac: <redacted>
These values were sufficient to craft valid BLE messages for unlocking the device.
BLE Protocol Structure
The communication between the mobile application and the smart lock relies on Bluetooth Low Energy (BLE) and operates through two specific GATT characteristics:
0x36f5 – Used by the mobile application to write encrypted commands to the lock.
0x36f6 – Used by the smart lock to send encrypted notifications back to the application.
All messages are encrypted using AES in ECB mode with no padding. The encryption key (lockKey) is extracted from the decrypted encryptedData value, which is unique per lock but can be retrieved due to the use of a globally hardcoded AES key.
Each command is a 16-byte message composed of:
Opcode (2 bytes): Defines the action (e.g., unlock, query battery).
Parameters (variable length): Payload depending on command type.
Random padding (up to 16 bytes total): Fills out the block to a full 16 bytes.
The result is then encrypted with the lockKey before transmission.
Responses from the lock follow the same structure but may contain status bytes, data, or acknowledgments.
The mobile app and lock communicate using this symmetric encryption channel without any form of MAC (Message Authentication Code), nonce, or rolling sequence number. This makes the protocol vulnerable to replay and injection attacks, as observed in the field.
Each message is treated as an independent, atomic block. There is no session context, authentication handshake, or stateful pairing after initial connection. This is atypical for secure BLE implementations, where session keys, pairing methods (e.g., Just Works, Passkey), and authenticated characteristics are used to prevent tampering.
From a forensic or offensive perspective, this structure makes the protocol straightforward to reverse and emulate, especially when the message format is consistent and the encryption key is discoverable.
Sniffed Traffic
Using BLE:Bit’s MiTM capabilities, we captured real-time BLE traffic between the mobile application and the lock.
Below is an excerpt of observed traffic:
WRITE Android → SmartLock @ 0x36f5: 3E 62 BB 1D F5 6C 60 94 84 E0 E3 87 26 0A 8B BE
NOTIFY SmartLock → Android @ 0x36f6: 93 C6 50 7E 00 79 94 24 6E 6E 40 EA D7 F8 86 7E
WRITE Android → SmartLock @ 0x36f5: FC B1 5D A6 3E 3C DD E4 56 72 60 2D 03 34 84 98
NOTIFY SmartLock → Android @ 0x36f6: DE 4F 0D BB F5 1B 34 08 5F DD F9 FC 59 A9 C5 EF
WRITE Android → SmartLock @ 0x36f5: C6 9D BC DA 2F 39 C7 AD 32 8D DA 21 B2 14 61 FE
NOTIFY SmartLock → Android @ 0x36f6: DE 4F 0D BB F5 1B 34 08 5F DD F9 FC 59 A9 C5 EF
From these patterns, we observed that each write command from the app was met with a corresponding BLE notification from the lock. The contents of the messages varied with operation types but were consistently 16 bytes in size and AES-encrypted.
Each operation — such as open lock, query status, or reset password — had a specific opcode. For example, OPEN_LOCK
was identified as 0501
in the application's BLE message definition enum.
Constructing and Sending Unlock Commands
The unlock command is constructed in the app by a class similar to the following:
public class i extends z {
public i(String password) {
super(TYPE.OPEN_LOCK);
char[] chars = password.toCharArray();
a((byte) 6, (byte) chars[0], ..., (byte) chars[5]);
}
}
Once constructed, the payload is encrypted and transmitted using:
BLEService.a(context, b.a(new i("000000")));
By extracting the password from the decrypted encryptedData
, we were able to replicate this sequence and issue an unlock command ourselves from a custom script.
Replay Vulnerability
BLE messages were static and reusable. Because no freshness mechanism was implemented (e.g., nonce, counter, or session token), we were able to capture a valid unlock message and replay it later with success. No additional authentication or time-based validation occurred on the lock side.
This constitutes a full replay attack vulnerability and would allow any nearby attacker to capture and reuse unlock commands.
Root Cause Analysis
The compromise was made possible by several design failures:
The device binding API lacked proper authorization and proximity validation
Encryption used a static key embedded in the client
BLE communication lacked any message integrity or replay protection
The application code revealed all internal cryptographic operations and protocol definitions without obfuscation
Recommendations
To prevent this class of attack, manufacturers should consider the following improvements:
Enforce physical proximity checks during binding via BLE challenge-response
Provision per-device cryptographic keys securely during manufacturing
Use message authentication codes (MACs) with nonce or counter to prevent replay attacks
Replace ECB mode with authenticated encryption (e.g., AES-GCM.
Obfuscate mobile application code and prevent dynamic inspection via Frida or similar tools
Conclusion
Through this research, we demonstrated that a combination of insecure API design, weak cryptographic practices, and poor BLE protocol implementation can result in full device compromise.
We were able to:
Register a lock without physical possession
Retrieve and decrypt its private credentials
Construct and transmit BLE commands to unlock the device
Replay previously captured BLE traffic for unauthorized access
This case highlights the urgent need for embedded security best practices in smart device development. It is not sufficient to encrypt data — the entire lifecycle of key management, communication, and user control must be secured.
Future research may explore additional BLE commands, fingerprint bypass vectors, or over-the-air update mechanisms if present.
Secure by Design. Tested in the Real World
This kind of research isn’t theoretical—it reflects real vulnerabilities found in real products currently on the market. If you're building smart locks, connected devices, or BLE-enabled systems, ask yourself:
Has your product been tested like this?
At our firm, we specialize in uncovering and mitigating exactly these kinds of flaws—before attackers do. From reverse engineering and protocol fuzzing to full-stack API abuse scenarios, we provide deep technical security assessments tailored to embedded and IoT products.
Ready to harden your product?
Let’s talk.
More Bluetooth Hacking
Would you like to learn more on how to hack bluetooth @anything ? Subscribe, and if you are already a subscriber, stay tuned for more!