
Disclosure: JustCallMeKoko supplied the Marauder v6.1. Youyeetoo supplied the X1S from my earlier benchmark series. Testing, tooling, and conclusions are my own.
The Marauder had already done the hard part: it could sit on my desk, capture the WiFi traffic around it, and save a PCAP to its SD card. I believed I was the bottleneck. Every useful run still ended with me pulling the card and opening Wireshark, the packet-analysis application I use to inspect individual frames, follow network conversations, and work out what actually happened in a capture.
Here's the thing: I wanted those captures to become readable first-pass reports without ever leaving my lab. No cloud API, no uploading the PCAP somewhere else, nothing. That led me back to the same Celeron N5095 box from my X1S benchmark series. The stock firmware's serial path moved each capture into Linux, tshark reduced it to a compact evidence brief, and a 4-billion-parameter local model wrote the initial analysis. The cable eventually disappeared too, but first I needed to know whether the pipeline could notice anything worth investigating.
It did, and sooner than I expected. By the end of the first day, a 60-second passive capture had turned up 83 deauthentication frames from a single source in the shared RF environment around me. I had not staged that traffic or targeted a network. That was the first real "wait, what?" moment of the project.
That surprise changed how I thought about the rest of the build. I was no longer trying to save myself a few minutes in Wireshark. I wanted to know whether the small model could stay grounded, whether a verifier could catch its mistakes, and whether the whole system would hold up when I generated known-good traffic on my own network. The answers were useful, and not always flattering to the model or to my first test design.
| Stage | Runs on | Job |
|---|---|---|
| Capture | ESP32 Marauder | Record the authorized WiFi traffic and save a PCAP |
| Brief | tshark on the SBC | Reduce packet fields to a compact, deterministic evidence brief |
| Report | Local Ollama model | Write a first-pass explanation without sending the capture to a cloud API |
| Check | Python verifier | Reconcile the specific counts and citations it knows how to test |
Why I paired the Marauder with the X1S
The capture side is the ESP32 Marauder v6.1 that JustCallMeKoko supplied for this project. It arrived running v1.8.5, so the first thing I did was update it from the SD card to v1.15.1, the current release while I was testing. Everything below runs on that build. v1.16.0 shipped on September 8, 2026, after testing wrapped, and I have not tested this project against it yet.
On the other side was the Youyeetoo X1S: Celeron N5095, 16 GB of RAM, no discrete GPU, and no WiFi hardware. The integrated Intel UHD graphics stayed unused, so every inference number below is CPU-only. Oddly enough, the lack of WiFi made the X1S a better fit for this job. It could analyze the airspace without adding another radio to it.
That was enough to get the first version moving, but it did not stay a one-box setup. Later, an Indiedroid Nova joined the project with an RK3588S, 16 GB of RAM, and onboard WiFi. The X1S handled the first serial and model runs, while the Nova eventually became both a wireless capture puller and the controlled client in my active test. Its radio ended up mattering as much as its CPU.
Tested hardware
| Capture device | ESP32 Marauder v6.1, firmware v1.15.1 (pinned commit in repo) |
| Analysis box 1 | Youyeetoo X1S, Celeron N5095, 16 GB RAM, CPU-only, no WiFi |
| Analysis box 2 | Indiedroid Nova, RK3588S, 16 GB RAM, CPU-only, WiFi onboard |
| Models | qwen3.5:0.8b and qwen3:4b-instruct via Ollama |
| Summarizer | tshark, one deterministic pass per PCAP |
| SD card | 64 GB, FAT32 |


Getting the captures off the device
The stock firmware can already stream captures live over USB serial, although I found the mechanism in the firmware source rather than the wiki. A Buffer::saveSerial path emits PCAP bytes between [BUF/BEGIN] markers whenever a sniff runs with the -serial flag. From there, a small Python script on the X1S sends the CLI commands, reassembles the segments, and writes a timestamped PCAP.
My first numbers made serial look terrible, and for a while I believed them. A 60-second stream contained 1,337 frames, while what I thought was a matching SD capture contained 4,474, so I wrote down that the UART had dropped roughly two thirds of the traffic. Then I checked the timestamps. The SD file covered 197 seconds, not 60, and the per-second rates were nearly identical. I had compared durations, not throughput.
Luckily, the firmware gave me a clean way to rerun the test. With -serial, the same buffer flush writes to the SD card and the serial stream at the same time. In a matched 60-second run in the same busy airspace, both files came back byte-identical, with the same sha256 and 1,718 frames each. That does not make the serial link unlimited. At 115200 baud, the theoretical ceiling is about 11.5 KB/s, and my capture averaged about 8.7. A busier environment could still outrun it, so the SD card remains the safer path when the capture rate starts getting close to that ceiling.
From PCAP to brief, the part everyone skips
The obvious shortcut was to dump the raw packet text into the 4B model and ask what it saw. That was also the wrong shape of the problem. It burned context and made it harder to tell whether the model had actually read the evidence or had simply written something plausible. What worked better was a deterministic first pass: tshark reads the PCAP and emits a compact plain-text brief with frame counts by 802.11 type and subtype, unique APs by BSSID, top talkers, probe-request senders, and deauth counts. After a lesson I will get to, I added a second pass for EAPOL handshake messages and a plain completeness verdict.
I was not inventing that shape from scratch. Cisco's PROBE paper uses a 500-to-5,000-token representation for LLM analysis of packet captures, and it also influenced the last stage of my pipeline: a reconciliation step that checks the model's quantitative claims against the brief before the report can carry a passing check. Here, that means frame totals, AP counts, probing devices, deauth counts, EAPOL totals, handshake message counts, completeness verdicts, and MAC citations. The checker reads the deterministic brief, not the raw packets, and it cannot judge subtype mixes, directionality, or whether the model's interpretation makes sense. A pass is useful, but it is not the same thing as being right.
LLMcap, Abkenar's pathology taxonomy, and PLUME's protocol-aware representation work helped shape the rest of the design. They gave me good reasons to test a compact local approach, but they do not prove that small models generally beat larger ones. My project does not prove that either.
What the models did with it
The first model comparison was simple: the same raw-capture brief went through two local models on the X1S.
| Model | Speed on N5095 | What it did |
|---|---|---|
| qwen3.5:0.8b | 7.4 tok/s | Invented 140 deauth events where the data said 83, plus a dual-AP topology that does not exist |
| qwen3:4b-instruct | ~1 tok/s | Correctly reported 78 APs, 83 deauthentication frames, and the single source responsible for them |
On a later one-command sniffbeacon run, the 4B model also inferred something I had not told it: an all-beacon frame mix meant the capture had been filtered to beacons. In that case, it was right. That little success felt promising, but a different beacon run showed why it was nowhere near enough to trust the model. The 0.8B version claimed potential spoofing by a single entity, mangled the frame mix into a meaningless ratio, and still passed the numeric checks because the numbers it quoted happened to match the brief. It was fast, numerically compliant, and still wrong.
I do not think the takeaway is simply "bigger is better." These were two models from different Qwen generations, so they cannot establish a clean parameter threshold. What I can say is narrower: the 0.8B model was fast and unreliable on these briefs, while the 4B model was slower and materially better. Both still needed a deterministic check and a human who understood its limits. PROBE found a related problem at a much larger scale: naive ensemble voting scored worse than a single pass, while evidence-grounded reconciliation improved the measured results.
The anomaly the pipeline found on day one
Remember those 83 deauthentication frames from the opening? I could not just leave that result hanging. The sniff had been completely passive, ran for only 60 seconds, and had no target, yet every one of those frames came from a single source in the surrounding RF environment.
I did not have enough evidence to identify the cause. Mesh WiFi systems and modern ISP routers can deauthenticate their own clients while steering them between bands and nodes. Router reboots and DFS channel changes can produce bursts too, and an attack remains another possible explanation. Sixty seconds of listening cannot separate those possibilities.
The next day, I let the Marauder listen longer. The day-one device never showed up again. Instead, a different radio dominated the capture by sending unicast deauths to one client with reason code 15, four-way handshake timeout, in clusters about 17 seconds apart with long quiet gaps. That looked much more like a struggling client or mesh steering than an attack: unicast instead of broadcast, a rhythm instead of a burst, and a reason code saying the AP had given up waiting for the handshake to finish. The follow-up did not identify the original source or support an attack conclusion. It was a less exciting answer, but the process had worked. The first result gave me a concrete capture to run next instead of a scary label to repeat.
Attacking my own lab AP on purpose
At that point I knew the pipeline could notice something interesting in passive traffic, but I still had no way to tell whether its verdicts matched a known event. To test that properly, I needed to give it controlled ground truth.
I used my own hotspot as the target and joined the Nova as its only client. From the X1S, the Marauder ran the wiki's targeted active PMKID workflow headless over serial: scan, select the AP, then run sniffpmkid -d -l. That command deauthenticates only the selected network's clients and listens for the re-authentication handshakes that follow.
Almost immediately, the test found two bugs in my own tooling, which is exactly what a real demo tends to do. My serial script was sending sniffpmkid -d without -l, the untargeted broadcast variant, instead of the targeted workflow I had documented. The summarizer was also counting only 802.11 frame types, which made EAPOL invisible because handshake frames ride inside QoS data frames. I fixed both before continuing, and the corrections are in the release package.
Once those bugs were out of the way, the first clean run captured four EAPOL Message-2 frames from the Nova in the middle of a handshake. The Nova's own journal showed4way_handshake -> disconnected during the same second. The deauth worked, the sniffer heard it, the model described it, and the verifier reconciled the fields it covers. More importantly, the brief stopped at the right conclusion: Message 2 without Message 1 is partial material, not enough to crack. That restraint was exactly what I wanted from the pipeline.
Cutting the cable
Once serial was working, the cable started to annoy me. The whole point of the Marauder is that I can pick it up and carry it around, so leaving it tethered to the X1S felt like stopping halfway. I wrote a small firmware module called FileServe, an HTTP server baked into a custom v1.15.1 build. One CLI command brings up an access point on the Marauder and serves /health,/list, and /get from the SD card behind an optional token. The build recipe is in the release package, and the stock flash backup remains one SD-card file away.
The first wireless pull was a 27,917-byte probe capture, and its size matched the Marauder's SD listing to the byte. Then I tried a 1,863,208-byte raw capture. That one needed curl retries because the Nova's WiFi driver was flapping, but it made it across. A matching size does not prove matching contents, so I hash-checked the small files and verified the large one with a clean tshark parse and matching frame counts. From there, the Nova ran the entire pipeline itself: pull, summarize, analyze with its own CPU-only Ollama, and verify. No cable, card removal, or cloud API was needed.
That wireless session also showed me how little room the ESP32 had left. I measured about 92K of free heap at idle and about 35K with the access point and server running. After a long scan-and-attack session, that fell to 12K; /get began resetting connections even though/health still answered. A reboot brought it back.
The Nova found its own limit while I was doing this. It hard-crashed three times when the 4B model used all cores, with each journal ending like an instant power loss. At two threads it remained stable, peaked at 65 C, and generated about 4 tokens per second, roughly three times the X1S. Power delivery is still my first suspect for the full-core crashes, but I did not prove the cause.
The full handshake and the radio lesson
The partial verdict was not the ending I wanted, but it gave me the next obvious question: was the receiver simply too far away from the client?
Run one, with the Nova across the room: 8 EAPOL frames, five Message 1, three Message 3, zero Message 2. The Marauder heard the loud hotspot fine and missed the quiet client's replies entirely. Message 3 cannot exist unless Message 2 was sent, so the replies were on the air. The ESP32 just could not hear them from where it sat.
For the second run, I moved the Marauder about a foot from the Nova and pointed the antenna toward it. Over 300 seconds it captured 33 EAPOL frames: 26 Message 1, 4 Message 2, and 3 Message 3. The verdict line flipped to "crackable material present (M1+M2)." The model called the repeated re-authentication pattern, identified the single client, and stated the implication correctly: M1+M2 is enough for an offline dictionary attack against the passphrase. The verifier passed every number it covers.
There was still a catch. The model muddled message direction in its prose, which is PROBE's "right observation, wrong conclusion" failure mode showing up in my own run. Moving the receiver recovered the missing client-side frames, but I also changed the capture duration, so this is a successful recovery path rather than a controlled proof that distance was the only cause.
At that point, I still wanted one independent check that the "crackable material" verdict meant what it said. I used hashcat once, but I was not trying to discover my own password because I already knew it. Supplying that passphrase as the only candidate isolated the question I cared about: had the Marauder captured a usable M1+M2 exchange, and had I converted it correctly? Hashcat matched it, so the answer was yes. A dictionary attack would have tested whether my password happened to appear in a word list, which says something about password strength but nothing more about the capture path. No hash or passphrase is published.
The target choice taught me as much as the antenna placement. An earlier run against a Windows hotspot on my daily-driver PC disrupted that PC's own WiFi connection because Windows Mobile Hotspot shares one radio between AP and station roles. A "self-targeted" attack on a hotspot that shares your daily-driver radio is not actually self-contained. My phone's hotspot was the cleaner target because it had its own radio and cellular uplink, with no dependency on the test PC's WiFi. The iPhone also rotates its hotspot BSSID between sessions, which complicates long-term AP tracking and does nothing against a per-session attack. Neither hotspot enforced protected management frames, which is why the deauths landed at all. On a network with 802.11w enforced, this entire section would read differently.
What I would build next
By then, I had the part I originally wanted: the pipeline could move a capture, summarize it, write a report, and check defined claims against the brief. What it still could not do was learn a baseline and decide on its own that a new pattern deserved attention. That is the next layer I would add, using the LLMcap idea as a starting point. The 83-deauth source is a good example of the restraint it would need: the first capture was unusual, but the follow-up produced no evidence of an attack.
There is already another branch of this project waiting for me. The Marauder has a GPS module and a wardrive mode that logs APs with coordinates to the SD card, so I took it on a two-part walk through a busy RF environment. It logged 282 unique access points, FileServe moved the logs to the analysis box, and the 4B model invented frame-level evidence the wardrive format did not contain. That result deserves its own writeup, as do the anomaly layer and a controlled model comparison. For now, this article is the working capture pipeline and the lessons that came from proving it against my own traffic.
Sources and evidence
These are the primary projects and papers that shaped the design. The run-specific measurements come from my own local artifacts and the evidence record described below.
The measurements in this article trace to a private run log with commands, byte counts, false starts, and reasons for each rerun. Raw captures and network identifiers stay local. The release package substitutes a sanitized evidence ledger that maps the published measurements back to those private entries.
Marauder analyst FAQ
Is this legal?
Everything active in this article targeted my own access points and clients in my own lab. Only use active functions on systems you own or are explicitly authorized to test. Unauthorized interference can violate laws, regulations, provider rules, and network policies; the exact boundary depends on where and how the equipment is used.
Why not just use Wireshark?
Wireshark is still where I would go when a finding matters. It is the packet-analysis application that lets you inspect a capture frame by frame, apply filters, and follow network conversations. This pipeline uses tshark, Wireshark's command-line companion, to prepare a compact brief for a local model. It speeds up the first pass; it does not replace checking the packets yourself.
Why not a Flipper Zero?
The serial streaming mechanism actually comes from the Flipper companion ecosystem, and a Flipper can drive the same firmware. The X1S is what a Flipper is not: a real Linux box with 16 GB of RAM that can run a 4B model next to the capture.
Could this run on a Raspberry Pi?
The Python, tshark, and Ollama pieces should run on a Raspberry Pi 5, but I have not tested this pipeline on one. The measured reference points are the N5095 at about 1.3 tokens per second and the RK3588S at about 4, both CPU-only with the same 4B model. Any Pi 5 speed estimate would be a guess until I run the same model and prompt there.
Did you crack your own WiFi password?
I validated the capture once with hashcat, but I was not trying to discover my own password. I supplied the known passphrase as the only candidate so the result tested the captured M1+M2 exchange and conversion path, not the quality of a word list. A dictionary attack would have answered a different question: whether my password was weak enough to appear in that list. No hash or passphrase is published.
Can I build this?
The local release package contains the pipeline scripts, FileServe module and build recipe, verifier, regression tests, and sanitized examples, including one deliberately bad model report that the verifier rejects. The raw capture log stays private because it contains third-party identifiers and lab details. A public repository link will be added only after the package has been reviewed and approved.
Related work
The benchmark series on the same N5095 box that became the analysis side of this pipeline.
The repair that made the Nova's radio reliable enough to play both victim client and wireless capture puller.
Release package
Repository under separate review
The local package contains the pipeline scripts, FileServe firmware module and build recipe, claim verifier, regression tests, sanitized evidence ledger, and both passing and deliberately failing examples. The repository has its own review and release gate, so its public link will be added here once that package is ready.
Get notified when I publish new hardware reviews, benchmarks, and security research. No spam, unsubscribe anytime.
I respect your privacy. Powered by Buttondown.