{"id":368,"date":"2026-07-01T19:31:57","date_gmt":"2026-07-01T19:31:57","guid":{"rendered":"https:\/\/marcinzygmunt.pl\/blog\/?p=368"},"modified":"2026-07-01T19:40:04","modified_gmt":"2026-07-01T19:40:04","slug":"quiet-gadgets-loud-radios","status":"publish","type":"post","link":"https:\/\/marcinzygmunt.pl\/blog\/quiet-gadgets-loud-radios\/","title":{"rendered":"Quiet gadgets, loud radios"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><strong>You just have to listen.<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Your phone and earbuds sit silent in your pocket \u2014 but their radios broadcast you non-stop. I checked how much you can hear in a dozen seconds.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It started as an audit of my own backyard: what do my devices and my network put out into the air before someone else looks? I set the scanner next to my desk \u2014 a dozen seconds later I had a list: my router and its vendor, a phone, earbuds, a smartwatch, a couple of IoT gadgets, each with a label saying how much is really visible about it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That&#8217;s how NodeRecon started. The idea is dead simple: if everything around us chatters in the background over&nbsp;<strong>WiFi and Bluetooth<\/strong>, how much of it actually leaks? Quite a lot \u2014 and you see it in the first few seconds. Which access points are in range and who built them, which Bluetooth devices are hanging around, what they&#8217;re looking for.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">You emit a real trail<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Here&#8217;s the thing: you don&#8217;t have to break anything. Every phone, laptop, watch or router with WiFi or Bluetooth broadcasts information about itself all on its own \u2014 that&#8217;s just how the 802.11 and Bluetooth standards work. What goes out on the air:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>WiFi access points<\/strong>&nbsp;beacon their SSID and a real, manufacturer-assigned MAC ~10 times a second.<\/li>\n\n\n\n<li><strong>WiFi clients<\/strong>&nbsp;send&nbsp;<em>probe requests<\/em>.<\/li>\n\n\n\n<li><strong>BLE devices<\/strong>&nbsp;advertise continuously: a manufacturer ID, sometimes a device type, sometimes a name.<\/li>\n\n\n\n<li><strong>Bluetooth Classic devices<\/strong>&nbsp;(in discoverable mode) answer an inquiry with their type and a real MAC.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">A passive listener turns this ambient noise into a profile of the room \u2014 no connection, no transmission, no trace.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Trustworthiness<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Most &#8220;WiFi sniffer&#8221; demos quietly lie. The classic party trick \u2014&nbsp;<em>&#8220;this phone has been to 3 airports, it knows the SSID&nbsp;<code>Marriott_Lounge<\/code>&#8220;<\/em>&nbsp;\u2014 mostly&nbsp;<strong>stopped working years ago<\/strong>. Modern systems send empty probe requests and&nbsp;<strong>randomize their MAC address<\/strong>&nbsp;(<a href=\"https:\/\/support.apple.com\/guide\/security\/wi-fi-privacy-with-apple-devices-sec31e483abf\/web\">Apple devices, for one, work this way<\/a>). The vendor lookup on a modern phone returns nothing, because the address is fake.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">But a random MAC isn&#8217;t the end of the story. The address changes \u2014 the device doesn&#8217;t. The rates and 802.11 capabilities a device advertises (the so-called Information Elements), its BLE service profile, the little quirks of its stack \u2014 all add up to a&nbsp;<strong>fingerprint that survives address rotation<\/strong>. A bit like a browser fingerprint: the IE set alone groups devices by model and stack, and to tell two identical units apart you add a timing pattern of their transmissions. And this isn&#8217;t theory \u2014 it&#8217;s a&nbsp;<a href=\"https:\/\/ar5iv.labs.arxiv.org\/html\/1703.02874\">documented tracking technique<\/a>&nbsp;that works despite randomization.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">NodeRecon doesn&#8217;t go that far, but it reads pieces of that fingerprint: the vendor from IEs, the device type, BLE service UUIDs. And that&#8217;s already enough to pull&nbsp;<em>what<\/em>&nbsp;a device is and what it&#8217;s for out of an &#8220;anonymous&#8221; address.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So NodeRecon doesn&#8217;t pretend. Every device carries a&nbsp;<strong>confidence label<\/strong>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>HARD<\/strong>&nbsp;\u2014 a real, global MAC with a known vendor. Access points, IoT, Bluetooth Classic devices. Trustworthy.<\/li>\n\n\n\n<li><strong>OPPORTUNISTIC<\/strong>&nbsp;\u2014 a randomized MAC that still leaked something useful (a named network it probed, a BLE name, a manufacturer ID). Hints, not identity.<\/li>\n\n\n\n<li><strong>ANONYMOUS<\/strong>&nbsp;\u2014 a randomized MAC with no leak. We see it; we can&#8217;t tie it to anyone.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">On a live scan you immediately tell the&nbsp;<strong>routers and infrastructure<\/strong>&nbsp;(hard facts: &#8220;MikroTik&#8221;, &#8220;Huawei&#8221;) from the&nbsp;<strong>phones<\/strong>&nbsp;(anonymous, randomized) \u2014 and the in-between, where a device leaked a manufacturer or a network name.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Sounds like little? For a well-behaved phone or laptop \u2014 sure, randomization does its job. But a device in new surroundings still searches and emits. It gets interesting with the&nbsp;<strong>peripherals<\/strong>&nbsp;\u2014 earbuds, fitness bands, IoT, beacons and Bluetooth Classic gear still leak plenty. A single scan is a snapshot; the picture fills in fast when you listen longer, or when even one chatty device is in the room.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I didn&#8217;t reinvent the wheel \u2014&nbsp;<a href=\"https:\/\/www.kismetwireless.net\/\"><strong>Kismet<\/strong><\/a>&nbsp;has collected this data for years, at larger scale and with more fields. What I added is what&#8217;s usually missing: honest confidence labels and a lens that makes this invisible trail tangible. And the room to extend it and orchestrate it with other tools is practically unlimited.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What it actually shows<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Concretely \u2014 what lands on the screen after a scan:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>WiFi:<\/strong>&nbsp;APs and clients, SSID \/ probe history, vendor from the IEEE OUI registry, signal strength, channel-hopped across 2.4 and 5 GHz.<\/li>\n\n\n\n<li><strong>BLE (passive, silent):<\/strong>&nbsp;manufacturer from the Bluetooth SIG Company ID, device&nbsp;<strong>type<\/strong>&nbsp;from the GAP Appearance field (Phone, Earbuds, Smartwatch, Heart-rate sensor\u2026), service UUIDs, RSSI. Flip a switch to&nbsp;<em>active<\/em>&nbsp;scan and you also get device&nbsp;<strong>names<\/strong>&nbsp;\u2014 at the cost of transmitting.<\/li>\n\n\n\n<li><strong>Bluetooth Classic:<\/strong>&nbsp;for discoverable devices, the&nbsp;<strong>type<\/strong>&nbsp;(Class of Device: &#8220;Phone \/ Smartphone&#8221;, &#8220;Audio \/ Headphones&#8221;), the&nbsp;<strong>real vendor<\/strong>&nbsp;(Classic uses a real MAC, so the manufacturer is solid), and the name. My Samsung phone in discoverable mode showed up instantly as&nbsp;<code>HARD \u00b7 Phone \u00b7 Samsung<\/code>.<\/li>\n\n\n\n<li><strong>Anomalies:<\/strong>&nbsp;an unusually strong source that matches no known AP gets flagged \u2014 it may point to a rogue access point, interference, or simply a device right next to you.<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"576\" src=\"https:\/\/marcinzygmunt.pl\/blog\/wp-content\/uploads\/2026\/07\/1VlOBF1rwRvklC8PzIFC7_41359f394f0a4d72b874a3591b0fd2d3-1024x576.png\" alt=\"\" class=\"wp-image-369\" srcset=\"https:\/\/marcinzygmunt.pl\/blog\/wp-content\/uploads\/2026\/07\/1VlOBF1rwRvklC8PzIFC7_41359f394f0a4d72b874a3591b0fd2d3-1024x576.png 1024w, https:\/\/marcinzygmunt.pl\/blog\/wp-content\/uploads\/2026\/07\/1VlOBF1rwRvklC8PzIFC7_41359f394f0a4d72b874a3591b0fd2d3-300x169.png 300w, https:\/\/marcinzygmunt.pl\/blog\/wp-content\/uploads\/2026\/07\/1VlOBF1rwRvklC8PzIFC7_41359f394f0a4d72b874a3591b0fd2d3-768x432.png 768w, https:\/\/marcinzygmunt.pl\/blog\/wp-content\/uploads\/2026\/07\/1VlOBF1rwRvklC8PzIFC7_41359f394f0a4d72b874a3591b0fd2d3-1536x864.png 1536w, https:\/\/marcinzygmunt.pl\/blog\/wp-content\/uploads\/2026\/07\/1VlOBF1rwRvklC8PzIFC7_41359f394f0a4d72b874a3591b0fd2d3-2048x1152.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><em>A shot from a real scan. SSIDs and device names are deliberately blurred \u2014 because that&#8217;s exactly the point of this piece: such a name can lead straight to your door (one lookup on&nbsp;<a href=\"https:\/\/wigle.net\/\">WiGLE<\/a>&nbsp;and you have the coordinates).<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Under the hood<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Hardware:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Raspberry Pi 4 \u2014 the whole thing fits in a backpack.<\/li>\n\n\n\n<li>A WiFi card in&nbsp;<strong>monitor<\/strong>&nbsp;mode \u2014 listens to 802.11 frames while channel-hopping.<\/li>\n\n\n\n<li>The Pi&#8217;s built-in Bluetooth in&nbsp;<strong>BLE<\/strong>&nbsp;mode \u2014 passive advertisement listening.<\/li>\n\n\n\n<li>A power bank or PSU \u2014 power in the field.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">That small footprint isn&#8217;t a gimmick. The whole thing fits in a backpack \u2014 but it can just as well&nbsp;<strong>stay behind as a drop device<\/strong>: NodeRecon has a headless mode that quietly records a session to an encrypted file, no dashboard, no transmitting. (Only on your own turf or in an authorized test, of course \u2014 more on that below.)<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"572\" src=\"https:\/\/marcinzygmunt.pl\/blog\/wp-content\/uploads\/2026\/07\/5fqkqWJZkk2z1NyVlSqB2_kJ7xfQiD-1024x572.png\" alt=\"\" class=\"wp-image-370\" srcset=\"https:\/\/marcinzygmunt.pl\/blog\/wp-content\/uploads\/2026\/07\/5fqkqWJZkk2z1NyVlSqB2_kJ7xfQiD-1024x572.png 1024w, https:\/\/marcinzygmunt.pl\/blog\/wp-content\/uploads\/2026\/07\/5fqkqWJZkk2z1NyVlSqB2_kJ7xfQiD-300x167.png 300w, https:\/\/marcinzygmunt.pl\/blog\/wp-content\/uploads\/2026\/07\/5fqkqWJZkk2z1NyVlSqB2_kJ7xfQiD-768x429.png 768w, https:\/\/marcinzygmunt.pl\/blog\/wp-content\/uploads\/2026\/07\/5fqkqWJZkk2z1NyVlSqB2_kJ7xfQiD.png 1376w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><em>The whole rig: a phone with the dashboard, a Raspberry Pi in an aluminium case, an Alfa card with an antenna, and a power bank.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Software:<\/strong>&nbsp;one self-contained app in&nbsp;<strong>Java<\/strong>. I grab WiFi through libpcap in monitor mode, and Bluetooth through a raw HCI socket driven straight from Java with the new&nbsp;<strong>Foreign Function &amp; Memory API<\/strong>&nbsp;(Panama) \u2014 passive LE scanning plus BR\/EDR inquiry, without a single line of native glue code. Sessions land in an&nbsp;<strong>AES-256 encrypted<\/strong>&nbsp;SQLite file, and you get a Markdown report at the end.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I put the whole thing together in a single day \u2014 a Raspberry Pi, a few libraries, publicly available knowledge. And the near-unlimited room to extend it is proof of how low the bar now sits to hear what your surroundings broadcast.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Does passive OSINT end at listening?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Recon is only the first half. Although NodeRecon stays&nbsp;<strong>passive by design<\/strong>, the same trail it collects is fuel for offensive tools \u2014 one leaked open-network name a phone keeps calling for is enough to stand up an&nbsp;<strong>evil twin<\/strong>&nbsp;it may join on its own.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So maybe somewhere there&#8217;s already a&nbsp;<strong>NodeTwin<\/strong>&nbsp;\u2014 the same node, except this time it&#8217;s the one transmitting: luring, spoofing, standing up a twin. But that&#8217;s a topic for another post \ud83d\ude09.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Watch what you emit<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">This post is really about awareness. Today, with modern tooling, a passive device like this comes together in a single day from off-the-shelf parts \u2014 and your devices are audible to anyone who cares to listen. For an ordinary user, that&#8217;s a reminder to turn the radios off when you don&#8217;t need them. For a pentester, it means the RF layer is shadow-IT that a physical audit usually never checks: a map of the hardware, rogue APs and leaked names, in a minute and without a single transmitted packet.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><em>Keep in mind:&nbsp;<strong>passive listening<\/strong>&nbsp;to broadcast frames isn&#8217;t forbidden, but MAC addresses and device names can be&nbsp;<strong>personal data<\/strong>&nbsp;\u2014 collecting and profiling other people&#8217;s gear without a legal basis (GDPR) is another matter entirely.&nbsp;<strong>Active operation<\/strong>&nbsp;\u2014 transmitting, spoofing a network (evil twin), capturing credentials or communication content \u2014 sits on completely different legal footing, and without consent it can be a crime.<\/em><\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\"><em>NodeRecon is a private tool \u2014 but plenty of others, freely available online, do the same thing.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>You just have to listen. Your phone and earbuds sit silent in your pocket \u2014 but their radios broadcast you non-stop. I checked how much you can hear\u2026<\/p>\n","protected":false},"author":1,"featured_media":371,"comment_status":"open","ping_status":"open","sticky":true,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[1],"tags":[99,97,15,101,102,98,100],"class_list":["post-368","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-bluetooth","tag-infosec","tag-java","tag-pentest","tag-raspberrypi","tag-rf","tag-wifi"],"jetpack_likes_enabled":true,"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"https:\/\/marcinzygmunt.pl\/blog\/wp-content\/uploads\/2026\/07\/CgGJAFzaY5HRYe1PM6wUU_w6L8hzGA.png","_links":{"self":[{"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/posts\/368","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/comments?post=368"}],"version-history":[{"count":2,"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/posts\/368\/revisions"}],"predecessor-version":[{"id":373,"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/posts\/368\/revisions\/373"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/media\/371"}],"wp:attachment":[{"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/media?parent=368"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/categories?post=368"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/tags?post=368"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}