{"id":47696464,"url":"https://github.com/smonse/ghostble","last_synced_at":"2026-04-25T08:02:11.994Z","repository":{"id":344354773,"uuid":"973142264","full_name":"SmonSE/GhostBLE","owner":"SmonSE","description":"GhostBLE is a BLE privacy scanner for the M5Stack Cardputer. It discovers nearby devices, analyzes their privacy posture, and visualizes BLE activity with the interactive mascot Nibbles.","archived":false,"fork":false,"pushed_at":"2026-04-17T13:28:01.000Z","size":66526,"stargazers_count":11,"open_issues_count":3,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-04-17T14:34:23.152Z","etag":null,"topics":["ble","ble-scanner","bluetooth","bluetooth-arduino","bluetooth-low-energy","cardputer","cardputer-adv","esp32","esp32-arduino","iot-security","iot-security-testing","iot-security-tools","m5stack","m5stack-cardputer","privacy","privacy-protection","privacy-tools","security-research","wardriving"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SmonSE.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-04-26T10:56:46.000Z","updated_at":"2026-04-17T13:28:15.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/SmonSE/GhostBLE","commit_stats":null,"previous_names":["smonse/ghostble"],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/SmonSE/GhostBLE","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SmonSE%2FGhostBLE","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SmonSE%2FGhostBLE/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SmonSE%2FGhostBLE/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SmonSE%2FGhostBLE/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SmonSE","download_url":"https://codeload.github.com/SmonSE/GhostBLE/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SmonSE%2FGhostBLE/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32000740,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T20:23:30.271Z","status":"online","status_checked_at":"2026-04-19T02:00:07.110Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ble","ble-scanner","bluetooth","bluetooth-arduino","bluetooth-low-energy","cardputer","cardputer-adv","esp32","esp32-arduino","iot-security","iot-security-testing","iot-security-tools","m5stack","m5stack-cardputer","privacy","privacy-protection","privacy-tools","security-research","wardriving"],"created_at":"2026-04-02T16:27:26.309Z","updated_at":"2026-04-19T09:02:04.155Z","avatar_url":"https://github.com/SmonSE.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# GhostBLE\n\n![](logoConverter/rawConverter/anyone_here.png)    ![](logoConverter/rawConverter/thugLife.png)    ![](logoConverter/rawConverter/jbl_headphone.png)   \n\n**A BLE privacy scanner for M5Stack devices**\n\nGhostBLE discovers nearby Bluetooth Low Energy devices, analyzes their privacy posture, and flags potential security concerns. Built for security researchers, tinkerers, and educators interested in BLE privacy, device fingerprinting, and wireless reconnaissance.\n\nA friendly mascot named **NibBLEs** guides you through the scanning process on the built-in display.\n\n\u003e [!WARNING]\n\u003e GhostBLE is intended for legal and authorized security testing, education, and privacy research only. Use of this software for any malicious or unauthorized activities is strictly prohibited. The developers assume no liability for misuse. Use at your own risk.\n\n---\n\n## Quick Start\n\n1. Flash the firmware (see [Building \u0026 Flashing](#building--flashing))\n2. Insert a **microSD card** (required on Cardputer for logging and XP)\n3. Power on — NibBLEs greets you on the display\n4. **Long press BtnA** (1 second) to start scanning\n5. Watch devices appear on the display and in the logs\n\n---\n\n## Supported Hardware\n\n| Device | Platform | Display | Keyboard | SD Card |\n|--------|----------|---------|----------|---------|\n| **M5Stack Cardputer** | ESP32-S3 | 240x135 LCD | Yes | Yes |\n| **M5StickC Plus 2** | ESP32 | 240x135 LCD | No (2 buttons) | No |\n| **M5StickS3** | ESP32-S3 | 240x135 LCD | No (2 buttons) | No |\n\nAll devices support BLE scanning, GATT connections, GPS wardriving, WiFi dashboard, and PwnBeacon. The Cardputer adds keyboard controls, SD card logging, XP persistence, and screenshot capture.\n\n---\n\n## Features\n\n### BLE Scanning \u0026 Analysis\n\n- **Passive BLE scanning** — discovers nearby devices with signal strength (RSSI) and estimated distance\n- **Device info extraction** — retrieves names, service UUIDs, and manufacturer-specific data\n- **GATT connections** — connects to devices and reads standard BLE services (Device Info, Battery, Heart Rate, Temperature, Generic Access, Current Time, TX Power, Immediate Alert, Link Loss)\n\n### Privacy Heuristics\n\n- **Rotating MAC detection** — flags devices using Resolvable Private Addresses (RPA)\n- **Cleartext detection** — flags devices leaking unencrypted identifiers\n- **Exposure classification** — rates devices into tiers (None, Passive, Active, Consent) with a privacy score\n\n### Security Analysis\n\n- Detects **writable characteristics** (potential for unauthorized writes)\n- Identifies **DFU** and **UART** services (expanded attack surface)\n- Checks for **encryption** on sensitive services\n- Builds **device fingerprints** from advertised UUIDs and GATT profiles\n\n### Known Device Detection\n\n- **Flipper Zero** — detected by known service UUIDs (black, white, transparent variants)\n- **CatHack / Apple Juice** — BLE spam tool detection\n- **Tesla** — detected via iBeacon UUID, GATT service, and name pattern matching\n- **LightBlue** — app-based BLE testing tool\n- **PwnBeacon / Pwnagotchi** — detects and reads PwnGrid beacons (identity, face, pwnd counters, messages)\n\n### PwnBeacon\n\nGhostBLE acts as both a PwnBeacon **client** (scanner) and **server** (advertiser), compatible with [PwnBook](https://github.com/pfefferle/PwnBook) and [Palnagotchi](https://github.com/pfefferle/palnagotchi):\n\n- Advertises as a PwnBeacon with SHA-256 fingerprint, identity JSON, face, and device name\n- Detects nearby PwnBeacon peers via advertisement service data\n- Reads full peer info via GATT (identity, face, name, message)\n- Signal/ping characteristic for peer interaction\n- Pwnd counters update dynamically during scanning\n\n### Manufacturer Identification\n\nDecodes manufacturer data for Apple, Google, Samsung, Epson, and more. Also parses **iBeacon** advertisements (UUID, major, minor, TX power, distance).\n\n### GPS \u0026 Wardriving\n\n- **Dual GPS support** — Grove UART and LoRa cap GPS (Cardputer only for LoRa)\n- **WiGLE CSV export** — log devices with location for mapping and analysis\n\n### Logging\n\nAll findings are logged to multiple channels simultaneously:\n\n| Channel | Details |\n|---------|---------|\n| **Serial** | 115200 baud, structured output |\n| **SD card** | Per-category log files (Cardputer only) |\n| **Web dashboard** | Real-time via WiFi AP and WebSocket |\n\nLogs are organized into categories: Scan, GATT, Privacy, Security, Beacon, Control, GPS, System, Target, and Notify. Each device gets a **session ID** for cross-log correlation.\n\n### XP System\n\nGhostBLE gamifies the scanning process with experience points:\n\n| Event | XP |\n|-------|-----|\n| Device discovered | +0.1 |\n| GATT connection success | +0.5 |\n| Characteristic subscription | +1.0 |\n| PwnBeacon detected | +1.0 |\n| UINT/FLOAT payload decoded | +1.0 |\n| Notify data received | +1.5 |\n| Manufacturer data decoded | +2.0 |\n| Suspicious device found | +2.0 |\n| Known characteristic decoded | +2.5 |\n| iBeacon parsed | +3.0 |\n\nXP is persisted to the SD card (Cardputer) and shown on the display with level progression.\n\n### NibBLEs\n\nNibBLEs is the on-screen mascot with context-sensitive expressions and speech bubbles:\n\n- **Expressions** — happy, sad, angry, glasses (detective), thug life, sleeping, hearts, and more\n- **Speech bubbles** — context-aware messages for idle, scan start, wardriving, suspicious finds, and level-ups\n- **Screenshot capture** — press ENTER on Cardputer to save the current display to SD\n\n---\n\n## Controls\n\n### Cardputer (Keyboard)\n\n| Key | Action |\n|-----|--------|\n| **Long press BtnA** (1s) | Toggle BLE scanning on/off |\n| **ENTER** | Capture screenshot to SD card |\n| **FN** | Toggle WiFi AP and web server |\n| **TAB** | Toggle wardriving mode |\n| **DEL** | Switch GPS source (Grove / LoRa) |\n| **H** | Help Control |\n| **S** | SCAN Mode |\n| **M** | Marker in logfile |\n\n### M5StickC Plus 2 / M5StickS3 (Buttons)\n\n| Button | Action |\n|--------|--------|\n| **BtnA short press** | Toggle WiFi AP and web server |\n| **BtnA long press** (1s) | Toggle BLE scanning on/off |\n| **BtnB short press** | Toggle wardriving mode |\n| **BtnB long press** (1s) | Switch GPS source |\n\n### Web Interface\n\n1. Enable WiFi (press **FN** on Cardputer or **BtnA** on StickC/StickS3)\n2. Connect to WiFi AP **`GhostBLE`** (password: **`ghostble123!`**)\n3. Open **`192.168.4.1`** in a browser\n4. View real-time device discovery logs via WebSocket\n\n---\n\n## Building \u0026 Flashing\n\n### PlatformIO (Recommended)\n\n```bash\n# Cardputer\npio run -e ghostble -t upload\n\n# M5StickC Plus 2\npio run -e ghostble-stickcplus2 -t upload\n\n# M5StickS3\npio run -e ghostble-sticks3 -t upload\n\n# Google Test\npio test -e native -v\n```\n\n### Arduino IDE\n\n1. Install the **M5Stack board package** via Board Manager\n2. Select the appropriate board for your device\n3. Install the required libraries via Library Manager:\n   - `M5Cardputer` / `M5StickCPlus2` / `M5Unified` — hardware abstraction (depends on device)\n   - `NimBLE-Arduino` — BLE stack\n   - `ESPAsyncWebServer`, `AsyncTCP` — web dashboard\n   - `TinyGPSPlus` — GPS parsing\n4. Open `GhostBLE.ino`, compile, and upload\n\n---\n\n## Sample Output\n\n```\n[#17] Advertised Services (1):\n     - fe78 (Unknown Service)\n[#17] 🔓 Connected and discovered attributes: be:e9:2f:33:47:f1\n[#17] Reading Generic Access Service (0x1800)\n   Device found: ENVY Photo 6200 series [be:e9:2f:33:47:f1]\n   Generic Access Service found (0x1800)\n     Read value of generic access info\n     Device Name: ENVY Photo 6200 series\n     Appearance: Unknown (0x0)\n     PPCP - Min: 6, Max: 6, Latency: 0, Timeout: 2000\n     Central Address Resolution: Not Supported\n     Generic Attribute Service detected (0x1801)\n     Service Changed: Supported (indicate)\n     Unknown Service (0xfe78)\n       Char 73fd8f50-626c-4f9b-a52e-b1d226efcf8d [RN] (len=4) = C0 A8 B2 35 (192.168.178.53)\n       Char 262040ed-6f79-41bb-b657-bff4cb49195a [RN] (len=16) = 2A 02  ... (2A02:8071:2287:5B20:BEE9:2FFF:FE33:C7F1)\n       Char 58633f16-5cad-46bd-978d-fa0ad01a45ea [R] (len=16) = 0C 76 32 66 4E A8 51 21 6D CA D9 B8 50 B3 E9 3D \n       Char 380c09f8-9665-417a-bb2b-06cb6a76e784 [R] (len=6) = 00 00 00 00 00 00 \n       Char 8fe0b1c0-ea32-11e5-a4fc-0002a5d5c51b [RN] (len=58) = 01 20 E2 F8 8D C4 24 90 AE 79 A8 DF 86 8E 47 ...\n       Char 17d096e0-ea1f-11e5-9dbc-0002a5d5c51b [RN] (len=51) = 00 00 ...\n     Unknown Service (0xfe77)\n       Char aec832f7-7dff-4d6e-9b65-5b5bcf753941 [R] (len=1) = 00 \n       Char 8cec8341-c2b8-4744-b491-6826c665f187 [W]\n       Char d87a143d-16f7-4c20-9b73-2e24a8dfbcac [R] (len=1) = 00 \n       Char c4be737a-c1ed-44a4-b115-b28bddba8f45 [RNI] (len=1) = 00 \n     Unknown Service (0x7365a0ae-e596-129d-d84a-88db1ffbcc04)\n       Char 1c7cfacb-7818-c09c-9345-04602070e0cc [RW] (len=1) = 00 \n       Char ddbb8ffd-d1b6-bbb5-0f47-87a23630038b [RNI] (len=1) = 00 \n[#17] Descriptor [73fd8f50-626c-4f9b-a52e-b1d226efcf8d]: IPv4 Address\n[#17] Descriptor [262040ed-6f79-41bb-b657-bff4cb49195a]: IPv6 Address\n[#17] Descriptor [58633f16-5cad-46bd-978d-fa0ad01a45ea]: Device UUID\n[#17] Descriptor [380c09f8-9665-417a-bb2b-06cb6a76e784]: P2P Device ID\n[#17] Descriptor [8fe0b1c0-ea32-11e5-a4fc-0002a5d5c51b]: Wi-Fi Infrastructure\n[#17] Descriptor [17d096e0-ea1f-11e5-9dbc-0002a5d5c51b]: Micro Ap Configuration\n[#17] No Target detected in gatt with address: be:e9:2f:33:47:f1\n[#17] Device Infos\n   Adress:  be:e9:2f:33:47:f1\n   Name:    ENVY Photo 6200 series\n   Manuf.:  Sony Ericsson Mobile Communications\n   Raw GATT:\n     - ENVY Photo 6200 series\n     - IPv4 Address = (192.168.178.53)\n     - IPv6 Address = (2A02:8071:2287:5B20:BEE9:2FFF:FE33:C7F1)\n     - Device UUID\n     - P2P Device ID\n     - Wi-Fi Infrastructure\n     - Micro Ap Configuration\n   Distance: 19.95 m\n   RSSI: -95\n```\n\n---\n\n## Project Structure\n\n```\nGhostBLE/\n├── src/\n│\n│   ├── app/                 # Application Layer (Use Cases)\n│   │   ├── context/\n│   │   ├── controller/\n│   │   ├── device/\n│   │   └── gamification/\n│   │\n│   ├── core/                # Domain Layer (Core Logic)\n│   │   ├── models/\n│   │   ├── parsing/\n│   │   ├── detection/\n│   │   ├── fingerprint/\n│   │   ├── filtering/\n│   │   ├── analysis/\n│   │   ├── privacy/\n│   │   └── gatt/\n│   │\n│   ├── infrastructure/      # Infrastructure Layer\n│   │   ├── ble/\n│   │   ├── logging/\n│   │   ├── gps/\n│   │   ├── storage/\n│   │   └── platform/        # Hardware (M5, ESP32 etc.)\n│   │\n│   ├── ui/                  # Presentation Layer\n│   │   ├── display/\n│   │   ├── overlay/\n│   │   ├── icons/\n│   │   └── screens/\n│   │\n│   ├── config/              # Configuration\n│   │   ├── app_config\n│   │   ├── detection_config\n│   │   ├── signal_config\n│   │   └── ...\n│   │\n│   ├── assets/              # Assets / Resources\n│   │   ├── images/\n│   │   └── gatt/ (optional)\n│   │\n│   └── main.cpp             # Entry Point\n│\n├── tests/                   # Tests / Unit Tests\n```\n\n---\n\n## Contributing\n\nPRs and suggestions welcome! This is a learning-focused BLE project, and your ideas are appreciated.\n\n## License\n\nMIT License\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmonse%2Fghostble","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsmonse%2Fghostble","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmonse%2Fghostble/lists"}