ESP32-C5 Wireshark Sniffer

Turn cheap ESP32-C5 boards into dual-band (2.4 GHz + 5 GHz) Wi-Fi sniffers that show up as ordinary capture interfaces inside Wireshark — with a toolbar for changing channels while the capture runs, and support for several boards at once.

Four Seeed Studio XIAO ESP32C5 boards, each with an external antenna soldered to its u.FL connector, plugged into the four numbered ports of a powered USB 3.0 hub.
Four Seeed Studio XIAO ESP32C5 boards on a powered hub — four Wireshark interfaces, all capturing at once. Use a powered hub: an unpowered one browns out under this many sniffers and causes failures that look exactly like firmware bugs.

Flash a board from this page

Plug an ESP32-C5 into a USB port using its native USB connector, then press the button. Nothing to install.

This browser cannot talk to serial devices. Use Chrome or Edge 89+ (or Firefox 151+). Safari is not supported — see the manual flashing instructions below. Serial access is not allowed on this page.

Chrome / Edge 89+, Firefox 151+, Chrome for Android. Not Safari.

If the board does not start sniffing after flashing. Some boards come up latched in download mode and never run the new firmware. Unplug it and plug it back in, or press its BOOT button once. This is a quirk of the board, not the firmware — it happened on two of the three boards this tool was developed against.
Wireshark capturing from two ESP32 sniffer interfaces at once, showing Wi-Fi columns for PHY type, channel, rate, frequency, signal and noise.
Two boards captured at once and merged into one window. The columns and the Wi-Fi filter buttons along the top come from the ESP32-Sniffer profile that installs with the tool.

What you get

Each board is an interface Plug in two or three and Wireshark lists them all. Capture from several at once and the frames merge into one window, each tagged with the board it came from.
Channels, your way One channel (6), several (1,6,11), a range (1-11) or a mix (1-13,36,149-165). Tick them in a list, or type them.
Change it live View → Interface Toolbars gives you a channel picker and a dwell time that retune the board mid-capture, without restarting it.
Dual band 2.4 GHz channels 1–14 and 5 GHz 36–177, on the same board.
Radio detail Every frame carries a radiotap header: channel, frequency, signal and noise in dBm, so Wireshark’s Wi-Fi columns and filters all work.
Zigbee and Thread too The same board sniffs IEEE 802.15.4 on channels 11–26, as a second interface. Wireshark dissects Zigbee, 6LoWPAN and Thread from it with nothing extra installed.
And Bluetooth LE advertising A third interface captures BLE advertising — beacons, trackers, and whatever a device broadcasts before anyone connects to it. Not connection traffic: see below.

Set up the Wireshark side

Flashing the board is only half of it. The other half is one command.

1. Requirements

2. Register the sniffer with Wireshark

git clone https://github.com/oshri-almog/esp32c5-wireshark-sniffer
cd esp32c5-wireshark-sniffer
pip install -r requirements.txt
python extcap/install.py

That installs a small launcher into Wireshark’s extcap folder and the ESP32-Sniffer Wireshark profile (Wi-Fi columns, colouring rules and filter buttons for beacons by Wi-Fi generation, probes, auth, RTS/CTS, ACKs, EAPOL and more). An existing profile of that name is never overwritten.

3. Capture

  1. Open Wireshark. Press F5 if the board is not in the list yet.
  2. Double-click ESP32 Wi-Fi sniffer (COM14, …).
  3. Use the gear icon next to it to pick the serial port, the channels and the dwell time.
  4. Turn on View → Interface Toolbars → ESP32 Wi-Fi sniffer to change channels while capturing.
Three ESP32 boards in Wireshark's interface list; the interface options dialog showing the serial port picker and the channel tick list with a drop-down of ready-made channel lists.
Three boards in the interface list, the serial port picker, and the channels as a tick list with ready-made lists to choose from. Tick a band heading to take the whole band.
The ESP32 sniffer toolbar inside Wireshark: a board selector, a Channels drop-down and a Custom text box.
The toolbar. Pick a board, choose a ready-made channel list or type your own, and the board retunes without the capture stopping.

4. Zigbee and Thread

Every board is listed three times, once per radio. The second entry, ESP32 Zigbee/Thread sniffer, captures raw IEEE 802.15.4 on channels 11–26 instead of Wi-Fi. It behaves exactly like the Wi-Fi one — same tick list, same toolbar — and Wireshark dissects Zigbee, 6LoWPAN and Thread from it without any extra plugin.

A board captures Wi-Fi or 802.15.4, never both: there is one radio and one antenna. Choosing the other interface reboots the board, which takes a second or two before frames appear. That is deliberate — handing the antenna between the two radios while running leaves the radio in a state that only unplugging the board clears.

Zigbee traffic above the network layer is encrypted. To read it, put the network key into Preferences → Protocols → ZigBee NWK. Thread shows up as 6LoWPAN and IPv6 with no key needed.

5. Bluetooth LE

The third entry, ESP32 Bluetooth LE advertising sniffer, captures BLE advertising: beacons, trackers, and whatever a device broadcasts before anyone connects to it. Wireshark dissects it with its ordinary Bluetooth dissectors, so addresses, device names, manufacturer data and iBeacon payloads all come out named. Twenty seconds in an ordinary flat picked up 27 different advertisers here.

What this does not do. It captures advertising, not connections. Once two devices pair up and move to the data channels, they vanish from this capture. That is a limit of the hardware, not of the firmware: the ESP32-C5 has no promiscuous mode for Bluetooth, only a passive scan — and no Bluetooth Classic (BR/EDR) at all. To follow connections you need a sniffer that hops with them, such as an nRF52840 running Nordic’s nRF Sniffer, which comes with its own Wireshark plugin.

Two smaller things follow from the same limit. The controller will not be restricted to one advertising channel, so there is no channel list for this interface — it listens on 37, 38 and 39 together. And it does not report which of them a packet arrived on, so every packet is recorded as channel 37. The capture also carries no CRC, and says so rather than claiming one was checked.

Dark mode tip. On Windows, Qt draws tick boxes with the system theme and in dark mode an unticked box has no visible outline, which makes the channel list hard to read. Start Wireshark with extcap\wireshark-fusion.bat, or set QT_STYLE_OVERRIDE=Fusion once, and the boxes become visible again without giving up dark mode.

Flashing without this page

If you would rather use a terminal, or you are on Safari:

# with ESP-IDF v5.5 or newer
cd firmware
idf.py set-target esp32c5
idf.py -p COM14 flash

# or flash the prebuilt merged image with esptool
esptool --chip esp32c5 --port COM14 write_flash 0x0 esp32c5-sniffer-1.2.0-merged.bin

Download the merged firmware image (1.1 MiB, flashes at offset 0x0).

Troubleshooting

Board missing from Wireshark Press F5 in Wireshark. Check the board appears as a serial port (USB VID 303A, PID 1001).
“Serial connection failed” Only one program may hold a serial port. Close any serial monitor, and any second copy of the capture.
Random failures, ports renumbering Almost always the USB link. Use a powered hub or a direct port, and a known-good data cable. A faulty cable and an unpowered hub cost this project hours of confusing, intermittent errors.
Nothing captured Check the channel actually carries traffic, and that the board is not sitting in download mode (power-cycle it).
A board prints <<START>> and then nothing It is almost certainly listening with the other radio. A board remembers its radio across reboots, so one last used for Zigbee or Thread stays there, sends its marker and header, and then waits on a band with nothing on it. Nothing is wrong with it. Wireshark sets the radio itself, so this only bites in a serial monitor or with host/sniffer.py — pass --mode wifi to bring it back.
No Wi-Fi after using the Zigbee/Thread interface Rare, and a reset will not clear it: unplug the board and plug it back in. The two radios share one antenna, and a board that has run 802.15.4 can come back deaf to Wi-Fi until it actually loses power. The firmware gives the radio back cleanly before it reboots, which avoids this in normal use.
Frames marked malformed A few per thousand is normal: the Wi-Fi driver reports some MIMO frames with metadata that does not match their contents. The rest of the capture is unaffected.

How it works

Wi-Fi driver --callback--> ring buffer --writer task--> USB-Serial-JTAG
                                                            |
                                          extcap plugin (Python) --pipe--> Wireshark

The firmware puts the radio in promiscuous mode and writes libpcap records straight to the board’s native USB port — nothing else shares that port, so the byte stream stays clean (logs go to UART instead). A frame is sent whole or dropped whole, so the stream never loses framing, and the host resynchronises on a marker if it ever does.