[{"content":"I keep my Kali Linux machine tucked away on its own little subnet, wired into a second router that itself hangs off the main house network. That isolation is on purpose: the lab stays separate from the phones, TVs and everyone else\u0026rsquo;s traffic. But it raises an obvious question:\nIf the Kali box is behind its own router, can I still reach it from my MacBook on the main Wi-Fi, SSH straight in, and from there launch a Hack The Box session without ever touching the machine physically?\nShort answer: yes. This post is the walk-through, including the one networking gotcha that trips everyone up the first time: double NAT.\nScope / ethics: everything here is my own hardware, my own home network, and my own Hack The Box subscription. SSH and HTB are being used exactly as intended, remote admin of a machine I own, and authorized practice on a platform built for it.\nThe setup Here\u0026rsquo;s the layout. Two routers, two subnets, one goal:\n┌──────────────────────────┐ MacBook Air (Wi-Fi) │ Main router │ 192.168.0.227 ───── Wi-Fi ───┤ 192.168.0.1 │ │ Network: 192.168.0.0/24 │ └──────────┬───────────────┘ │ (cable, WAN side) ┌──────────┴───────────────┐ │ Router 2 │ │ WAN: 192.168.0.138 │ ← its IP on the main net │ LAN: 192.168.1.1 │ ← its own subnet │ Network: 192.168.1.0/24 │ └──────────┬───────────────┘ │ (cable) Kali Linux PC 192.168.1.144 (user: cabuya) The Mac (192.168.0.0/24) and the Kali box (192.168.1.0/24) are on different subnets, separated by Router 2 doing its own NAT. The Mac can\u0026rsquo;t just \u0026ldquo;see\u0026rdquo; the Kali box, from the main network\u0026rsquo;s point of view, Router 2 is a single device and everything behind it is hidden.\nPart 1 — Turn on SSH on the Kali box Kali ships with an OpenSSH server that\u0026rsquo;s off by default. Enable and start it:\nsudo systemctl enable --now ssh sudo systemctl status ssh # should say \u0026#34;active (running)\u0026#34; Quick local sanity check (from the Kali box itself):\nss -tlnp | grep :22 # confirms sshd is listening on port 22 On my box that returned:\nLISTEN 0 128 0.0.0.0:22 0.0.0.0:* 0.0.0.0:22 means sshd is listening on every interface (including eth0, 192.168.1.144), exactly what the port forward needs to hand off to.\nPart 2 — The double-NAT problem, explained Normally, to reach a device on your LAN you just use its IP. But the Kali box isn\u0026rsquo;t on the Mac\u0026rsquo;s LAN, it\u0026rsquo;s one NAT layer deeper. From the main network, traffic can reach Router 2\u0026rsquo;s WAN IP (192.168.0.138), but Router 2 won\u0026rsquo;t forward anything inward unless we tell it to. That\u0026rsquo;s exactly what port forwarding is for.\nThe plan:\nPin the Kali box\u0026rsquo;s IP so it never changes (DHCP reservation). On Router 2, forward an external port to the Kali box\u0026rsquo;s port 22. From the Mac, SSH to Router 2\u0026rsquo;s WAN IP on that external port. I chose port forwarding over the alternatives (putting Router 2 in bridge mode, or using an overlay like Tailscale) precisely because I want to keep the subnet isolation, that\u0026rsquo;s the whole reason the lab is back there.\nPart 3 — Pin the IPs so nothing breaks later Port forwarding points at a specific IP, so if that IP changes on a reboot, the rule silently breaks. Two one-time fixes:\nKali\u0026rsquo;s LAN IP → add a DHCP reservation on Router 2 for the Kali box\u0026rsquo;s MAC (d8:5e:d3:91:d2:22), so it always gets 192.168.1.144. Router 2\u0026rsquo;s WAN IP → add a DHCP reservation on the main router for Router 2\u0026rsquo;s WAN MAC, so the address I SSH to stays put. (Optional, but saves surprises.) Do this once and the whole thing becomes set-and-forget.\nPart 4 — Forward the port on Router 2 In Router 2\u0026rsquo;s admin page, under Port Forwarding (sometimes \u0026ldquo;Virtual Server\u0026rdquo; / \u0026ldquo;NAT\u0026rdquo;):\nField Value External / WAN port 2222 Internal IP 192.168.1.144 Internal port 22 Protocol TCP Using a non-default external port like 2222 is a small good habit, fewer collisions, slightly less noise. Save and (if the router asks) reboot it.\nOn the E2500 specifically this lives under Applications \u0026amp; Gaming → Single Port Forwarding, not \u0026ldquo;Port Range Forwarding\u0026rdquo;, which would force the external and internal ports to match and defeat the 2222 → 22 remap.\nPart 5 — SSH in from the Mac Moment of truth, from the MacBook on the main Wi-Fi:\nssh -p 2222 cabuya@192.168.0.138 First connection will ask to trust the host key (yes), then the password. If you plan to do this often, drop in a key and a shortcut:\n# one-time: copy your public key so no more passwords ssh-copy-id -p 2222 cabuya@192.168.0.138 # ~/.ssh/config — then you can just run: ssh kali Host kali HostName 192.168.0.138 Port 2222 User cabuya There it is: hostname says kali, whoami says cabuya, and eth0 sits at 192.168.1.144 — a machine on the 192.168.1.0/24 subnet, reached from a Mac on 192.168.0.0/24, straight through the double NAT.\nPart 6 — Into Hack The Box, from the terminal Now I\u0026rsquo;m on the Kali box, driving it entirely over SSH. Connecting to HTB is a normal outbound connection, so the double-NAT setup doesn\u0026rsquo;t get in the way at all, the port forward only governs traffic coming in to the Kali box, not what it dials out.\nThis is HTB Labs, which you reach over OpenVPN. Grab your connection pack (the .ovpn file) from the HTB site, get it onto the Kali box, and bring the tunnel up, all from the same SSH session:\n# from the SSH session on Kali: sudo openvpn starting_point_cabuya_VIP.ovpn # brings up the tun interface Here\u0026rsquo;s the whole thing in motion — I\u0026rsquo;m on the Mac, SSH\u0026rsquo;d into the Kali box, watching OpenVPN negotiate and finish with Initialization Sequence Completed:\nThen confirm the interface and reach a target:\nip addr show tun0 # confirm the VPN interface is up ping 10.129.95.232 # a live HTB machine — reachable through the tunnel The tun0 interface pulled 10.10.14.86/23, a 10.10.x.x address of a HTB Labs VPN. That\u0026rsquo;s the proof the whole chain works: I\u0026rsquo;m typing into a Kali box on its own subnet, over SSH, from a Mac on a different subnet, and that Kali box is simultaneously live on the HTB network, pinging a target at 10.129.95.232.\nA nice touch: run the VPN inside tmux so it survives if the SSH session drops.\nTroubleshooting notes SSH just hangs / times out → the forward isn\u0026rsquo;t reaching Kali. Recheck the internal IP in the rule vs. Kali\u0026rsquo;s actual IP; confirm sshd is running. \u0026ldquo;Connection refused\u0026rdquo; → you reached Router 2 but nothing is listening; wrong internal port or sshd down. Works once, breaks after a reboot → an IP drifted; that\u0026rsquo;s what the DHCP reservations in Part 3 prevent. Takeaways Double NAT isn\u0026rsquo;t a wall, it\u0026rsquo;s just a layer you have to explicitly poke a hole through. One forwarded port + two DHCP reservations = permanent, low-maintenance remote access, with the lab subnet still isolated. Once you\u0026rsquo;re in over SSH, the machine is fully yours from anywhere in the house -HTB and all-, no monitor, no keyboard, no walking over to it. Setup: MacBook Air (main Wi-Fi) · Kali Linux (wired, behind Router 2) · OpenSSH · OpenVPN · Hack The Box All on my own network and my own HTB subscription.\n","permalink":"https://cabuyal.github.io/blog/posts/ssh-into-kali-for-htb/","summary":"\u003cp\u003eI keep my \u003cstrong\u003eKali Linux\u003c/strong\u003e machine tucked away on its own little subnet, wired into a\n\u003cstrong\u003esecond router\u003c/strong\u003e that itself hangs off the main house network. That isolation is on\npurpose: the lab stays separate from the phones, TVs and everyone else\u0026rsquo;s traffic. But it\nraises an obvious question:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eIf the Kali box is behind its own router, can I still reach it from my MacBook on the\nmain Wi-Fi, SSH straight in, and from there launch a \u003cstrong\u003eHack The Box\u003c/strong\u003e session without\never touching the machine physically?\u003c/p\u003e","title":"Reaching My Kali Box Through a Second Router: SSH Across Double NAT, Then Into Hack The Box"},{"content":"I bought a new toy: a LilyGO T-Embed CC1101 Plus. It\u0026rsquo;s a pocket-sized, battery-powered multi-radio tool in a clear case, with a little scroll wheel and three antennas. Think of it as a Swiss Army knife for the airwaves: sub-GHz radio, Wi-Fi, Bluetooth and NFC/RFID in one device you can drive with your thumb.\nI didn\u0026rsquo;t buy it just to collect gadgets. Three capabilities sold me on it:\nWi-Fi testing — I wanted a hands-on way to learn how Wi-Fi attacks actually work. Bluetooth testing — same reason, next radio down. Sub-GHz signal copying — and this one is genuinely useful to me, not just a lab exercise. Let me explain that last one, because it\u0026rsquo;s the reason I reached for my wallet.\nWhy signal copying is actually useful to me At my parents\u0026rsquo; house I have a remote for the garage. Fine. But they also own a property up in the mountains, behind a community gate that sits before their own gate, and I don\u0026rsquo;t have a remote for the community one. They go up often, and whenever I want to join them after they\u0026rsquo;ve already arrived, someone has to walk a long way down just to let me in, sometimes even at night. Being able to copy that remote and carry a clone would save everyone the hike.\nSame story at my wife\u0026rsquo;s grandmother\u0026rsquo;s place: sometimes there\u0026rsquo;s no cell signal out there, so \u0026ldquo;text us and we\u0026rsquo;ll open the gate\u0026rdquo; simply doesn\u0026rsquo;t work once you\u0026rsquo;re standing at it. A clone in my pocket solves a real, boring, everyday problem.\nOn permission: every signal I copy is one I have permission to copy. Cloning a remote for a gate you\u0026rsquo;re authorized to use is convenience; doing it to one you\u0026rsquo;re not is theft, plain and simple. This whole post is me testing on my own gear and my own family\u0026rsquo;s access, with consent. Do the same.\nWith that out of the way, here\u0026rsquo;s how the first round of testing went across three of the radios.\nTest 1 — Sub-GHz RF (the CC1101) The star of the show is the CC1101 sub-GHz transceiver. Most garage and gate remotes live down in the 300–928 MHz band, and the T-Embed can scan those ranges, capture a signal, and replay it.\nFor my first test I used the remote for my parents\u0026rsquo; garage. You drop into Scan/Copy, pick a frequency range (in my experience, it\u0026rsquo;s best to use a fixed frequency), and hold the remote near the device while pressing its button. The T-Embed listens for a signal to lock onto and record.\nThe honest result: this is where you learn that not all remotes are equal.\nFixed-code remotes — common on simpler community and property gates — send the same code every time. Capture once, replay forever. These are the ones a tool like this can genuinely clone. Rolling-code remotes — most modern garage openers change the code on every press. You can record a transmission, but replaying it won\u0026rsquo;t work, because the receiver has already moved on. That\u0026rsquo;s the whole point of rolling codes, and it\u0026rsquo;s a good thing. Luckily, both controllers tested seem to be old tech, exactly the kind of fixed-code system this shines on.\nTest 2 — RFID / NFC Next radio: the 13.56 MHz RFID/NFC reader, which the T-Embed calls Tag-O-Matic. I threw two very different cards at it.\nA hotel key card. The reader identified the card type and then hit a wall:\n\u0026ldquo;Failed reading data blocks.\u0026rdquo; That\u0026rsquo;s not a bug, it\u0026rsquo;s the card\u0026rsquo;s security doing its job. The data sectors are protected with keys the reader doesn\u0026rsquo;t have, so it can see the card exists but can\u0026rsquo;t pull the contents. Exactly what you\u0026rsquo;d want from a card that unlocks a room.\nA blank NFC tag. Completely different story:\nAn unprotected tag reads instantly, blocks and all. Next on my list is testing whether the T-Embed can write to one of these, though I\u0026rsquo;ll admit I don\u0026rsquo;t yet have a use for that. Sometimes you learn the capability first and find the reason later.\nThe takeaway: the reader isn\u0026rsquo;t magic. A well-secured card stays secured; an open tag is an open book.\nTest 3 — Wi-Fi handshake capture (my favorite) This is the one I was most excited about. I dug out an old Cisco/Linksys E1200 router, set it up as a throwaway Wi-Fi network, and used it as a target I fully own.\nI created a network called wifiTest with WPA2, purely to practice the capture-and-crack workflow end to end.\nA quick word on the deauth process To crack a WPA/WPA2 password offline you first need to capture the 4-way handshake, the short exchange (EAPOL messages) a device and the router perform when the device joins the network. The problem: that only happens at connection time, and you can\u0026rsquo;t just wait around forever.\nEnter the deauthentication (\u0026ldquo;deauth\u0026rdquo;) attack. In WPA2, the management frames that tell a client \u0026ldquo;you\u0026rsquo;ve been disconnected\u0026rdquo; are not authenticated, anyone can forge them. So the attacker sends spoofed deauth frames that look like they came from the router, kicking a connected device off the network. The device, being helpful, immediately tries to reconnect, and that\u0026rsquo;s when it performs the handshake again, right in front of your capturing radio.\nIn short: deauth to force a reconnect → capture the handshake → crack it offline. You never need to be connected to the network, and the cracking happens later on a laptop, not on the device.\nModern defenses exist: WPA3 and 802.11w (Protected Management Frames) authenticate those management frames, which shuts this technique down. My little E1200 has neither, which is exactly why it made a good teaching target.\nCapturing the handshake The T-Embed has a dedicated handshake-capture mode. Point it at the network, fire off some deauth frames, and wait for a client to reconnect:\nHANDSHAKE CAPTURE SSID: wifiTest BSSID: 58:6D:8F:C0:5A:3A Security: WPA2/PSK Status: CAPTURED! EAPOL MSG 1: Captured EAPOL MSG 2: Captured EAPOL MSG 3: Captured EAPOL MSG 4: Captured Deauth sent: 20 All four EAPOL messages, a complete handshake, saved to a .pcap file. That\u0026rsquo;s the hard part done.\nCracking it From here it\u0026rsquo;s a standard offline job. I moved the capture to my Kali machine and ran it through aircrack-ng against the classic rockyou.txt wordlist:\nAircrack-ng 1.7 [00:00:00] 72/10303726 keys tested (2222.76 k/s) KEY FOUND! [ password ] KEY FOUND! [ password ] — cracked in well under a second, because I\u0026rsquo;d deliberately set the password to password. That\u0026rsquo;s the point being made: the capture works regardless, and after that your only defense is a password that isn\u0026rsquo;t in a wordlist. A weak password falls instantly; a long, random one turns \u0026ldquo;offline crack\u0026rdquo; into \u0026ldquo;offline wait a few million years.\u0026rdquo;\nWhat\u0026rsquo;s next The three radios were only the beginning. The thing that keeps pulling me back to the T-Embed is that it\u0026rsquo;s programmable, it\u0026rsquo;s not a fixed-function appliance, it\u0026rsquo;s a platform you can build on.\nSo there\u0026rsquo;s a project brewing. I want to add a GPS antenna and write a listening mode that watches the probe requests from devices nearby, the little \u0026ldquo;is my network here?\u0026rdquo; calls phones broadcast, and analyzes which known networks they\u0026rsquo;re looking for. Wardriving, but for the devices instead of the access points.\nMore on that in a future post. For now: one gadget, three radios, and a much better feel for how the invisible traffic around us actually works.\nHardware: LilyGO T-Embed CC1101 Plus · Linksys E1200 (test AP) · Kali Linux · aircrack-ng All testing performed on my own equipment and access, with permission.\n","permalink":"https://cabuyal.github.io/blog/posts/t-embed-cc1101/","summary":"\u003cp\u003eI bought a new toy: a \u003cstrong\u003eLilyGO T-Embed CC1101 Plus\u003c/strong\u003e. It\u0026rsquo;s a pocket-sized, battery-powered\nmulti-radio tool in a clear case, with a little scroll wheel and three antennas. Think of it as a\nSwiss Army knife for the airwaves: sub-GHz radio, Wi-Fi, Bluetooth and NFC/RFID in one device you\ncan drive with your thumb.\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"The T-Embed and the pile of things I tested it against\" loading=\"lazy\" src=\"/blog/posts/t-embed-cc1101/images/gear-desk.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003eI didn\u0026rsquo;t buy it just to collect gadgets. Three capabilities sold me on it:\u003c/p\u003e","title":"One Gadget, Three Radios: First Tests With the T-Embed CC1101 Plus"},{"content":"Last year I attended PWNED 0x08, a cybersecurity conference here in Costa Rica, and signed up for the workshop \u0026ldquo;RF Exploration: Introduction to Sniffing with ESP32/ESP8266.\u0026rdquo; The goal was simple and very fun: build a pocket-sized wardriver, a device that listens for Wi-Fi networks around you, tags each one with a GPS position, logs everything to an SD card and shows its status on a small screen.\nI walked out of that workshop with a bag of parts and a project I hadn\u0026rsquo;t finished.\nThis post covers how I picked it back up almost a year later, what broke along the way, and the feature I wanted to add to the original project.\nThe hardware The build is intentionally cheap and simple:\nPart Role Wemos/Lolin D1 Mini (ESP8266) The brain. Puts the Wi-Fi radio in promiscuous mode to sniff 802.11 management frames GPS module (GY-GPS6MV2 / NEO-6M) Supplies latitude, longitude, altitude and time for every capture Micro SD shield for the D1 Mini Stores the CSV logs SSD1306 OLED, 128×64, I2C Live status: GPS, network count, SD state The workshop code lives in the PWNEDCRx08 repository, and builds on ESPProLib for the promiscuous-mode sniffing.\nWhy it didn\u0026rsquo;t get finished at the conference My laptop gave me trouble during the workshop. I had prepared everything the day before; everything I needed to work on the project was installed, and everything was up to date. But as soon as we sat down and the workshop began, the only IDE that would open was the \u0026lsquo;default\u0026rsquo; version -the old one that came with the operating system and had no plugins available-. All the necessary plugins had been installed on the newer version. No one was able to get it to open the correct one. I spent the entire session troubleshooting, so I never flashed the board. While everyone else was watching their screens fill up with networks, I was still fighting with my setup. I took the parts home, and they ended up sitting in a box for most of a year.\nPicking it back up, with an AI pair With PWNED coming up again this year -and partly because I bought a T-Embed CC1101 Plus to experiment with (more on this in an upcoming post)-, I got excited and decided to pick up the wardriving project again. When I came back to it, I did two things differently.\n1. I ditched the Arduino IDE for VS Code + PlatformIO. The repo\u0026rsquo;s README is written for the Arduino IDE, but I wanted builds inside my editor. PlatformIO also makes the build reproducible, because the board, framework, serial speed and library versions all go in one platformio.ini:\n[platformio] src_dir = ESP2866 [env:d1_mini] platform = espressif8266 board = d1_mini framework = arduino monitor_speed = 115200 lib_deps = mikalhart/TinyGPSPlus paulstoffregen/Time adafruit/Adafruit SSD1306 adafruit/Adafruit GFX Library adafruit/Adafruit BusIO 2. I worked through it with an AI coding assistant (Claude Code, running in my terminal next to VS Code). I stayed in charge of the hardware, the wiring, the testing and every decision. The assistant was a fast pair partner. It read the code, explained what it was doing, and helped me debug step by step.\nVS Code on the left, the original workshop repo below it, and the AI session on the right.\nFirst bug: code that no longer compiled The first build failed right away with this error:\n#if (SSD1306_LCDHEIGHT != 64) #error(\u0026#34;Incorrect screen height, fix Adafruit_SSD1306.h\u0026#34;); #endif That guard was left over from an old Adafruit SSD1306 library. Current versions only define SSD1306_LCDHEIGHT if you opt into a legacy macro, which the sketch never did. The sketch already used the modern constructor that takes the width and height directly (Adafruit_SSD1306 display(128, 64, \u0026amp;Wire, -1)). The macro was always undefined, so the error always fired. I removed the dead check and the build passed.\nLesson: workshop code is a snapshot in time. Libraries move on, and a year is plenty of time for something to break.\nTroubleshooting: a dark screen and silent satellites The first assembly: everything plugged in, but the OLED stayed dark.\nThe OLED showed nothing The board flashed and the serial monitor showed the sketch running. The screen stayed black.\nInstead of guessing, I added a temporary I2C scanner to setup(). It checks every address on the bus and prints what answers. The result was always the same: \u0026ldquo;No I2C devices found.\u0026rdquo;\nThat result ruled out a large group of causes. The problem wasn\u0026rsquo;t the display library, the address (0x3C) or the code. If nothing answers on the bus at all, the problem is physical. I also had a theory that the stacked SD shield might not expose D1/D2 (the I2C pins) properly.\nSo I took the wiring apart and rewired everything from scratch. The next scan printed I2C device found at 0x3C, and the boot logo appeared. The cause was a bad or missing connection somewhere in the original wiring. I removed the debug scanner and reflashed the clean sketch.\nLesson: when a bus scan finds nothing, check the wiring before you touch the code.\nThe GPS wouldn\u0026rsquo;t get a fix By design, the sketch waits in setup() until the GPS reports a valid location before it starts logging. On my first outdoor test, the satellite count stayed at 0 for several minutes.\nA cold front was passing over Costa Rica those days, with heavy clouds and storms. A GPS module doing a cold start (no saved satellite data) is very sensitive to a weak sky view. Since the GPS wiring had already been redone once, I didn\u0026rsquo;t want to start taking things apart again without a reason. I waited for better weather.\nA few days later, under a clearer sky, the module found its satellites and the wardriver started logging. My first real walk captured 5,821 packets across 94 GPS points.\nAfter the rewire: the OLED shows GPS, Wi-Fi and SD status. (short video)\nLesson: not every failure is a bug. Before you start changing things, rule out the environment: sky view, weather, cold start and time to first fix.\nThe feature I wanted: security type per access point With everything working, I looked at my first logs and realized something important was missing. The wardriver recorded what networks existed and where, but not how they were protected. For a security-focused tool, that\u0026rsquo;s the most interesting column.\nThe original code had a getEncryption() function, but it was dead code. It called WiFi.encryptionType(), which only works with the ESP8266\u0026rsquo;s active scan API. This sketch sniffs passively in promiscuous mode, so that call could never return anything useful.\nSo I built the feature properly by parsing the raw 802.11 frames. Every Beacon and Probe Response an access point sends includes the information needed to classify it:\nCapability Information → Privacy bit (0x0010). If it isn\u0026rsquo;t set, the network is Open. RSN Information Element (tag 48). If present, the network is WPA2 or WPA3. Walking its AKM suite list tells them apart: AKM 1, 2, 5, 6 (802.1X / PSK) → WPA2 AKM 8, 9, 24 (SAE / FT-SAE / SAE-EXT) → WPA3 Both → WPA2/WPA3 transition mode Vendor-specific IE (tag 221) with OUI 00:50:F2, type 1 → legacy WPA. String getSecurityType(esppl_frame_info *info) { bool privacy = info-\u0026gt;capability_info \u0026amp; 0x0010; if (!privacy) return \u0026#34;Open\u0026#34;; if (info-\u0026gt;has_rsn) { String s; if (info-\u0026gt;has_wpa3_akm) { s = info-\u0026gt;has_wpa2_akm ? \u0026#34;WPA2/WPA3\u0026#34; : \u0026#34;WPA3\u0026#34;; } else { s = \u0026#34;WPA2\u0026#34;; } if (info-\u0026gt;has_wpa_vendor) s = \u0026#34;WPA/\u0026#34; + s; return s; } if (info-\u0026gt;has_wpa_vendor) return \u0026#34;WPA\u0026#34;; return \u0026#34;Encrypted(?)\u0026#34;; } A new Security column was added to the CSV log.\nThe hardware limit I hit (and why Encrypted(?) exists) Here\u0026rsquo;s the most interesting part technically. The ESP8266 SDK\u0026rsquo;s promiscuous callback only gives you the first 112 bytes of a management frame body, however long the real frame is. The original tag-parsing loop was bounded by a length value that reflected the SDK\u0026rsquo;s struct size, not the real data. Parsing further meant reading unrelated memory and treating it as fake tags. I fixed the loop so it stops at the 112-byte window.\nSome access points send long beacons, with long SSIDs and many rate and vendor tags. In those, the RSN tag falls after the cutoff. The privacy bit says \u0026ldquo;encrypted,\u0026rdquo; but the details aren\u0026rsquo;t visible.\nI had to decide how to label those. The tempting answer is \u0026ldquo;WEP,\u0026rdquo; because privacy is on and no WPA/RSN tag is visible. In 2026 that would almost always be wrong. A truncated WPA2 beacon is far more likely than a real WEP network. So the firmware labels those networks Encrypted(?). It reports what it actually knows and doesn\u0026rsquo;t guess.\nLesson: a tool that labels uncertain results honestly is more useful than one that fills gaps with plausible guesses.\nFrom CSV to a readable report Raw CSV logs are hard to read. I added a post-processing step that turns each walk into a landscape PDF report: one row per access point, with SSID, security type, BSSID, channel, packet count, best and average RSSI, first and last time seen, and location.\nDetecting meshes and multi-SSID radios A single physical router often broadcasts several networks: main, guest, hidden, a setup SSID. Mesh systems add more. Listing each of those separately would inflate the numbers and make the report confusing.\nThis was harder than expected because the sniffer\u0026rsquo;s CSV drops leading zeros in MAC address bytes. BSSIDs from the same radio can end up with different string lengths, so a simple comparison doesn\u0026rsquo;t work. The merge rule that proved reliable was:\nSame channel + BSSID hex suffix match of at least 6 characters → same physical radio.\nWith this rule, the main network, guest network and hidden variants of one router merge into one row. Separate mesh nodes (for example a 3-node mesh system) stay as separate rows, because they are separate radios in separate locations. That\u0026rsquo;s what you want on a map.\nWhat a walk looks like On the second field walk, with the security feature running, the report found about 60 physical access points:\nMost of them (~¾) used WPA2 A handful were Encrypted(?) (truncated beacons, see above) 2 WPA3, 2 legacy WPA, 1 WPA2/WPA3 transition 1 completely Open network WPA3 adoption in a real residential area is still tiny, and legacy WPA is still around. That alone made the feature worth building.\nA note on ethics and privacy: I only captured passive broadcast frames (beacons and probe responses) that access points send to everyone. I never connected to, attacked or tried to authenticate against any network. The raw logs contain real coordinates and neighbors\u0026rsquo; network names, so they stay offline. They\u0026rsquo;re excluded from the repo, and no SSIDs, MACs or locations appear in this post. If you build one, check your local laws and treat the data carefully.\nTakeaways Unfinished projects aren\u0026rsquo;t failures. They\u0026rsquo;re paused. A year later, with better tools and more patience, it came together. Isolate the layer before you debug. The I2C scanner separated a wiring fault from a code fault in one step. Rule out the environment. My \u0026ldquo;broken\u0026rdquo; GPS was a cold start under storm clouds. AI helps most when you stay in the loop. I held the multimeter, did the rewiring, walked the neighborhood and made the design calls (like refusing to guess \u0026ldquo;WEP\u0026rdquo;). The assistant sped up reading, explaining and writing code. Build the feature you actually want. The most useful part of this device is now the part that wasn\u0026rsquo;t -or maybe just wasn\u0026rsquo;t working-, in the original repo. Thanks to the PWNED 0x08 organizers and the workshop instructor for the project that started all of this. See you at the next one, hopefully with a working laptop this time.\nHardware: Wemos D1 Mini · NEO-6M GPS · SSD1306 OLED · Micro SD shield Tooling: VS Code · PlatformIO · Claude Code\n","permalink":"https://cabuyal.github.io/blog/posts/pwned-wardriver/","summary":"\u003cp\u003eLast year I attended \u003cstrong\u003ePWNED 0x08\u003c/strong\u003e, a cybersecurity conference here in Costa Rica, and signed up for\nthe workshop \u003cem\u003e\u0026ldquo;RF Exploration: Introduction to Sniffing with ESP32/ESP8266.\u0026rdquo;\u003c/em\u003e The goal was simple and\nvery fun: build a pocket-sized \u003cstrong\u003ewardriver\u003c/strong\u003e, a device that listens for Wi-Fi networks around you,\ntags each one with a GPS position, logs everything to an SD card and shows its status on a small\nscreen.\u003c/p\u003e\n\u003cp\u003eI walked out of that workshop with a bag of parts and a project I hadn\u0026rsquo;t finished.\u003c/p\u003e","title":"Finishing What I Started: Building an ESP8266 Wardriver a Year After PWNED 0x08"},{"content":"I\u0026rsquo;m Bernardo, based in Costa Rica. I\u0026rsquo;m into technology and cybersecurity.\nThis blog is where I document my process, including what broke along the way.\nYou can contact me through LinkedIn: linkedin.com/in/bernardoalfaro\n","permalink":"https://cabuyal.github.io/blog/about/","summary":"\u003cp\u003eI\u0026rsquo;m Bernardo, based in Costa Rica. I\u0026rsquo;m into technology and cybersecurity.\u003c/p\u003e\n\u003cp\u003eThis blog is where I document my process, including what broke along the way.\u003c/p\u003e\n\u003cp\u003eYou can contact me through LinkedIn: linkedin.com/in/bernardoalfaro\u003c/p\u003e","title":"About"}]