Skip to content

Make ubertooth-btle -v1 (CRC verify) actually filter bad-CRC packets in LE sniffing#550

Open
Oliver0804 wants to merge 2 commits into
greatscottgadgets:masterfrom
Oliver0804:le-crc-verify-fix
Open

Make ubertooth-btle -v1 (CRC verify) actually filter bad-CRC packets in LE sniffing#550
Oliver0804 wants to merge 2 commits into
greatscottgadgets:masterfrom
Oliver0804:le-crc-verify-fix

Conversation

@Oliver0804

Copy link
Copy Markdown

Summary

ubertooth-btle -v1 (CRC verification) is documented but is currently a silent no-op for all LE sniffing modes (-n, -f). As a result, bit-errored packets are streamed to the host and show up as "phantom" advertisers — bit-flipped copies of real advertising addresses.

There are actually two independent reasons -v1 does nothing during sniffing:

1. Host: CRC verify is set after the capture loop (ubertooth-btle.c)

In main(), the do_follow || do_no_follow || do_promisc block runs the entire while (running) { cmd_poll(...) } capture loop and only returns on Ctrl-C. The do_crc handling that calls cmd_set_crc_verify() sits after that block, so for sniffing it executes only once capture has already ended.

Fix: issue cmd_set_crc_verify() just before the capture loop — after the mode has started, since mode entry runs reset_le() which clears crc_verify.

2. Firmware: the modern LE engine never checked the CRC (le_phy.c)

-n/-f are serviced by le_phy_main() (le_phy.c), which forwarded every received packet regardless of CRC. Only the legacy bt_le_sync() path (now reached only for promiscuous mode) honoured le.crc_verify.

Fix: after dewhitening, compute the CRC and drop bad-CRC packets when le.crc_verify is set. Advertising-channel PDUs use the fixed CRCInit (reversed 0xAAAAAA); data-channel PDUs use the value recovered from CONNECT_IND. Gated on le.crc_verify, so the default behaviour is unchanged.

Testing

Built host tools + firmware and flashed an Ubertooth One (was 2020-12-R1, now this branch). Captured advertising on channel 37 for 15 s with and without -v1, validating CRCs in Wireshark (btle.crc.incorrect):

total pkts bad CRC unique advertisers
-n (no -v1) 1198 114 (9.5%) 137
-n -v1 1108 0 (0.0%) 27

With -v1 the bad-CRC packets are dropped on-device and the phantom advertisers disappear; without it, behaviour is unchanged.

Notes

  • Two commits: the firmware change and the host change. Each is inert without the other, but together they make -v1 work end-to-end for LE sniffing.
  • No change to default behaviour — CRC verification stays off unless -v1 is passed.

The modern LE engine (le_phy.c, used by ubertooth-btle -n/-f) forwarded every
received packet including bit-errored ones, so UBERTOOTH_SET_CRC_VERIFY had no
effect there — only the legacy bt_le_sync() path (now just promiscuous mode)
honoured le.crc_verify. Bit-flipped phantom advertisers leaked to the host.

Verify the CRC after dewhitening and drop bad-CRC packets when le.crc_verify is
set. Advertising-channel PDUs use the fixed CRCInit (reversed 0xAAAAAA);
data-channel PDUs use the value recovered from CONNECT_IND. Disabled by
default, so legacy behaviour is unchanged.
ubertooth-btle handled -v (do_crc) only after the streaming loop returned, so
cmd_set_crc_verify ran after capture had already ended — making -v1 a silent
no-op for all sniffing modes. Move the call to just before the capture loop
(after mode start, since mode entry resets crc_verify).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant