From 96f148a770e26309c2b0ec44b5d93e2095167f10 Mon Sep 17 00:00:00 2001 From: "a.edenhauser" Date: Fri, 23 Oct 2026 08:57:05 +0200 Subject: [PATCH] doc0 - 2.6, 2.7 --- Document0-Initial_Information_Gathering.md | 15 +- ...att_FF-EC-EE-E7-32-E5_20261023_085131.json | 87 +++++++++ ...y_report_FFECEEE732E5_20261023_085351.json | 182 ++++++++++++++++++ 3 files changed, 280 insertions(+), 4 deletions(-) create mode 100644 toothfairy_reports/gatt_FF-EC-EE-E7-32-E5_20261023_085131.json create mode 100644 toothfairy_reports/toothfairy_report_FFECEEE732E5_20261023_085351.json diff --git a/Document0-Initial_Information_Gathering.md b/Document0-Initial_Information_Gathering.md index 5e80b88..99f7a39 100644 --- a/Document0-Initial_Information_Gathering.md +++ b/Document0-Initial_Information_Gathering.md @@ -153,7 +153,7 @@ Once again, it reported no critical or high findings. > The old init capture supposedly was the first real fresh setup. As mentioned, the lock has been tempered with before. -### URLs and Endpoints +## 2.6 Port Scan I used the PreTester to probe all URLs and endpoints, here are some (interesting) findings: @@ -161,11 +161,19 @@ While most of ports are common for HTTPS and SSH, there are a few interesting on - 31234 onshelly-101-eu.shelly.cloud: [Nmap scan](nmap/shelly-101-eu-shelly-cloud.nmap) revealed no more information - 6113 on shelly-120-eu.shelly.cloud: [Nmap scan](nmap/shelly-120-eu-shelly-cloud.nmap) found ports 6115, 6022, 8007, 6114 - It may be important to note that scan took significantly more time (almost 1h) and was eventually aborted - - **#TODO: RESCAN TMRW** + - **#TODO: RESCAN** - 9443 on shelly-infra1-eu.shelly.cloud: widely recognized as an alternative or **administrative** HTTPS port - 8883 on mqtt.production.loqed.com: official standard port designated for MQTT over TLS (MQTTS) -Some playing around with Metasploit's `check` on these 2 endpoints couldn't find anything either. +Some playing around with Metasploit's `check` on these 2 cloud endpoints couldn't find anything either. + +## 2.7 BLE + +I ran ToothFairy on the lock. It's advertising name is "Loqed Inside" and it uses a fixed MAC address `FF:EC:EE:E7:32:E5`. + +I obtained the [GATT table](toothfairy_reports/gatt_FF-EC-EE-E7-32-E5_20261023_085131.json) and a very incomplete [test report](toothfairy_reports/toothfairy_report_FFECEEE732E5_20261023_085351.json), due to a lack of hardware. + +However, ToothFairy labelled `WRLS-FUZZ-002` as `FAIL`, due to the target not recovering after malformed packets were sent. ## 1.8 Collect Firmware Dump of Firmware after initial Setup @@ -193,4 +201,3 @@ Some playing around with Metasploit's `check` on these 2 endpoints couldn't find ## 2.5 Inspection of Device During Normal Usage -## 2.6 Port Scan diff --git a/toothfairy_reports/gatt_FF-EC-EE-E7-32-E5_20261023_085131.json b/toothfairy_reports/gatt_FF-EC-EE-E7-32-E5_20261023_085131.json new file mode 100644 index 0000000..9cbb634 --- /dev/null +++ b/toothfairy_reports/gatt_FF-EC-EE-E7-32-E5_20261023_085131.json @@ -0,0 +1,87 @@ +{ + "mac_address": "FF:EC:EE:E7:32:E5", + "timestamp": "2026-10-23 08:51:27", + "services": [ + { + "service_uuid": "00001800-0000-1000-8000-00805f9b34fb", + "service_name": "Generic Access", + "characteristics": [ + { + "handle": 8, + "uuid": "00002aa6-0000-1000-8000-00805f9b34fb", + "name": "00002aa6-0000-1000-8000-00805f9b34fb", + "properties": "READ", + "value_hex": "01" + }, + { + "handle": 2, + "uuid": "00002a00-0000-1000-8000-00805f9b34fb", + "name": "Device Name", + "properties": "READ|WRITE", + "value_hex": "4c6f71656420496e73696465" + }, + { + "handle": 6, + "uuid": "00002a04-0000-1000-8000-00805f9b34fb", + "name": "00002a04-0000-1000-8000-00805f9b34fb", + "properties": "READ", + "value_hex": "ffffffff0000ffff" + }, + { + "handle": 4, + "uuid": "00002a01-0000-1000-8000-00805f9b34fb", + "name": "Appearance", + "properties": "READ", + "value_hex": "0000" + } + ] + }, + { + "service_uuid": "00001801-0000-1000-8000-00805f9b34fb", + "service_name": "Generic Attribute", + "characteristics": [ + { + "handle": 11, + "uuid": "00002a05-0000-1000-8000-00805f9b34fb", + "name": "00002a05-0000-1000-8000-00805f9b34fb", + "properties": "INDICATE", + "value_hex": null + } + ] + }, + { + "service_uuid": "bdce0001-e90d-4685-b89d-5578cd199a9f", + "service_name": "bdce0001-e90d-4685-b89d-5578cd199a9f", + "characteristics": [ + { + "handle": 18, + "uuid": "bdce0102-e90d-4685-b89d-5578cd199a9f", + "name": "bdce0102-e90d-4685-b89d-5578cd199a9f", + "properties": "READ|INDICATE", + "value_hex": "01eba8bd1eef947846d8aaf7020e5b8728a13e1d9065224487d0525b16ab105e36" + }, + { + "handle": 25, + "uuid": "bdce0104-e90d-4685-b89d-5578cd199a9f", + "name": "bdce0104-e90d-4685-b89d-5578cd199a9f", + "properties": "READ|INDICATE", + "value_hex": "01828813069ae1d6d046ece86e9bd0fd01ce500b5389caa95f45869b216c332d59c48ef6a6aad6cd74c1ee26959dedaf9e710ce2d14784c334e9faf4211628de1f5ffe3a4e90e1a209dd480bfd64f3ebae96dadcff4146010a507d015b28601f83" + }, + { + "handle": 15, + "uuid": "bdce0101-e90d-4685-b89d-5578cd199a9f", + "name": "bdce0101-e90d-4685-b89d-5578cd199a9f", + "properties": "WRITE", + "value_hex": null + }, + { + "handle": 22, + "uuid": "bdce0103-e90d-4685-b89d-5578cd199a9f", + "name": "bdce0103-e90d-4685-b89d-5578cd199a9f", + "properties": "WRITE", + "value_hex": null + } + ] + } + ] +} \ No newline at end of file diff --git a/toothfairy_reports/toothfairy_report_FFECEEE732E5_20261023_085351.json b/toothfairy_reports/toothfairy_report_FFECEEE732E5_20261023_085351.json new file mode 100644 index 0000000..a3ab83e --- /dev/null +++ b/toothfairy_reports/toothfairy_report_FFECEEE732E5_20261023_085351.json @@ -0,0 +1,182 @@ +{ + "timestamp": "2026-10-23 08:53:51", + "target": { + "mac": "FF:EC:EE:E7:32:E5", + "address_type": "PUBLIC", + "vendor": "Unknown", + "rssi": -56, + "connectable": true, + "name": "Loqed Inside" + }, + "security_score_percentage": 65.79, + "coverage_percentage": 22.09, + "final_verdict": "CRITICAL - Device has significant vulnerabilities", + "test_summary": { + "total_tests": 22, + "passed": 3, + "failed": 2, + "skipped": 11, + "review": 6, + "pending": 0, + "errors": 0 + }, + "test_cases": { + "WRLS-SCAN-001": { + "name": "Advertising Data Leakage", + "description": "Parse scan responses and advertisement packets to check for leaked hardware info, serial numbers, firmware versions, or excessive manufacturer data.", + "status": "REVIEW", + "details": "Advertising carries opaque data blobs (presence alone is normal BLE behaviour): Manufacturer data present (opaque): {65535: '0000'}. Decode vendor-specific formats for a definitive judgement.", + "weight": 3 + }, + "WRLS-SCAN-002": { + "name": "Static MAC Device Tracking", + "description": "Analyze address type to determine if the device uses a static or non-resolvable public MAC address, enabling long-term user tracking.", + "status": "FAIL", + "details": "Device advertises with a fixed address type (PUBLIC) that does not rotate. Any passive observer within radio range can log this MAC and correlate the device's comings and goings over time (a physical-tracking / de-anonymization risk for the device's owner).", + "weight": 3 + }, + "WRLS-SCAN-003": { + "name": "Cleartext Passive Sniffing", + "description": "Utilize a BLE sniffer (e.g., nrfutil sniffer) during active operation to check if application-layer payload data is transmitted completely unencrypted.", + "status": "SKIPPED", + "details": "No application traffic captured during the window - cannot judge (interact with the device and re-run).", + "weight": 9 + }, + "WRLS-GATT-001": { + "name": "Unauthenticated GATT Enumeration", + "description": "Connect to the peripheral without pairing or bonding and attempt to fully map out all available services, characteristics, and descriptors.", + "status": "REVIEW", + "details": "Full GATT topology mapped without pairing: 3 services, 9 characteristics discovered unauthenticated. This is normal BLE behaviour by itself (discovery is not meant to be authenticated) - see WRLS-GATT-003/004 for whether privileged VALUES are actually accessible without authorization.", + "weight": 8 + }, + "WRLS-GATT-002": { + "name": "Exposed Debug or DFU Services", + "description": "Check the enumerated GATT database against known standard/vendor UUIDs for active Over-The-Air (OTA) updates, Device Firmware Updates (DFU), or debug interfaces.", + "status": "PASS", + "details": "No known debug/DFU/OTA services detected.", + "weight": 8 + }, + "WRLS-GATT-003": { + "name": "Missing Service-Level Authorization", + "description": "Attempt to read from characteristics requiring authentication or higher privilege levels while completely unauthenticated to identify privilege escalation paths.", + "status": "PASS", + "details": "Sensitive characteristics enforce authorization.", + "weight": 9 + }, + "WRLS-GATT-004": { + "name": "Improper Write Permissions", + "description": "Systematically issue unauthorized write requests to all accessible characteristic UUIDs (including read-only handles) to find missing backend validation.", + "status": "REVIEW", + "details": "Writes accepted unauthenticated on 2 DECLARED-writable characteristic(s): bdce0101-e90d-4685-b89d-5578cd199a9f, bdce0103-e90d-4685-b89d-5578cd199a9f. This is expected if the profile requires no authentication, but confirm manually that write content is validated (this is what makes a device actually exploitable).", + "weight": 9 + }, + "WRLS-PAIR-001": { + "name": "Pairing Procedure Downgrade", + "description": "Force a connection and check if the device accepts insecure Legacy Pairing methods or automated 'Just Works' authentication when MITM protection is requested.", + "status": "SKIPPED", + "details": "No SMP Pairing Request/Response captured - cannot judge. IMPORTANT: btmon only sees THIS machine's Bluetooth traffic; pairing the target with a phone is invisible to it. Pair the target with THIS machine (e.g. bluetoothctl remove + connect) during the capture window, and remove any existing bond first so a fresh SMP exchange occurs.", + "weight": 9 + }, + "WRLS-PAIR-002": { + "name": "Pairing Lockout & Rate Limiting", + "description": "Test whether repeated unauthenticated connection/pairing attempts are throttled or locked out (absence of a lockout enables offline passkey brute-force).", + "status": "PASS", + "details": "Device rejected all 10/10 rapid unauthenticated connection attempts (lockout or auth enforcement present).", + "weight": 8 + }, + "WRLS-PAIR-003": { + "name": "Encryption Key Size Verification", + "description": "Inspect the link layer encryption parameters to confirm the device negotiates and enforces a minimum cryptographic key size of 128 bits (16 bytes).", + "status": "SKIPPED", + "details": "No packets carrying a key-size negotiation field (no pairing observed) - trigger pairing (remove any existing bond first) and re-run.", + "weight": 8 + }, + "WRLS-PAIR-004": { + "name": "Bonding Persistence & Deletion", + "description": "Verify if Long Term Keys (LTK) are stored securely, not systematically reused across differing sessions, and can be modified or deleted without authenticating.", + "status": "SKIPPED", + "details": "No packets are Pairing Request/Response - cannot judge. Trigger pairing and re-run.", + "weight": 8 + }, + "WRLS-LGC-001": { + "name": "GATT Write & Notification Replay", + "description": "Capture a valid, signed/encrypted GATT write or notification sequence and attempt to replay it to the device later to trigger unauthorized state changes.", + "status": "SKIPPED", + "details": "GATT write/notification replay requires inject-capable hardware; set INJECT_INTERFACE to enable.", + "weight": 9 + }, + "WRLS-LGC-002": { + "name": "Race Condition & Session Hijacking", + "description": "Bombard the device with rapid disconnect/reconnect commands to attempt session hijacking, or check if active sessions can be kicked off by a third-party MAC.", + "status": "SKIPPED", + "details": "Could not establish baseline connection: device 'dev_FF_EC_EE_E7_32_E5' not found", + "weight": 8 + }, + "WRLS-FUZZ-001": { + "name": "MTU & Buffer Overflow Fuzzing", + "description": "Request maximal MTU exchanges and send oversized payloads during write transactions to check for buffer overflows, memory corruption, or soft resets.", + "status": "REVIEW", + "details": "Device dropped connection after oversized writes but reconnected.", + "weight": 10 + }, + "WRLS-FUZZ-002": { + "name": "GATT Command Injection", + "description": "Fuzz specific functional characteristics with malformed data strings, boundary parameters (0x00, 0xFF), and unexpected formatting to disrupt logic flows.", + "status": "FAIL", + "details": "Target dropped connection during fuzzing and did NOT recover.", + "weight": 10, + "legacy_mappings": [ + "WRLS-INPV-002" + ] + }, + "WRLS-FUZZ-003": { + "name": "Protocol Stack Malformed PDU (DoS)", + "description": "Inject malformed L2CAP frame headers, invalid ATT opcodes, or corrupted SMP handshake structures to force a complete hardware panic or deadlock.", + "status": "SKIPPED", + "details": "Malformed L2CAP/ATT/SMP PDU injection requires inject-capable hardware; set INJECT_INTERFACE to enable.", + "weight": 10 + }, + "WRLS-FUZZ-004": { + "name": "Connection Parameter Exhaustion", + "description": "Flood the peripheral with rapid, extreme Connection Parameter Update Requests to check if it suffers from a Denial of Service (DoS) state.", + "status": "SKIPPED", + "details": "Connection parameter update flooding requires inject-capable hardware; set INJECT_INTERFACE to enable.", + "weight": 6 + }, + "WRLS-SNIF-001": { + "name": "LL Privacy & Address Resolution Check", + "description": "Verify if the peripheral rotates its Resolvable Private Address (RPA) correctly during an active connection attempt, and check if identity resolution keys (IRK) are leaked over the air.", + "status": "REVIEW", + "details": "Only one address (FF:EC:EE:E7:32:E5) seen for 'Loqed Inside' across the 30s rescan window - rotation could not be confirmed one way or the other in this window (the window may simply be shorter than the device's rotation interval, which is commonly 15 minutes). Re-run with a longer window or verify IRK handling with a sniffer capture.", + "weight": 7 + }, + "WRLS-SNIF-002": { + "name": "Channel Map & Frequency Hopping Analysis", + "description": "Analyze if the device adheres to standard pseudo-random channel selection algorithms (CSA #2) or if its frequency hopping pattern is predictable, allowing targeted jamming.", + "status": "SKIPPED", + "details": "Requires an nRF Sniffer PCAP with an established connection captured (set NRF_SNIFFER_PCAP) - the shared capture phase found none, or only saw advertising traffic. Trigger a real connection and interact with the device during the capture window.", + "weight": 5 + }, + "WRLS-SNIF-003": { + "name": "SMP Just-Works Key Extraction", + "description": "Capture the raw Security Manager Protocol (SMP) pairing handshake. If 'Just Works' is negotiated, automatically extract the temporary/short-term key from the PCAP to decrypt the entire session.", + "status": "SKIPPED", + "details": "Captured 0 SMP packet(s) over the capture window (PCAP: gatt_outputs/toothfairy_sniff_1792738341.pcap), but no Pairing Request/Response - trigger pairing (remove any existing bond first) and re-run.", + "weight": 10 + }, + "WRLS-SNIF-004": { + "name": "Link Layer Control PDU Injection", + "description": "Inject anomalous Link Layer Control PDUs (e.g., malformed LL_LENGTH_REQ or LL_FEATURE_REQ) using the nRF hardware to bypass the OS stack and fuzz the target SoC firmware directly.", + "status": "SKIPPED", + "details": "Raw Link Layer Control PDU injection requires inject-capable hardware; set INJECT_INTERFACE to enable.", + "weight": 9 + }, + "WRLS-SNIF-005": { + "name": "Directed Advertisement Bypass", + "description": "Check if the peripheral responds to scanning requests or connection requests when it is theoretically configured to only accept directed advertising to a bonded master.", + "status": "REVIEW", + "details": "Device advertises as generally connectable; no directed/restricted advertising was observed to test a bypass against. Accepting connections is expected behaviour for an undirected-connectable device. (Note: the adv PDU type is not visible via bleak - populate target_device.directed_advertising from a sniffer capture to enable the active bypass probe.)", + "weight": 6 + } + } +} \ No newline at end of file