Ble ctf
Bluetooth CTF¶
Scripts¶
detection_callback.py:
import argparse
import asyncio
import logging
from bleak import BleakScanner
from bleak.backends.device import BLEDevice
from bleak.backends.scanner import AdvertisementData
logger = logging.getLogger(__name__)
printed_devices = {}
def simple_callback(device: BLEDevice, advertisement_data: AdvertisementData):
if device.address not in printed_devices:
printed_devices[device.address] = advertisement_data
logger.info("{}: {}".format(device.address, advertisement_data))
async def main(args: argparse.Namespace):
scanner = BleakScanner(
simple_callback, args.services, cb=dict(use_bdaddr=args.macos_use_bdaddr)
)
while True:
#logger.info("(re)starting scanner")
await scanner.start()
await asyncio.sleep(5.0)
await scanner.stop()
#Print New BLE Devices
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument(
"--macos-use-bdaddr",
action="store_true",
help="when true use Bluetooth address instead of UUID on macOS",
)
parser.add_argument(
"--services",
metavar="<uuid>",
nargs="*",
help="UUIDs of one or more services to filter for",
)
parser.add_argument(
"-d",
"--debug",
action="store_true",
help="sets the logging level to debug",
)
args = parser.parse_args()
log_level = logging.DEBUG if args.debug else logging.INFO
logging.basicConfig(
level=log_level,
format="%(asctime)-15s %(name)-8s %(levelname)s: %(message)s",
)
asyncio.run(main(args))
service_explorer.py
import argparse
import asyncio
import logging
import collections
from bleak import BleakClient, BleakScanner
logger = logging.getLogger(__name__)
async def main(args: argparse.Namespace):
output = {}
logger.info("starting scan...")
if args.address:
device = await BleakScanner.find_device_by_address(
args.address, cb=dict(use_bdaddr=args.macos_use_bdaddr)
)
if device is None:
logger.error("could not find device with address '%s'", args.address)
return
else:
device = await BleakScanner.find_device_by_name(
args.name, cb=dict(use_bdaddr=args.macos_use_bdaddr)
)
if device is None:
logger.error("could not find device with name '%s'", args.name)
return
logger.info("connecting to device...")
async with BleakClient(device, services=args.services) as client:
logger.info("connected")
for service in client.services:
#logger.info("[Service] %s", service)
output[service.handle] = {"info": "[Service] {}".format(service)}
output[service.handle]["characteristics"] = {}
for char in service.characteristics:
if "read" in char.properties:
try:
value = await client.read_gatt_char(char.uuid)
output[service.handle]["characteristics"][char.handle] = {"info": " [Characteristic] {} ({}), Value: {}".format(char, ",".join(char.properties), value)}
except Exception as e:
output[service.handle]["characteristics"][char.handle] = {"info": " [Characteristic] {} ({}), Error: {}".format(char, ",".join(char.properties), e)}
else:
output[service.handle]["characteristics"][char.handle] = {"info": " [Characteristic] {} ({})".format(char, ",".join(char.properties))}
#init descriptors
output[service.handle]["characteristics"][char.handle]["descriptors"] = {}
for descriptor in char.descriptors:
try:
value = await client.read_gatt_descriptor(descriptor.handle)
output[service.handle]["characteristics"][char.handle]["descriptors"][descriptor.handle] = {"info": " [Descriptor] {}, Value: {}".format(descriptor, value)}
except Exception as e:
output[service.handle]["characteristics"][char.handle]["descriptors"][descriptor.handle] = {"info": " [Descriptor] {}, Error: {}".format(descriptor, e)}
#Sort Descriptors
output[service.handle]["characteristics"][char.handle]["descriptors"] = dict(sorted(output[service.handle]["characteristics"][char.handle]["descriptors"].items()))
#Sort Characteristics
output[service.handle]["characteristics"] = dict(sorted(output[service.handle]["characteristics"].items()))
#Sort Services
output = dict(sorted(output.items()))
#Print Services
for service_handle in output:
logger.info(output[service_handle]["info"])
#Print Characteristics
for characteristic in output[service_handle]["characteristics"]:
logger.info(output[service_handle]["characteristics"][characteristic]["info"])
#Print Descriptors
for descriptor in output[service_handle]["characteristics"][characteristic]["descriptors"]:
logger.info(output[service_handle]["characteristics"][characteristic]["descriptors"][descriptor]["info"])
logger.info("disconnecting...")
logger.info("disconnected")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
device_group = parser.add_mutually_exclusive_group(required=True)
device_group.add_argument(
"--name",
metavar="<name>",
help="the name of the bluetooth device to connect to",
)
device_group.add_argument(
"--address",
metavar="<address>",
help="the address of the bluetooth device to connect to",
)
parser.add_argument(
"--macos-use-bdaddr",
action="store_true",
help="when true use Bluetooth address instead of UUID on macOS",
)
parser.add_argument(
"--services",
nargs="+",
metavar="<uuid>",
help="if provided, only enumerate matching service(s)",
)
parser.add_argument(
"-d",
"--debug",
action="store_true",
help="sets the log level to debug",
)
args = parser.parse_args()
log_level = logging.DEBUG if args.debug else logging.INFO
logging.basicConfig(
level=log_level,
format="%(asctime)-15s %(name)-8s %(levelname)s: %(message)s",
)
asyncio.run(main(args))
service_writer.py:
import asyncio, string, platform, sys, argparse
from bleak import BleakClient
from bleak.uuids import normalize_uuid_16, uuid16_dict
async def main(args: argparse.Namespace):
async with BleakClient(args.device, winrt=dict(use_cached_services=True)) as client:
print(f"Connected: {client.is_connected}")
#Read UUID or handle
if args.debug:
read_data = await client.read_gatt_char(args.service)
print(f"Read[{args.service}]: {read_data}")
#Write data to UUID or handle
print(f"Write[{args.service}]: {args.data}")
value = await client.read_gatt_char(args.service)
print(f"Returned Data: {value}")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument(
"--macos-use-bdaddr",
action="store_true",
help="when true use Bluetooth address instead of UUID on macOS",
)
parser.add_argument(
"--device",
required=True,
help="Which Device MAC to connect to",
)
parser.add_argument(
"--service",
required=True,
help="UUID or Handle to write to",
)
parser.add_argument(
"--data",
required=True,
help="the Data to write. Can be 0x02, or \"test\"",
)
parser.add_argument(
"-v",
dest="debug",
action="store_true",
help="sets the logging level to debug",
)
args = parser.parse_args()
print(args)
#Convert to bytes
if args.data.starts_with("0x") and all(c in string.hexdigits for c in args.data):
args.data = int(args.data, 16)
else:
args.data = args.data.encode()
log_level = logging.DEBUG if args.debug else logging.INFO
logging.basicConfig(
level=log_level,
format="%(asctime)-15s %(name)-8s %(levelname)s: %(message)s",
)
asyncio.run(main(args))
Setup¶
Setup Bluetooth:
yay -S bleah bleak
sudo systemctl start bluetooth.service
# You might need to edit the service file and add a -E to the end of the ExecStart
#ExecStart=/usr/lib/bluetooth/bluetoothd -E
Scanning for Devices:
>>> python detection_callback.py
2023-11-13 22:21:01,667 __main__ INFO: E1:A1:E5:38:52:DD: AdvertisementData(local_name='F48F92878BF433A8EA', manufacturer_data={1447: b'\x05\x10\x01\x00\x00\x00\x00\x00\x00\x04#\x00\xca'}, service_uuids=['0000fe07-0000-1000-8000-00805f9b34fb'], tx_power=0, rssi=-77)
2023-11-13 22:21:01,671 __main__ INFO: 64:E8:33:82:AF:6A: AdvertisementData(local_name='BLECTF', service_uuids=['000000ff-0000-1000-8000-00805f9b34fb'], tx_power=-21, rssi=-33)
2023-11-13 22:21:01,731 __main__ INFO: 5B:40:40:4E:17:66: AdvertisementData(manufacturer_data={76: b'\x07\x19\x01\x14 !2\x8f\x11\x00\x043C\xe1\xee84$#\xa1(\xcb\x94\x81\x8a\x83\x85'}, rssi=-63)
2023-11-13 22:21:01,731 __main__ INFO: D8:EB:80:A5:37:B0: AdvertisementData(manufacturer_data={76: b'\x12\x02\x00\x00'}, rssi=-83)
2023-11-13 22:21:01,742 __main__ INFO: 08:2A:49:00:56:1E: AdvertisementData(manufacturer_data={6: b'\x01\t "\xf5\xb4\x10\xec\xe8\xbc\xeaS7\xe6%\x00,\xe1\x9a\x11E\xa0\xf4\x90#\x07\x1e'}, rssi=-72)
2023-11-13 22:21:01,745 __main__ INFO: 49:03:08:8E:A1:91: AdvertisementData(manufacturer_data={76: b'\x10\x06s\x1de\xccHx'}, tx_power=7, rssi=-78)
2023-11-13 22:21:01,772 __main__ INFO: 64:13:D4:80:A3:4C: AdvertisementData(manufacturer_data={76: b'\x10\x07x\x1fe>G\x16\x80'}, tx_power=7, rssi=-84)
2023-11-13 22:21:01,773 __main__ INFO: 00:4D:32:11:6F:C1: AdvertisementData(local_name='HS2S 11070', manufacturer_data={71: b'\x00\x00\x00\x00\x00M2\x11o\xc1'}, service_uuids=['636f6d2e-6a69-7561-6e2e-424653563232'], tx_power=0, rssi=-80)
2023-11-13 22:21:01,783 __main__ INFO: 71:A5:1D:B5:32:01: AdvertisementData(manufacturer_data={76: b'\x10\x07\x1d\x1b\xb6\xf3\xb0\xc8('}, tx_power=11, rssi=-81)
2023-11-13 22:21:01,815 __main__ INFO: 0A:4A:29:47:E9:FF: AdvertisementData(manufacturer_data={76: b'\t\x06\x03\xb8\xc0\xa8\x01F'}, rssi=-78)
2023-11-13 22:21:01,863 __main__ INFO: 2C:4C:C6:0E:C4:81: AdvertisementData(local_name='Venus_2C4CC60EC481', manufacturer_data={9474: b'\x00\x8c\x00\x00\xc16'}, service_uuids=['06aa1910-f22a-11e3-9daa-0002a5d5c51b'], rssi=-83)
2023-11-13 22:21:01,864 __main__ INFO: C9:01:59:A3:44:2B: AdvertisementData(manufacturer_data={76: b'\x12\x02d\x02\x07\x11\x06\x91\xdb\xb3h\x8eS\xd0.\xbdSU\xba\xa69\x8aG'}, rssi=-75)
2023-11-13 22:21:01,895 __main__ INFO: 57:97:97:9E:7F:9C: AdvertisementData(manufacturer_data={224: b'X\x07\xcas`\x10'}, service_data={'0000fe9f-0000-1000-8000-00805f9b34fb': b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'}, service_uuids=['0000fe9f-0000-1000-8000-00805f9b34fb'], rssi=-52)
2023-11-13 22:21:01,936 __main__ INFO: 7E:48:71:E2:7D:73: AdvertisementData(manufacturer_data={76: b'\x10\x06O\x1dFbo\x18'}, tx_power=5, rssi=-82)
2023-11-13 22:21:01,936 __main__ INFO: 5C:C1:D7:72:87:97: AdvertisementData(local_name='[TV] Samsung 7 Series (50)', manufacturer_data={117: b'B\x04\x01\x80f\\\xc1\xd7r\x87\x97^\xc1\xd7r\x87\x96\x01\x00\x00\x00\x00\x00\x00'}, rssi=-78)
2023-11-13 22:21:01,966 __main__ INFO: 7D:09:8F:04:AB:40: AdvertisementData(manufacturer_data={76: b'\x0c\x0e\x00!IU\xfb\x17\xa0\xe4\xd0\x0e\xc7@\t\x19\x10\x06s\x1d\xd0\x9bI('}, rssi=-86)
2023-11-13 22:21:01,966 __main__ INFO: 1C:B3:C9:31:23:8F: AdvertisementData(manufacturer_data={76: b'\x10\x05\x01\x10+\xf0<'}, tx_power=4, rssi=-71)
2023-11-13 22:21:02,271 __main__ INFO: E4:FC:95:73:04:94: AdvertisementData(local_name='Hatch Rest', service_data={'0000180f-0000-1000-8000-00805f9b34fb': b'd'}, service_uuids=['0000180a-0000-1000-8000-00805f9b34fb', '0000180f-0000-1000-8000-00805f9b34fb'], rssi=-83)
2023-11-13 22:21:02,340 __main__ INFO: 0E:8F:3C:F4:EE:31: AdvertisementData(manufacturer_data={76: b'\t\x08\x13\xa0\xc0\xa827\x1bX'}, rssi=-85)
2023-11-13 22:21:02,527 __main__ INFO: 7E:39:F0:B7:2B:4D: AdvertisementData(manufacturer_data={76: b'\x10\x05<\x1c\x80\x15\x0c'}, tx_power=12, rssi=-85)
2023-11-13 22:21:02,946 __main__ INFO: 75:4E:57:6B:5A:DA: AdvertisementData(manufacturer_data={76: b'\x10\x05&\x18\x91\t\x8c'}, tx_power=8, rssi=-80)
2023-11-13 22:21:03,337 __main__ INFO: CB:0B:A7:63:74:BF: AdvertisementData(manufacturer_data={76: b'\x12\x02\x00\x01'}, rssi=-83)
2023-11-13 22:21:03,410 __main__ INFO: 7B:75:51:E5:65:CE: AdvertisementData(manufacturer_data={76: b'\t\x08\x13\x84\xc0\xa8\x00y\x1bX\x13\x07\x02\xf1:\xe6h\xd5\xa7'}, rssi=-88)
2023-11-13 22:21:03,425 __main__ INFO: FA:BA:C9:96:86:5F: AdvertisementData(local_name='98E78202A2C83397E9', manufacturer_data={1447: b'\x05\x10\x01\x00\x00\x00\x00\x00\x00\x02#\x00\xca'}, service_uuids=['0000fe07-0000-1000-8000-00805f9b34fb'], rssi=-84)
2023-11-13 22:21:03,778 __main__ INFO: 72:0D:34:BE:A0:C4: AdvertisementData(manufacturer_data={76: b'\x10\x07z\x1f\xb8\xccG\xfa\x80'}, tx_power=7, rssi=-80)
2023-11-13 22:21:03,778 __main__ INFO: C5:06:F6:45:C4:8B: AdvertisementData(manufacturer_data={76: b'\x12\x02\x00\x00'}, rssi=-82)
2023-11-13 22:21:04,399 __main__ INFO: 7D:38:31:ED:39:43: AdvertisementData(manufacturer_data={76: b'\x10\x06O\x1dFbo\x18'}, tx_power=5, rssi=-82)
2023-11-13 22:21:04,885 __main__ INFO: DE:07:E3:73:56:E2: AdvertisementData(manufacturer_data={76: b'\x12\x02n\x03\x07\x11\x06I\x15\xb67\xd3J^\x99t\xa4\tVyu\xdeV'}, rssi=-78)
2023-11-13 22:21:05,028 __main__ INFO: 57:3F:49:79:A1:CF: AdvertisementData(manufacturer_data={76: b'\t\x08\x13\xa7\xc0\xa8\x01\x0c\x1bX'}, rssi=-83)
2023-11-13 22:21:05,043 __main__ INFO: E7:38:83:A1:46:9D: AdvertisementData(manufacturer_data={76: b'\x12\x02\x00\x03'}, rssi=-79)
2023-11-13 22:21:05,319 __main__ INFO: E3:36:5D:AE:20:D4: AdvertisementData(manufacturer_data={76: b'\x12\x19\x102\x8dM\xdb#d\x0f\xccN\x1d\xb2\xce\x17!l\xdb\xef\xacn\xf6F\xcc\x03\xd4'}, rssi=-76)
2023-11-13 22:21:05,415 __main__ INFO: C7:2D:EA:36:45:B2: AdvertisementData(manufacturer_data={76: b'\x12\x02\xac\x02'}, rssi=-71)
2023-11-13 22:21:05,601 __main__ INFO: C4:57:DC:51:D9:E4: AdvertisementData(manufacturer_data={76: b'\x12\x02\xa5\x03'}, rssi=-63)
2023-11-13 22:21:05,870 __main__ INFO: 52:03:53:87:0B:A2: AdvertisementData(manufacturer_data={76: b'\x10\x05{\x1c\x88\xb8\r'}, tx_power=8, rssi=-85)
2023-11-13 22:21:06,404 __main__ INFO: 44:F2:D3:91:C7:1A: AdvertisementData(service_uuids=['0000180f-0000-1000-8000-00805f9b34fb'], rssi=-83)
2023-11-13 22:21:06,479 __main__ INFO: 4B:BA:AF:E7:1E:21: AdvertisementData(manufacturer_data={76: b'\x10\x06\r\x1d\x8a\xa6\x80\x08'}, tx_power=4, rssi=-88)
List Capabilities (bleah):
>>> sudo bleah -b "64:E8:33:82:AF:6A" -e
@ Scanning for 5s [-128 dBm of sensitivity] ...
┌ 64:e8:33:82:af:6a (-34 dBm) ──────────────────────────────────────────┐
│ Vendor │ ? │
│ Allows Connections │ ✓ │
│ Address Type │ public │
│ Tx Power │ u'eb' │
│ Complete 16b Services │ '000000ff-0000-1000-8000-00805f9b34fb' │
│ Complete Local Name │ BLECTF │
│ Flags │ LE General Discoverable, BR/EDR Not Supported │
└───────────────────────┴───────────────────────────────────────────────┘
@ Connecting to 64:e8:33:82:af:6a ... connected.
@ Enumerating all the things ...
┌──────────────┬────────────────────────────────────────────────────────────────────────┬──────────────────────────────────────────────────┬──────────────────────────────────────────────────────────────┐
│ Handles │ Service > Characteristics │ Properties │ Data │
├──────────────┼────────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────┤
│ 0001 -> 000b │ Generic Attribute ( 00001801-0000-1000-8000-00805f9b34fb ) │ │ │
│ 0003 │ Service Changed ( 00002a05-0000-1000-8000-00805f9b34fb ) │ INDICATE │ │
│ 0006 │ 2b29 ( 00002b29-0000-1000-8000-00805f9b34fb ) │ READ WRITE │ '\x04' │
│ 0008 │ 2b2a ( 00002b2a-0000-1000-8000-00805f9b34fb ) │ READ │ '\xe5\xc2\xaa\x8b\xb1!\xce\xaf\xef\xe3\xb9\xf3\xd5\xa3\xc21' │
│ 000a │ 2b3a ( 00002b3a-0000-1000-8000-00805f9b34fb ) │ READ │ '\x00' │
│ │ │ │ │
│ 0014 -> 001c │ Generic Access ( 00001800-0000-1000-8000-00805f9b34fb ) │ │ │
│ 0016 │ Device Name ( 00002a00-0000-1000-8000-00805f9b34fb ) │ READ │ u'2b00042f7481c7b056c4b410d28f33cf' │
│ 0018 │ Appearance ( 00002a01-0000-1000-8000-00805f9b34fb ) │ READ │ Unknown │
│ 001a │ Central Address Resolution ( 00002aa6-0000-1000-8000-00805f9b34fb ) │ READ │ '\x00' │
│ │ │ │ │
│ 0028 -> ffff │ 00ff ( 000000ff-0000-1000-8000-00805f9b34fb ) │ │ │
│ 002a │ ff01 ( 0000ff01-0000-1000-8000-00805f9b34fb ) │ READ │ u'Score: 0/20' │
│ 002c │ ff02 ( 0000ff02-0000-1000-8000-00805f9b34fb ) │ READ WRITE │ u'Write Flags Here' │
│ 002e │ ff03 ( 0000ff03-0000-1000-8000-00805f9b34fb ) │ READ │ u'd205303e099ceff44835' │
│ 0030 │ ff04 ( 0000ff04-0000-1000-8000-00805f9b34fb ) │ READ │ u'MD5 of Device Name' │
│ 0032 │ ff05 ( 0000ff05-0000-1000-8000-00805f9b34fb ) │ READ WRITE │ u'Write anything here' │
│ 0034 │ ff06 ( 0000ff06-0000-1000-8000-00805f9b34fb ) │ READ WRITE │ u'Write the ascii value "yo" here' │
│ 0036 │ ff07 ( 0000ff07-0000-1000-8000-00805f9b34fb ) │ READ WRITE │ u'Write the hex value 0x07 here' │
│ 0038 │ ff08 ( 0000ff08-0000-1000-8000-00805f9b34fb ) │ READ │ u'Write 0xC9 to handle 58' │
│ 003a │ ff09 ( 0000ff09-0000-1000-8000-00805f9b34fb ) │ WRITE │ │
│ 003c │ ff0a ( 0000ff0a-0000-1000-8000-00805f9b34fb ) │ READ WRITE │ u'Brute force my value 00 to ff' │
│ 003e │ ff0b ( 0000ff0b-0000-1000-8000-00805f9b34fb ) │ READ │ u'Read me 1000 times' │
│ 0040 │ ff0c ( 0000ff0c-0000-1000-8000-00805f9b34fb ) │ NOTIFY READ WRITE │ u'Listen to me for a single notification' │
│ 0042 │ ff0d ( 0000ff0d-0000-1000-8000-00805f9b34fb ) │ READ │ u'Listen to handle 0x0044 for a single indication' │
│ 0044 │ ff0e ( 0000ff0e-0000-1000-8000-00805f9b34fb ) │ READ INDICATE WRITE │ │
│ 0046 │ ff0f ( 0000ff0f-0000-1000-8000-00805f9b34fb ) │ NOTIFY READ WRITE │ u'Listen to me for multi notifications' │
│ 0048 │ ff10 ( 0000ff10-0000-1000-8000-00805f9b34fb ) │ READ │ u'Listen to handle 0x004a for multi indications' │
│ 004a │ ff11 ( 0000ff11-0000-1000-8000-00805f9b34fb ) │ READ INDICATE WRITE │ │
│ 004c │ ff12 ( 0000ff12-0000-1000-8000-00805f9b34fb ) │ READ │ u'Connect with BT MAC address 11:22:33:44:55:66' │
│ 004e │ ff13 ( 0000ff13-0000-1000-8000-00805f9b34fb ) │ READ │ u'Set your connection MTU to 444' │
│ 0050 │ ff14 ( 0000ff14-0000-1000-8000-00805f9b34fb ) │ READ WRITE │ u"Write+resp 'hello' " │
│ 0052 │ ff15 ( 0000ff15-0000-1000-8000-00805f9b34fb ) │ READ WRITE │ u'No notifications here! really?' │
│ 0054 │ ff16 ( 0000ff16-0000-1000-8000-00805f9b34fb ) │ NOTIFY BROADCAST READ WRITE EXTENDED PROPERTIES │ u'So many properties!' │
│ 0056 │ ff17 ( 0000ff17-0000-1000-8000-00805f9b34fb ) │ READ │ u"md5 of author's twitter handle" │
│ │ │ │ │
└──────────────┴────────────────────────────────────────────────────────────────────────┴──────────────────────────────────────────────────┴──────────────────────────────────────────────────────────────┘
()
List Capabilities Python:
>>> python service_explorer.py --name BLECTF
2023-11-13 22:55:50,730 __main__ INFO: starting scan...
2023-11-13 22:55:50,861 __main__ INFO: connecting to device...
2023-11-13 22:55:52,262 __main__ INFO: connected
2023-11-13 22:55:54,629 __main__ INFO: [Service] 00001801-0000-1000-8000-00805f9b34fb (Handle: 1): Generic Attribute Profile
2023-11-13 22:55:54,629 __main__ INFO: [Characteristic] 00002a05-0000-1000-8000-00805f9b34fb (Handle: 2): Service Changed (indicate)
2023-11-13 22:55:54,629 __main__ INFO: [Descriptor] 00002902-0000-1000-8000-00805f9b34fb (Handle: 4): Client Characteristic Configuration, Value: bytearray(b'\x02\x00')
2023-11-13 22:55:54,629 __main__ INFO: [Characteristic] 00002b29-0000-1000-8000-00805f9b34fb (Handle: 5): Client Supported Features (read,write), Value: bytearray(b'\x05')
2023-11-13 22:55:54,629 __main__ INFO: [Characteristic] 00002b2a-0000-1000-8000-00805f9b34fb (Handle: 7): Database Hash (read), Value: bytearray(b'\xe5\xc2\xaa\x8b\xb1!\xce\xaf\xef\xe3\xb9\xf3\xd5\xa3\xc21')
2023-11-13 22:55:54,630 __main__ INFO: [Characteristic] 00002b3a-0000-1000-8000-00805f9b34fb (Handle: 9): Server Supported Features (read), Value: bytearray(b'\x00')
2023-11-13 22:55:54,630 __main__ INFO: [Service] 000000ff-0000-1000-8000-00805f9b34fb (Handle: 40): Vendor specific
2023-11-13 22:55:54,630 __main__ INFO: [Characteristic] 0000ff01-0000-1000-8000-00805f9b34fb (Handle: 41): Vendor specific (read), Value: bytearray(b'Score:8 /20')
2023-11-13 22:55:54,630 __main__ INFO: [Characteristic] 0000ff02-0000-1000-8000-00805f9b34fb (Handle: 43): Vendor specific (read,write), Value: bytearray(b'Write Flags Here')
2023-11-13 22:55:54,630 __main__ INFO: [Characteristic] 0000ff03-0000-1000-8000-00805f9b34fb (Handle: 45): Vendor specific (read), Value: bytearray(b'd205303e099ceff44835')
2023-11-13 22:55:54,630 __main__ INFO: [Characteristic] 0000ff04-0000-1000-8000-00805f9b34fb (Handle: 47): Vendor specific (read), Value: bytearray(b'MD5 of Device Name')
2023-11-13 22:55:54,630 __main__ INFO: [Characteristic] 0000ff05-0000-1000-8000-00805f9b34fb (Handle: 49): Vendor specific (read,write), Value: bytearray(b'3873c0270763568cf7aa')
2023-11-13 22:55:54,630 __main__ INFO: [Characteristic] 0000ff06-0000-1000-8000-00805f9b34fb (Handle: 51): Vendor specific (read,write), Value: bytearray(b'c55c6314b3db0a6128af')
2023-11-13 22:55:54,630 __main__ INFO: [Characteristic] 0000ff07-0000-1000-8000-00805f9b34fb (Handle: 53): Vendor specific (read,write), Value: bytearray(b'1179080b29f8da16ad66')
2023-11-13 22:55:54,630 __main__ INFO: [Characteristic] 0000ff08-0000-1000-8000-00805f9b34fb (Handle: 55): Vendor specific (read), Value: bytearray(b'f8b136d937fad6a2be9f')
2023-11-13 22:55:54,630 __main__ INFO: [Characteristic] 0000ff09-0000-1000-8000-00805f9b34fb (Handle: 57): Vendor specific (write)
2023-11-13 22:55:54,630 __main__ INFO: [Characteristic] 0000ff0a-0000-1000-8000-00805f9b34fb (Handle: 59): Vendor specific (read,write), Value: bytearray(b'Brute force my value 00 to ff')
2023-11-13 22:55:54,630 __main__ INFO: [Characteristic] 0000ff0b-0000-1000-8000-00805f9b34fb (Handle: 61): Vendor specific (read), Value: bytearray(b'Read me 1000 times')
2023-11-13 22:55:54,630 __main__ INFO: [Characteristic] 0000ff0c-0000-1000-8000-00805f9b34fb (Handle: 63): Vendor specific (read,write,notify), Value: bytearray(b'Listen to me for a single notification')
2023-11-13 22:55:54,630 __main__ INFO: [Characteristic] 0000ff0d-0000-1000-8000-00805f9b34fb (Handle: 65): Vendor specific (read), Value: bytearray(b'Listen to handle 0x0044 for a single indication')
2023-11-13 22:55:54,630 __main__ INFO: [Characteristic] 0000ff0e-0000-1000-8000-00805f9b34fb (Handle: 67): Vendor specific (read,write,indicate), Value: bytearray(b'Listen to handle 0x0044 for a single indication\x00')
2023-11-13 22:55:54,631 __main__ INFO: [Characteristic] 0000ff0f-0000-1000-8000-00805f9b34fb (Handle: 69): Vendor specific (read,write,notify), Value: bytearray(b'Listen to me for multi notifications')
2023-11-13 22:55:54,631 __main__ INFO: [Characteristic] 0000ff10-0000-1000-8000-00805f9b34fb (Handle: 71): Vendor specific (read), Value: bytearray(b'Listen to handle 0x004a for multi indications')
2023-11-13 22:55:54,631 __main__ INFO: [Characteristic] 0000ff11-0000-1000-8000-00805f9b34fb (Handle: 73): Vendor specific (read,write,indicate), Value: bytearray(b'Listen to handle 0x004a for multi indications\x00')
2023-11-13 22:55:54,631 __main__ INFO: [Characteristic] 0000ff12-0000-1000-8000-00805f9b34fb (Handle: 75): Vendor specific (read), Value: bytearray(b'Connect with BT MAC address 11:22:33:44:55:66')
2023-11-13 22:55:54,631 __main__ INFO: [Characteristic] 0000ff13-0000-1000-8000-00805f9b34fb (Handle: 77): Vendor specific (read), Value: bytearray(b'Set your connection MTU to 444')
2023-11-13 22:55:54,631 __main__ INFO: [Characteristic] 0000ff14-0000-1000-8000-00805f9b34fb (Handle: 79): Vendor specific (read,write), Value: bytearray(b"Write+resp \'hello\' ")
2023-11-13 22:55:54,631 __main__ INFO: [Characteristic] 0000ff15-0000-1000-8000-00805f9b34fb (Handle: 81): Vendor specific (read,write), Value: bytearray(b'No notifications here! really?')
2023-11-13 22:55:54,631 __main__ INFO: [Characteristic] 0000ff16-0000-1000-8000-00805f9b34fb (Handle: 83): Vendor specific (broadcast,read,write,notify,extended-properties), Value: bytearray(b'So many properties!')
2023-11-13 22:55:54,631 __main__ INFO: [Characteristic] 0000ff17-0000-1000-8000-00805f9b34fb (Handle: 85): Vendor specific (read), Value: bytearray(b"md5 of author\'s twitter handle")
2023-11-13 22:55:54,631 __main__ INFO: disconnecting...
2023-11-13 22:55:56,665 __main__ INFO: disconnected
Common Functions¶
Read Values (bluetoothctl):
>>> bluetoothctl
hci0 new_settings: powered bondable ssp br/edr le secure-conn
Agent registered
[CHG] Controller A8:7E:EA:C2:EB:46 Pairable: yes
[2b00042f7481c7b056c4b410d28f33cf]# menu gatt
[2b00042f7481c7b056c4b410d28f33cf]# select-attribute 0000ff01-0000-1000-8000-00805f9b34fb
[2b00042f7481c7b056c4b410d28f33cf:/service0028/char0029]# read
Attempting to read /org/bluez/hci0/dev_64_E8_33_82_AF_6A/service0028/char0029
[CHG] Attribute /org/bluez/hci0/dev_64_E8_33_82_AF_6A/service0028/char0029 Value:
53 63 6f 72 65 3a 20 30 2f 32 30 Score: 0/20
53 63 6f 72 65 3a 20 30 2f 32 30 Score: 0/20
Read Values (python):
>>> python service_explorer.py --address "64:E8:33:82:AF:6A" 2>&1 | grep 0000ff01-0000-1000-8000-00805f9b34fb
2023-11-13 23:00:37,073 __main__ INFO: [Characteristic] 0000ff01-0000-1000-8000-00805f9b34fb (Handle: 41): Vendor specific (read), Value: bytearray(b'Score:8 /20')
Write Values (python):
Write Values (bleah):
sudo bleah -b "64:E8:33:82:AF:6A" -u 0000ff02-0000-1000-8000-00805f9b34fb -d "5cd56d74049ae40f442ece036c6f4f06"
sudo bleah -b "64:E8:33:82:AF:6A" -n 0x002c -d "5cd56d74049ae40f442ece036c6f4f06"
sudo bleah -b "64:E8:33:82:AF:6A" -n 43 -d "5cd56d74049ae40f442ece036c6f4f06"
Write Values (bluetoothctl):
#Dosent work
Flag 1¶
Write a Flag:
>>> sudo bleah -b "64:E8:33:82:AF:6A" -u 0000ff02-0000-1000-8000-00805f9b34fb -d "12345678901234567890"
@ Scanning for 5s [-128 dBm of sensitivity] ...
┌ 64:e8:33:82:af:6a (-37 dBm) ──────────────────────────────────────────┐
│ Vendor │ ? │
│ Allows Connections │ ✓ │
│ Address Type │ public │
│ Tx Power │ u'eb' │
│ Complete 16b Services │ '000000ff-0000-1000-8000-00805f9b34fb' │
│ Complete Local Name │ BLECTF │
│ Flags │ LE General Discoverable, BR/EDR Not Supported │
└───────────────────────┴───────────────────────────────────────────────┘
@ Connecting to 64:e8:33:82:af:6a ... connected.
()
@ Searching for characteristic uuid(0000ff02-0000-1000-8000-00805f9b34fb) ... found
@ Sending 20 bytes ... done
()
()
Flag 2¶
Read the Flag with bluetoothctl:
>>> bluetoothctl
scan on
[2b00042f7481c7b056c4b410d28f33cf]# menu gatt
[2b00042f7481c7b056c4b410d28f33cf]# select-attribute 0000ff03-0000-1000-8000-00805f9b34fb
[2b00042f7481c7b056c4b410d28f33cf:/service0028/char0029]# read
Attempting to read /org/bluez/hci0/dev_64_E8_33_82_AF_6A/service0028/char0029
[CHG] Attribute /org/bluez/hci0/dev_64_E8_33_82_AF_6A/service0028/char0029 Value:
53 63 6f 72 65 3a 20 30 2f 32 30 Score: 0/20
53 63 6f 72 65 3a 20 30 2f 32 30 Score: 0/20
Note
Cant write with bluetoothctl
Write a Flag with bluetoothctl:
sudo bleah -b "64:E8:33:82:AF:6A" -u 0000ff02-0000-1000-8000-00805f9b34fb -d "d205303e099ceff44835"
Flag 3¶
#md5("BLECTF") = 5cd56d74049ae40f442ece036c6f4f06
>>> sudo bleah -b "64:E8:33:82:AF:6A" -u 0000ff02-0000-1000-8000-00805f9b34fb -d "5cd56d74049ae40f442ece036c6f4f06"
[...]
@ Connecting to 64:e8:33:82:af:6a ... connected.
()
@ Searching for characteristic uuid(0000ff02-0000-1000-8000-00805f9b34fb) ... found
@ Sending 32 bytes ... done
()
()
#Actually wants the first 20 characters
>>> sudo bleah -b "64:E8:33:82:AF:6A" -u 0000ff02-0000-1000-8000-00805f9b34fb -d "5cd56d74049ae40f442e"
Flag 4¶
Get device name and sent it to 0000ff02-0000-1000-8000-00805f9b34fb
.
[BLECTF]# info
Device 64:E8:33:82:AF:6A (public)
Name: 2b00042f7481c7b056c4b410d28f33cf
Alias: 2b00042f7481c7b056c4b410d28f33cf
Paired: no
Bonded: no
Trusted: no
Blocked: no
Connected: yes
LegacyPairing: no
UUID: Unknown (000000ff-0000-1000-8000-00805f9b34fb)
UUID: Generic Access Profile (00001800-0000-1000-8000-00805f9b34fb)
UUID: Generic Attribute Profile (00001801-0000-1000-8000-00805f9b34fb)
AdvertisingFlags:
06
>>> sudo bleah -b "64:E8:33:82:AF:6A" -u 0000ff02-0000-1000-8000-00805f9b34fb -d "2b00042f7481c7b056c4"
@ Connecting to 64:e8:33:82:af:6a ... connected.
()
@ Searching for characteristic uuid(0000ff02-0000-1000-8000-00805f9b34fb) ... found
@ Sending 20 bytes ... done
()
()
Flag 5¶
Write anything
to 0000ff05-0000-1000-8000-00805f9b34fb
>>> sudo bleah -b "64:E8:33:82:AF:6A" -u 0000ff05-0000-1000-8000-00805f9b34fb -d "anything"
@ Connecting to 64:e8:33:82:af:6a ... connected.
()
@ Searching for characteristic uuid(0000ff02-0000-1000-8000-00805f9b34fb) ... found
@ Sending 20 bytes ... done
()
()
After anything
is written the data is changed
[BLECTF]# select-attribute 0000ff05-0000-1000-8000-00805f9b34fb
[2b00042f7481c7b056c4b410d28f33cf:/service0028/char0031]# read
Attempting to read /org/bluez/hci0/dev_64_E8_33_82_AF_6A/service0028/char0031
[CHG] Attribute /org/bluez/hci0/dev_64_E8_33_82_AF_6A/service0028/char0031 Value:
33 38 37 33 63 30 32 37 30 37 36 33 35 36 38 63 3873c0270763568c
66 37 61 61 f7aa
33 38 37 33 63 30 32 37 30 37 36 33 35 36 38 63 3873c0270763568c
66 37 61 61 f7aa
[2b00042f7481c7b056c4b410d28f33cf:/service0028/char0031]#
Write the flag
>>> sudo bleah -b "64:E8:33:82:AF:6A" -u 0000ff02-0000-1000-8000-00805f9b34fb -d "3873c0270763568cf7aa"
[...]
@ Connecting to 64:e8:33:82:af:6a ... connected.
()
@ Searching for characteristic uuid(0000ff02-0000-1000-8000-00805f9b34fb) ... found
@ Sending 20 bytes ... done
()
()
Flag 6¶
Write ascii "yo"
>>> sudo bleah -b "64:E8:33:82:AF:6A" -u 0000ff06-0000-1000-8000-00805f9b34fb -d "yo"
[...]
@ Connecting to 64:e8:33:82:af:6a ... connected.
()
@ Searching for characteristic uuid(0000ff06-0000-1000-8000-00805f9b34fb) ... found
@ Sending 2 bytes ... done
()
()
Read the flag from the 0000ff06-0000-1000-8000-00805f9b34fb
handle
Write the flag
>>> sudo bleah -b "64:E8:33:82:AF:6A" -u 0000ff02-0000-1000-8000-00805f9b34fb -d "c55c6314b3db0a6128af"
[...]
@ Connecting to 64:e8:33:82:af:6a ... connected.
()
@ Searching for characteristic uuid(0000ff02-0000-1000-8000-00805f9b34fb) ... found
@ Sending 20 bytes ... done
()
()
Flag 7¶
Write binary 0x07
>>> sudo bleah -b "64:E8:33:82:AF:6A" -u 0000ff07-0000-1000-8000-00805f9b34fb -d 0x07
[...]
@ Connecting to 64:e8:33:82:af:6a ... connected.
()
@ Searching for characteristic uuid(0000ff07-0000-1000-8000-00805f9b34fb) ... found
@ Sending 1 bytes ... done
()
()
Read the flag from the 0000ff07-0000-1000-8000-00805f9b34fb
handle
Write the flag
>>> sudo bleah -b "64:E8:33:82:AF:6A" -u 0000ff02-0000-1000-8000-00805f9b34fb -d "1179080b29f8da16ad66"
[...]
@ Connecting to 64:e8:33:82:af:6a ... connected.
()
@ Searching for characteristic uuid(0000ff02-0000-1000-8000-00805f9b34fb) ... found
@ Sending 20 bytes ... done
()
()
Flag 8¶
Write 0xC9 to handle 58. 58 == 0x003a
sudo bleah -b "64:E8:33:82:AF:6A" -n 0x003a -d 0xC9
[...]
@ Connecting to 64:e8:33:82:af:6a ... connected.
()
@ Searching for characteristic handle(58) ... found
@ Sending 1 bytes ... done
()
()
Read the flag from the 0000ff08-0000-1000-8000-00805f9b34fb
handle
Write the flag
>>> sudo bleah -b "64:E8:33:82:AF:6A" -n 0x002a -d "f8b136d937fad6a2be9f"
[...]
@ Connecting to 64:e8:33:82:af:6a ... connected.
()
@ Searching for characteristic uuid(0000ff02-0000-1000-8000-00805f9b34fb) ... found
@ Sending 20 bytes ... done
()
()
Flag 9¶
Modified write Script
import asyncio, string, platform, sys, argparse, logging
from bleak import BleakClient
from bleak.uuids import normalize_uuid_16, uuid16_dict
logger = logging.getLogger(__name__)
async def flag9(args: argparse.Namespace):
async with BleakClient(args.device, winrt=dict(use_cached_services=True)) as client:
logger.info(f"Connected: {client.is_connected}")
for i in range(255):
write_data = bytearray([i])
#Read UUID or handle
read_data = await client.read_gatt_char(args.service)
logger.info(f"Read[{args.service}]: {read_data}")
#Write data to UUID or handle
logger.info(f"Write[{args.service}]: {write_data}")
value = await client.write_gatt_char(args.service, write_data, response=True)
logger.info(f"Returned Data: {value}")
async def main(args: argparse.Namespace):
async with BleakClient(args.device, winrt=dict(use_cached_services=True)) as client:
logger.info(f"Connected: {client.is_connected}")
#Read UUID or handle
read_data = await client.read_gatt_char(args.service)
logger.info(f"Read[{args.service}]: {read_data}")
#Write data to UUID or handle
logger.info(f"Write[{args.service}]: {args.data}")
value = await client.write_gatt_char(args.service, args.data, response=True)
logger.info(f"Returned Data: {value}")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument(
"--macos-use-bdaddr",
action="store_true",
help="when true use Bluetooth address instead of UUID on macOS",
)
parser.add_argument(
"--device",
required=True,
help="Which Device MAC to connect to",
)
parser.add_argument(
"--service",
required=True,
help="UUID or Handle to write to",
)
parser.add_argument(
"--data",
required=True,
help="the Data to write. Can be 0x02, or \"test\"",
)
parser.add_argument(
"-v",
dest="debug",
#default=True,
action="store_true",
help="sets the logging level to debug",
)
args = parser.parse_args()
#Convert to bytes
if args.data.startswith("0x") and all(c in string.hexdigits for c in args.data):
args.data = int(args.data, 16)
else:
args.data = args.data.encode()
log_level = logging.DEBUG if args.debug else logging.INFO
logging.basicConfig(
level=log_level,
format="%(asctime)-15s %(name)-8s %(levelname)s: %(message)s",
)
#asyncio.run(main(args))
asyncio.run(flag9(args))
Run the script:
>>> python write_data.py --device "64:E8:33:82:AF:6A" --service 0000ff0a-0000-1000-8000-00805f9b34fb --data 0x00
2023-11-13 23:14:19,135 __main__ INFO: Connected: True
2023-11-13 23:14:19,529 __main__ INFO: Read[0000ff0a-0000-1000-8000-00805f9b34fb]: bytearray(b'933c1fcfa8ed52d2ec05')
2023-11-13 23:14:19,529 __main__ INFO: Write[0000ff0a-0000-1000-8000-00805f9b34fb]: bytearray(b'\x00')
2023-11-13 23:14:19,608 __main__ INFO: Returned Data: None
2023-11-13 23:14:19,689 __main__ INFO: Read[0000ff0a-0000-1000-8000-00805f9b34fb]: bytearray(b'933c1fcfa8ed52d2ec05')
2023-11-13 23:14:19,689 __main__ INFO: Write[0000ff0a-0000-1000-8000-00805f9b34fb]: bytearray(b'\x01')
2023-11-13 23:14:19,768 __main__ INFO: Returned Data: None
2023-11-13 23:14:19,849 __main__ INFO: Read[0000ff0a-0000-1000-8000-00805f9b34fb]: bytearray(b'933c1fcfa8ed52d2ec05')
2023-11-13 23:14:19,849 __main__ INFO: Write[0000ff0a-0000-1000-8000-00805f9b34fb]: bytearray(b'\x02')
2023-11-13 23:14:19,929 __main__ INFO: Returned Data: None
2023-11-13 23:14:20,009 __main__ INFO: Read[0000ff0a-0000-1000-8000-00805f9b34fb]: bytearray(b'933c1fcfa8ed52d2ec05')
2023-11-13 23:14:20,009 __main__ INFO: Write[0000ff0a-0000-1000-8000-00805f9b34fb]: bytearray(b'\x03')
2023-11-13 23:14:20,089 __main__ INFO: Returned Data: None
2023-11-13 23:14:20,168 __main__ INFO: Read[0000ff0a-0000-1000-8000-00805f9b34fb]: bytearray(b'933c1fcfa8ed52d2ec05')
2023-11-13 23:14:20,168 __main__ INFO: Write[0000ff0a-0000-1000-8000-00805f9b34fb]: bytearray(b'\x04')
2023-11-13 23:14:20,249 __main__ INFO: Returned Data: None
Write the flag:
>>> python write_data.py --device "64:E8:33:82:AF:6A" --service 0000ff02-0000-1000-8000-00805f9b34fb --data "933c1fcfa8ed52d2ec05"
2023-11-13 23:19:52,034 __main__ INFO: Connected: True
2023-11-13 23:19:52,412 __main__ INFO: Read[0000ff02-0000-1000-8000-00805f9b34fb]: bytearray(b'Write Flags Here')
2023-11-13 23:19:52,412 __main__ INFO: Write[0000ff02-0000-1000-8000-00805f9b34fb]: b'933c1fcfa8ed52d2ec05'
2023-11-13 23:19:52,492 __main__ INFO: Returned Data: None
Flag 10¶
Modified read Script
import asyncio, string, platform, sys, argparse, logging
from bleak import BleakClient
from bleak.uuids import normalize_uuid_16, uuid16_dict
logger = logging.getLogger(__name__)
async def flag(args: argparse.Namespace):
async with BleakClient(args.device, winrt=dict(use_cached_services=True)) as client:
logger.info(f"Connected: {client.is_connected}")
for i in range(1000):
#Read UUID or handle
read_data = await client.read_gatt_char(args.service)
logger.info(f"Read[{args.service}]: {read_data}")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument(
"--macos-use-bdaddr",
action="store_true",
help="when true use Bluetooth address instead of UUID on macOS",
)
parser.add_argument(
"--device",
required=True,
help="Which Device MAC to connect to",
)
parser.add_argument(
"--service",
required=True,
help="UUID or Handle to write to",
)
parser.add_argument(
"--data",
required=True,
help="the Data to write. Can be 0x02, or \"test\"",
)
parser.add_argument(
"-v",
dest="debug",
#default=True,
action="store_true",
help="sets the logging level to debug",
)
args = parser.parse_args()
#Convert to bytes
if args.data.startswith("0x") and all(c in string.hexdigits for c in args.data):
args.data = int(args.data, 16)
else:
args.data = args.data.encode()
log_level = logging.DEBUG if args.debug else logging.INFO
logging.basicConfig(
level=log_level,
format="%(asctime)-15s %(name)-8s %(levelname)s: %(message)s",
)
asyncio.run(flag(args))
Run the script:
>>> python solve10.py --device "64:E8:33:82:AF:6A" --service 0000ff0b-0000-1000-8000-00805f9b34fb --data a
[...]
2023-11-13 23:35:08,025 __main__ INFO: Read[0000ff0b-0000-1000-8000-00805f9b34fb]: bytearray(b'6ffcd214ffebdc0d069e')
2023-11-13 23:35:08,105 __main__ INFO: Read[0000ff0b-0000-1000-8000-00805f9b34fb]: bytearray(b'6ffcd214ffebdc0d069e')
Write the flag:
>>> python write_data.py --device "64:E8:33:82:AF:6A" --service 0000ff02-0000-1000-8000-00805f9b34fb --data "933c1fcfa8ed52d2ec05"
2023-11-13 23:19:52,034 __main__ INFO: Connected: True
2023-11-13 23:19:52,412 __main__ INFO: Read[0000ff02-0000-1000-8000-00805f9b34fb]: bytearray(b'Write Flags Here')
2023-11-13 23:19:52,412 __main__ INFO: Write[0000ff02-0000-1000-8000-00805f9b34fb]: b'933c1fcfa8ed52d2ec05'
2023-11-13 23:19:52,492 __main__ INFO: Returned Data: None
>>> python service_explorer.py --address "64:E8:33:82:AF:6A" 2>&1 | grep Score
2023-11-13 23:37:37,829 __main__ INFO: [Characteristic] 0000ff01-0000-1000-8000-00805f9b34fb (Handle: 41): Vendor specific (read), Value: bytearray(b'Score:10/20')
Flag 11¶
Modified notification Script
import argparse
import asyncio
import logging
from bleak import BleakClient, BleakScanner
from bleak.backends.characteristic import BleakGATTCharacteristic
logger = logging.getLogger(__name__)
def notification_handler(characteristic: BleakGATTCharacteristic, data: bytearray):
"""Simple notification handler which prints the data received."""
logger.info(f"{characteristic.description}: {data}")
async def main(args: argparse.Namespace):
logger.info("starting scan...")
if args.address:
device = await BleakScanner.find_device_by_address(
args.address, cb=dict(use_bdaddr=args.macos_use_bdaddr)
)
if device is None:
logger.error("could not find device with address '%s'", args.address)
return
else:
device = await BleakScanner.find_device_by_name(
args.name, cb=dict(use_bdaddr=args.macos_use_bdaddr)
)
if device is None:
logger.error("could not find device with name '%s'", args.name)
return
logger.info("connecting to device...")
async with BleakClient(device) as client:
logger.info("Connected")
await client.start_notify(args.characteristic, notification_handler)
read_data = await client.read_gatt_char(args.characteristic)
logger.info(f"Read[{args.characteristic}]: {read_data}")
read_data = await client.write_gatt_char(args.characteristic, bytearray([0x01]), response=True)
logger.info(f"Write[{args.characteristic}]: 0x01 {read_data}")
await asyncio.sleep(20.0)
await client.stop_notify(args.characteristic)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
device_group = parser.add_mutually_exclusive_group(required=True)
device_group.add_argument(
"--name",
metavar="<name>",
help="the name of the bluetooth device to connect to",
)
device_group.add_argument(
"--address",
metavar="<address>",
help="the address of the bluetooth device to connect to",
)
parser.add_argument(
"--macos-use-bdaddr",
action="store_true",
help="when true use Bluetooth address instead of UUID on macOS",
)
parser.add_argument(
"characteristic",
metavar="<notify uuid>",
help="UUID of a characteristic that supports notifications",
)
parser.add_argument(
"-d",
"--debug",
action="store_true",
help="sets the log level to debug",
)
args = parser.parse_args()
log_level = logging.DEBUG if args.debug else logging.INFO
logging.basicConfig(
level=log_level,
format="%(asctime)-15s %(name)-8s %(levelname)s: %(message)s",
)
asyncio.run(main(args))
Run the script:
>>> python enable_notifications.py --address "64:E8:33:82:AF:6A" 0000ff0c-0000-1000-8000-00805f9b34fb
2023-11-14 00:01:32,679 __main__ INFO: starting scan...
2023-11-14 00:01:32,824 __main__ INFO: connecting to device...
2023-11-14 00:01:34,198 __main__ INFO: Connected
2023-11-14 00:01:34,765 __main__ INFO: Vendor specific: bytearray(b'Listen to me for a single notification')
2023-11-14 00:01:34,765 __main__ INFO: Read[0000ff0c-0000-1000-8000-00805f9b34fb]: bytearray(b'Listen to me for a single notification')
2023-11-14 00:01:34,848 __main__ INFO: Write[0000ff0c-0000-1000-8000-00805f9b34fb]: 0x01 None
2023-11-14 00:01:34,849 __main__ INFO: Vendor specific: bytearray(b'5ec3772bcd00cf06d8eb')
Write the flag:
>>> python write_data.py --device "64:E8:33:82:AF:6A" --service 0000ff02-0000-1000-8000-00805f9b34fb --data "5ec3772bcd00cf06d8eb"
2023-11-14 00:04:41,191 __main__ INFO: Connected: True
2023-11-14 00:04:41,608 __main__ INFO: Read[0000ff02-0000-1000-8000-00805f9b34fb]: bytearray(b'Write Flags Here')
2023-11-14 00:04:41,609 __main__ INFO: Write[0000ff02-0000-1000-8000-00805f9b34fb]: b'5ec3772bcd00cf06d8eb'
2023-11-14 00:04:41,688 __main__ INFO: Returned Data: None
>>> python service_explorer.py --address "64:E8:33:82:AF:6A" 2>&1 | grep Score
2023-11-14 00:04:54,249 __main__ INFO: [Characteristic] 0000ff01-0000-1000-8000-00805f9b34fb (Handle: 41): Vendor specific (read), Value: bytearray(b'Score:11/20')
Flag 12¶
Listen to handle 0x0044 for a single indication
import argparse
import asyncio
import logging
from bleak import BleakClient, BleakScanner
from bleak.backends.characteristic import BleakGATTCharacteristic
logger = logging.getLogger(__name__)
def notification_handler(characteristic: BleakGATTCharacteristic, data: bytearray):
"""Simple notification handler which prints the data received."""
logger.info(f"{characteristic.description}: {data}")
async def main(args: argparse.Namespace):
logger.info("starting scan...")
if args.address:
device = await BleakScanner.find_device_by_address(
args.address, cb=dict(use_bdaddr=args.macos_use_bdaddr)
)
if device is None:
logger.error("could not find device with address '%s'", args.address)
return
else:
device = await BleakScanner.find_device_by_name(
args.name, cb=dict(use_bdaddr=args.macos_use_bdaddr)
)
if device is None:
logger.error("could not find device with name '%s'", args.name)
return
logger.info("connecting to device...")
async with BleakClient(device) as client:
logger.info("Connected")
await client.start_notify(args.characteristic, notification_handler)
read_data = await client.read_gatt_char(args.characteristic)
logger.info(f"Read[{args.characteristic}]: {read_data}")
read_data = await client.write_gatt_char(args.characteristic, bytearray([0x01]), response=True)
logger.info(f"Write[{args.characteristic}]: 0x01 {read_data}")
await asyncio.sleep(20.0)
await client.stop_notify(args.characteristic)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
device_group = parser.add_mutually_exclusive_group(required=True)
device_group.add_argument(
"--name",
metavar="<name>",
help="the name of the bluetooth device to connect to",
)
device_group.add_argument(
"--address",
metavar="<address>",
help="the address of the bluetooth device to connect to",
)
parser.add_argument(
"--macos-use-bdaddr",
action="store_true",
help="when true use Bluetooth address instead of UUID on macOS",
)
parser.add_argument(
"characteristic",
metavar="<notify uuid>",
help="UUID of a characteristic that supports notifications",
)
parser.add_argument(
"-d",
"--debug",
action="store_true",
help="sets the log level to debug",
)
args = parser.parse_args()
log_level = logging.DEBUG if args.debug else logging.INFO
logging.basicConfig(
level=log_level,
format="%(asctime)-15s %(name)-8s %(levelname)s: %(message)s",
)
asyncio.run(main(args))
Run the script:
>>> python enable_notifications.py --address "64:E8:33:82:AF:6A" 0000ff0e-0000-1000-8000-00805f9b34fb
2023-11-14 00:10:18,764 __main__ INFO: starting scan...
2023-11-14 00:10:18,923 __main__ INFO: connecting to device...
2023-11-14 00:10:20,253 __main__ INFO: Connected
2023-11-14 00:10:20,612 __main__ INFO: Vendor specific: bytearray(b'Listen to handle 0x0044 for a single indication\x00')
2023-11-14 00:10:20,612 __main__ INFO: Read[0000ff0e-0000-1000-8000-00805f9b34fb]: bytearray(b'Listen to handle 0x0044 for a single indication\x00')
2023-11-14 00:10:20,695 __main__ INFO: Write[0000ff0e-0000-1000-8000-00805f9b34fb]: 0x01 None
2023-11-14 00:10:20,695 __main__ INFO: Vendor specific: bytearray(b'c7b86dd121848c77c113')
Write the flag:
>>> python write_data.py --device "64:E8:33:82:AF:6A" --service 0000ff02-0000-1000-8000-00805f9b34fb --data "c7b86dd121848c77c113"
2023-11-14 00:11:07,529 __main__ INFO: Connected: True
2023-11-14 00:11:07,775 __main__ INFO: Read[0000ff02-0000-1000-8000-00805f9b34fb]: bytearray(b'Write Flags Here')
2023-11-14 00:11:07,775 __main__ INFO: Write[0000ff02-0000-1000-8000-00805f9b34fb]: b'c7b86dd121848c77c113'
2023-11-14 00:11:07,855 __main__ INFO: Returned Data: None
>>> python service_explorer.py --address "64:E8:33:82:AF:6A" 2>&1 | grep Score
2023-11-14 00:11:20,576 __main__ INFO: [Characteristic] 0000ff01-0000-1000-8000-00805f9b34fb (Handle: 41): Vendor specific (read), Value: bytearray(b'Score:12/20')
Flag 13¶
Listen for a single indication
Run the script:
>>> python enable_notifications.py --address "64:E8:33:82:AF:6A" 0000ff0f-0000-1000-8000-00805f9b34fb
2023-11-14 00:18:31,246 __main__ INFO: starting scan...
2023-11-14 00:18:31,408 __main__ INFO: connecting to device...
2023-11-14 00:18:32,436 __main__ INFO: Connected
2023-11-14 00:18:32,658 __main__ INFO: Vendor specific: bytearray(b'Listen to me for multi notifications')
2023-11-14 00:18:32,659 __main__ INFO: Read[0000ff0f-0000-1000-8000-00805f9b34fb]: bytearray(b'Listen to me for multi notifications')
2023-11-14 00:18:32,738 __main__ INFO: Write[0000ff0f-0000-1000-8000-00805f9b34fb]: 0x01 None
2023-11-14 00:18:32,738 __main__ INFO: Vendor specific: bytearray(b'U no want this msg\x00\x00')
2023-11-14 00:18:33,738 __main__ INFO: Vendor specific: bytearray(b'c9457de5fd8cafe349fd')
2023-11-14 00:18:34,738 __main__ INFO: Vendor specific: bytearray(b'c9457de5fd8cafe349fd')
2023-11-14 00:18:35,738 __main__ INFO: Vendor specific: bytearray(b'c9457de5fd8cafe349fd')
2023-11-14 00:18:36,738 __main__ INFO: Vendor specific: bytearray(b'c9457de5fd8cafe349fd')
2023-11-14 00:18:37,738 __main__ INFO: Vendor specific: bytearray(b'c9457de5fd8cafe349fd')
2023-11-14 00:18:38,738 __main__ INFO: Vendor specific: bytearray(b'c9457de5fd8cafe349fd')
2023-11-14 00:18:39,738 __main__ INFO: Vendor specific: bytearray(b'c9457de5fd8cafe349fd')
2023-11-14 00:18:40,738 __main__ INFO: Vendor specific: bytearray(b'c9457de5fd8cafe349fd')
2023-11-14 00:18:41,738 __main__ INFO: Vendor specific: bytearray(b'c9457de5fd8cafe349fd')
2023-11-14 00:18:42,738 __main__ INFO: Vendor specific: bytearray(b'c9457de5fd8cafe349fd')
2023-11-14 00:18:43,738 __main__ INFO: Vendor specific: bytearray(b'c9457de5fd8cafe349fd')
2023-11-14 00:18:44,739 __main__ INFO: Vendor specific: bytearray(b'c9457de5fd8cafe349fd')
2023-11-14 00:18:45,738 __main__ INFO: Vendor specific: bytearray(b'c9457de5fd8cafe349fd')
2023-11-14 00:18:46,738 __main__ INFO: Vendor specific: bytearray(b'c9457de5fd8cafe349fd')
2023-11-14 00:18:47,738 __main__ INFO: Vendor specific: bytearray(b'c9457de5fd8cafe349fd')
2023-11-14 00:18:48,738 __main__ INFO: Vendor specific: bytearray(b'c9457de5fd8cafe349fd')
2023-11-14 00:18:49,738 __main__ INFO: Vendor specific: bytearray(b'c9457de5fd8cafe349fd')
2023-11-14 00:18:50,738 __main__ INFO: Vendor specific: bytearray(b'c9457de5fd8cafe349fd')
2023-11-14 00:18:51,741 __main__ INFO: Vendor specific: bytearray(b'c9457de5fd8cafe349fd')
2023-11-14 00:18:52,738 __main__ INFO: Vendor specific: bytearray(b'c9457de5fd8cafe349fd')
Write the flag:
>>> python write_data.py --device "64:E8:33:82:AF:6A" --service 0000ff02-0000-1000-8000-00805f9b34fb --data "c9457de5fd8cafe349fd"
2023-11-14 00:19:15,739 __main__ INFO: Connected: True
2023-11-14 00:19:15,978 __main__ INFO: Read[0000ff02-0000-1000-8000-00805f9b34fb]: bytearray(b'Write Flags Here')
2023-11-14 00:19:15,979 __main__ INFO: Write[0000ff02-0000-1000-8000-00805f9b34fb]: b'c9457de5fd8cafe349fd'
2023-11-14 00:19:16,058 __main__ INFO: Returned Data: None
>>> python service_explorer.py --address "64:E8:33:82:AF:6A" 2>&1 | grep Score
2023-11-14 00:19:31,739 __main__ INFO: [Characteristic] 0000ff01-0000-1000-8000-00805f9b34fb (Handle: 41): Vendor specific (read), Value: bytearray(b'Score:13/20')
Flag 14¶
Listen to handle 0x004a for multi indications
Run the script:
>>> python enable_notifications.py --address "64:E8:33:82:AF:6A" 0000ff11-0000-1000-8000-00805f9b34fb
2023-11-14 00:20:20,240 __main__ INFO: starting scan...
2023-11-14 00:20:20,390 __main__ INFO: connecting to device...
2023-11-14 00:20:21,743 __main__ INFO: Connected
2023-11-14 00:20:22,141 __main__ INFO: Vendor specific: bytearray(b'Listen to handle 0x004a for multi indications\x00')
2023-11-14 00:20:22,142 __main__ INFO: Read[0000ff11-0000-1000-8000-00805f9b34fb]: bytearray(b'Listen to handle 0x004a for multi indications\x00')
2023-11-14 00:20:22,218 __main__ INFO: Write[0000ff11-0000-1000-8000-00805f9b34fb]: 0x01 None
2023-11-14 00:20:22,219 __main__ INFO: Vendor specific: bytearray(b'U no want this msg\x00\x00')
2023-11-14 00:20:22,302 __main__ INFO: Vendor specific: bytearray(b'b6f3a47f207d38e16ffa')
2023-11-14 00:20:22,378 __main__ INFO: Vendor specific: bytearray(b'b6f3a47f207d38e16ffa')
2023-11-14 00:20:22,458 __main__ INFO: Vendor specific: bytearray(b'b6f3a47f207d38e16ffa')
Write the flag:
>>> python write_data.py --device "64:E8:33:82:AF:6A" --service 0000ff02-0000-1000-8000-00805f9b34fb --data "b6f3a47f207d38e16ffa"
2023-11-14 00:21:05,699 __main__ INFO: Connected: True
2023-11-14 00:21:05,938 __main__ INFO: Read[0000ff02-0000-1000-8000-00805f9b34fb]: bytearray(b'Write Flags Here')
2023-11-14 00:21:05,939 __main__ INFO: Write[0000ff02-0000-1000-8000-00805f9b34fb]: b'b6f3a47f207d38e16ffa'
2023-11-14 00:21:06,021 __main__ INFO: Returned Data: None
>>> python service_explorer.py --address "64:E8:33:82:AF:6A" 2>&1 | grep Score
2023-11-14 00:21:15,783 __main__ INFO: [Characteristic] 0000ff01-0000-1000-8000-00805f9b34fb (Handle: 41): Vendor specific (read), Value: bytearray(b'Score:14/20')
Flag 15¶
Connect with BT MAC address 11:22:33:44:55:66'
TODO
Flag 16¶
Set your connection MTU to 444
Needed a separate library for MTU Support bluepy
Script:
#!/usr/bin/env python3
import bluepy.btle as btle
dev = btle.Peripheral('64:E8:33:82:AF:6A')
dev.setMTU(444)
print(dev.readCharacteristic(0x4e).decode())
Run the script:
>>> python mtu.py
b1e409e5a4eaf9fe5158
Write the flag:
>>> python write_data.py --device "64:E8:33:82:AF:6A" --service 0000ff02-0000-1000-8000-00805f9b34fb --data "b1e409e5a4eaf9fe5158"
2023-11-22 15:05:33,163 __main__ INFO: Connected: True
2023-11-22 15:05:33,537 __main__ INFO: Read[0000ff02-0000-1000-8000-00805f9b34fb]: bytearray(b'Write Flags Here')
2023-11-22 15:05:33,537 __main__ INFO: Write[0000ff02-0000-1000-8000-00805f9b34fb]: b'b1e409e5a4eaf9fe5158'
2023-11-22 15:05:33,617 __main__ INFO: Returned Data: None
>>> python service_explorer.py --address "64:E8:33:82:AF:6A" 2>&1 | grep Score
2023-11-22 15:08:29,981 __main__ INFO: [Characteristic] 0000ff01-0000-1000-8000-00805f9b34fb (Handle: 41): Vendor specific (read), Value: bytearray(b'Score:15/20')
Flag 17¶
Write+resp 'hello'
Write the String:
>>> python write_data.py --device "64:E8:33:82:AF:6A" --service 0000ff14-0000-1000-8000-00805f9b34fb --data "hello"
2023-11-22 15:11:26,263 __main__ INFO: Connected: True
2023-11-22 15:11:26,621 __main__ INFO: Read[0000ff14-0000-1000-8000-00805f9b34fb]: bytearray(b"Write+resp \'hello\' ")
2023-11-22 15:11:26,621 __main__ INFO: Write[0000ff14-0000-1000-8000-00805f9b34fb]: b'hello'
2023-11-22 15:11:26,700 __main__ INFO: Returned Data: None
Read the flag:
>>> python service_explorer.py --address "64:E8:33:82:AF:6A" 2>&1 | grep 0000ff14-0000-1000-8000-00805f9b34fb
2023-11-22 15:12:19,182 __main__ INFO: [Characteristic] 0000ff14-0000-1000-8000-00805f9b34fb (Handle: 79): Vendor specific (read,write), Value: bytearray(b'd41d8cd98f00b204e980\x00')
Write the flag:
>>> python write_data.py --device "64:E8:33:82:AF:6A" --service 0000ff02-0000-1000-8000-00805f9b34fb --data "d41d8cd98f00b204e980"
2023-11-22 15:14:09,430 __main__ INFO: Connected: True
2023-11-22 15:14:09,824 __main__ INFO: Read[0000ff02-0000-1000-8000-00805f9b34fb]: bytearray(b'Write Flags Here')
2023-11-22 15:14:09,824 __main__ INFO: Write[0000ff02-0000-1000-8000-00805f9b34fb]: b'd41d8cd98f00b204e980'
2023-11-22 15:14:09,904 __main__ INFO: Returned Data: None
>>> python service_explorer.py --address "64:E8:33:82:AF:6A" 2>&1 | grep Score
2023-11-22 15:14:33,105 __main__ INFO: [Characteristic] 0000ff01-0000-1000-8000-00805f9b34fb (Handle: 41): Vendor specific (read), Value: bytearray(b'Score:16/20')
Flag 18¶
'No notifications here! really?'
Read Notification:
Write the flag:
>>> python write_data.py --device "64:E8:33:82:AF:6A" --service 0000ff02-0000-1000-8000-00805f9b34fb --data "b1e409e5a4eaf9fe5158"
2023-11-22 15:05:33,163 __main__ INFO: Connected: True
2023-11-22 15:05:33,537 __main__ INFO: Read[0000ff02-0000-1000-8000-00805f9b34fb]: bytearray(b'Write Flags Here')
2023-11-22 15:05:33,537 __main__ INFO: Write[0000ff02-0000-1000-8000-00805f9b34fb]: b'b1e409e5a4eaf9fe5158'
2023-11-22 15:05:33,617 __main__ INFO: Returned Data: None
>>> python service_explorer.py --address "64:E8:33:82:AF:6A" 2>&1 | grep Score
2023-11-22 15:08:29,981 __main__ INFO: [Characteristic] 0000ff01-0000-1000-8000-00805f9b34fb (Handle: 41): Vendor specific (read), Value: bytearray(b'Score:15/20')
Flag 19¶
'So many properties!'
Write the flag:
>>> python write_data.py --device "64:E8:33:82:AF:6A" --service 0000ff02-0000-1000-8000-00805f9b34fb --data "b1e409e5a4eaf9fe5158"
2023-11-22 15:05:33,163 __main__ INFO: Connected: True
2023-11-22 15:05:33,537 __main__ INFO: Read[0000ff02-0000-1000-8000-00805f9b34fb]: bytearray(b'Write Flags Here')
2023-11-22 15:05:33,537 __main__ INFO: Write[0000ff02-0000-1000-8000-00805f9b34fb]: b'b1e409e5a4eaf9fe5158'
2023-11-22 15:05:33,617 __main__ INFO: Returned Data: None
>>> python service_explorer.py --address "64:E8:33:82:AF:6A" 2>&1 | grep Score
2023-11-22 15:08:29,981 __main__ INFO: [Characteristic] 0000ff01-0000-1000-8000-00805f9b34fb (Handle: 41): Vendor specific (read), Value: bytearray(b'Score:15/20')
Flag 20¶
"md5 of author's twitter handle"
Write the flag:
>>> python write_data.py --device "64:E8:33:82:AF:6A" --service 0000ff02-0000-1000-8000-00805f9b34fb --data "b1e409e5a4eaf9fe5158"
2023-11-22 15:05:33,163 __main__ INFO: Connected: True
2023-11-22 15:05:33,537 __main__ INFO: Read[0000ff02-0000-1000-8000-00805f9b34fb]: bytearray(b'Write Flags Here')
2023-11-22 15:05:33,537 __main__ INFO: Write[0000ff02-0000-1000-8000-00805f9b34fb]: b'b1e409e5a4eaf9fe5158'
2023-11-22 15:05:33,617 __main__ INFO: Returned Data: None
>>> python service_explorer.py --address "64:E8:33:82:AF:6A" 2>&1 | grep Score
2023-11-22 15:08:29,981 __main__ INFO: [Characteristic] 0000ff01-0000-1000-8000-00805f9b34fb (Handle: 41): Vendor specific (read), Value: bytearray(b'Score:15/20')