IP-KVM Hardware on a Corporate Laptop and on Its Network Segment

WindowsmacOSNetwork

TTP Hunt high DPRK IT Worker FraudFamous ChollimaLaptop Farm

USB and PnP telemetry for the KVM-over-IP and video-capture hardware DPRK operators attach to employer-issued laptops, paired with the network view of the same devices: Raspberry Pi hardware addresses, the default TinyPilot host name and internet-exposed KVM interfaces.

What this hunt looks for

A KVM-over-IP device gives an overseas operator console control of a laptop below the operating system, with nothing for an EDR agent to inspect. Huntress recovered a PiKVM V4 Mini and a Guermok USB capture card, registered as a webcam, on a laptop within hours of its reaching a residential address; ReliaQuest documents the equivalent TinyPilot artifacts.

The hardware still enrols: Windows writes a key under HKLM\SYSTEM\CurrentControlSet\Enum\USB and raises Security event 6416, while macOS lists it in system_profiler and leaves a ColorSync display profile behind. A capture card proves nothing alone; its co-occurrence with an IP-KVM on one host is the pattern both vendors call out.

The network view covers what the agent never sees: Raspberry Pi address prefixes in DHCP and ARP (mattysplo.it), the default tinypilot.local name (ReliaQuest), and exposed interfaces from Shodan or Censys matched against proxy logs (Grumpy Goose Labs). A GL.iNet Comet with an obfuscation preset presents another identity, so a clean result does not rule one out.

Hand-drawn diagram: a company desktop wired through an EDID emulator and a TinyPilot KVM to a separate laptop.
The setup as drawn by the operation for a prospective U.S. facilitator: a TinyPilot KVM between the company machine and the network, and an EDID emulator so the machine never sleeps.Source: Hayden McKenzie
Four numbered photographs of cables being connected to a TinyPilot KVM.
The install steps sent with it: Ethernet, USB, HDMI, then power.Source: Hayden McKenzie
Technique
Hardware-based remote access to a corporate endpoint, evading software remote-access controls entirely (MITRE ATT&CK T1200, Hardware Additions), in support of fraudulent-employment valid-account misuse (T1078); network-side discovery of the same hardware.
Data sources
Windows Security event log (6416), EDR PnP/USB device telemetry, Windows registry (USB enumeration), macOS system profiler, DHCP logs, Endpoint process telemetry, DNS/mDNS telemetry, Internet-wide scan data, macOS ColorSync display profiles
Last updated
2026-10-04

Indicators

The atomic values this hunt matches on, listed separately from the queries so they can be lifted into tooling that speaks none of the query languages below. Every value here is reported by one of the sources cited at the foot of this page.

TypeValueNote
USB VID/PID VID_1D6B&PID_0104 PiKVM Composite Device, as recovered by Huntress; the same VID/PID is published for TinyPilot by mattysplo.it. It is the generic Linux USB gadget identifier, so it also appears on any other Linux device emulating USB peripherals.
Registry FriendlyName PiKVM Composite Device Under HKLM\SYSTEM\CurrentControlSet\Enum\USB (Huntress).
USB VID/PID VID_345F&PID_2130 Guermok USB3 Video capture card, registered as a webcam on the host (Huntress).
Registry FriendlyName Guermok USB3 Video Under HKLM\SYSTEM\CurrentControlSet\Enum\USB (Huntress).
Registry FriendlyName UltraSemi / MacroSilicon The same Guermok capture card enumerates on some hosts under the names of the chipset vendors behind it, UltraSemi and MacroSilicon (the MS2130 that VID_345F&PID_2130 identifies), rather than under Guermok, so every query on this page matches those strings alongside it. Recorded from this site's own observation on 18 September 2026 rather than from published reporting.
USB VID/PID VID_3346&PID_1009 NanoKVM, which enumerates as USB 3346:1009 (SANS Internet Storm Center, "Detecting IP KVMs").
USB descriptor Manufacturer: PiKVM / ProductName: Optical Drive PiKVM mass-storage interface as seen in USB logging (ReliaQuest).
USB descriptor Generic Monitor (%1);(TinyPilot) TinyPilot DeviceDescription as seen in USB logging (ReliaQuest).
USB Manufacturer tinypilot Manufacturer string a stock TinyPilot reports (Grumpy Goose Labs).
USB Manufacturer PiKVM Manufacturer string a stock PiKVM reports (Grumpy Goose Labs).
USB Manufacturer GLKVM (firmware 1.3.0); Glinet (firmware 1.5.0) The GL.iNet Comet's manufacturer string, which changed between firmware versions (Grumpy Goose Labs, "Be KVM, Do Fraud"). The Comet ships presets that impersonate other peripherals, so a device that presents these strings has not had them turned on; see the Comet hunt for the fingerprints that survive the presets.
USB configuration name Config 1: GLKVM device Comet USB configuration descriptor name (Grumpy Goose Labs, "Be KVM, Do Fraud").
USB serial CAFEBABE Default PiKVM gadget serial (ReliaQuest, mattysplo.it).
USB serial 6b65796d696d657069 Default TinyPilot gadget serial (ReliaQuest, mattysplo.it). The hex decodes to "keymimepi", after Key Mime Pi, the project TinyPilot builds on.
File path (macOS) /Library/ColorSync/Profiles/Displays/TinyPilot-*.icc Colour profile macOS writes for the display TinyPilot presents (ReliaQuest). It persists after the device is unplugged, which makes it the one artifact in this hunt that finds a KVM which is no longer attached.
Windows event Security 6416 "A new external device was recognized by the System." Huntress recommends alerting on this event where the device description contains PiKVM or Guermok.
MAC OUI 04c98b (TinyPilot); b827eb, 28cdc1, d83add, dca632, e45f01, 2ccf67, 3a3541, 88a29e, 98fe54 (Raspberry Pi) Hardware-address prefixes published by mattysplo.it. The first is attributed to TinyPilot itself; the remainder are Raspberry Pi, which is what a PiKVM and a TinyPilot are both built on.
Hostname tinypilot.local Default TinyPilot mDNS name (ReliaQuest). Link-local, so a hit means the device is on the same segment as the host that resolved it.
Command ssh.exe pilot@tinypilot.local TinyPilot administration over SSH from the connected host (ReliaQuest).
Command sudo.exe service tinypilot start TinyPilot service control (ReliaQuest).
Scan query http.title:"PiKVM" Shodan/Censys query for an internet-exposed PiKVM web interface (mattysplo.it).
Scan query http.html:'<script src="guacamole' Shodan/Censys query for an exposed Guacamole remote-desktop gateway (mattysplo.it).
Scan query http.title:tinypilot,pikvm Combined Shodan query for both device web interfaces (Grumpy Goose Labs).

Logic

Every query below implements these steps, so the same hunt returns the same result in each product.

  1. Collect: USB/PnP enrolment on Windows (6416, PnP connect) and macOS (USB inventory, ColorSync profiles); process, DNS and ARP/DHCP data
  2. Match: USB descriptor, serial or VID/PID of a known IP-KVM or capture card (PiKVM, TinyPilot, GL.iNet Comet, NanoKVM, Guermok)
  3. Match: or a ColorSync profile, command line or DNS name carrying tinypilot, pikvm or glkvm
  4. Match: or (optional) a Raspberry Pi or TinyPilot MAC prefix in DHCP leases or the ARP cache
  5. Report: hosts with a match, newest first; flag hosts that match both an IP-KVM and a capture card

Queries

Defender / Sentinel KQL

Written for this site, from indicators reported by Huntress, ReliaQuest

A host listing both Classes (IP-KVM and CaptureCard) is the pairing Huntress reports; confirm the AdditionalFields keys against a known PnpDeviceConnected event in your tenant.

// Hunt: IP-KVM and capture-card hardware on a corporate laptop. Windows PnP,
// macOS colour profiles, and any command line or lookup naming tinypilot.
let KvmWords = dynamic(["pikvm", "tinypilot", "glkvm", "cafebabe", "6b65796d696d657069"]);
let CaptureWords = dynamic(["guermok", "ultrasemi", "macrosilicon"]);
union
( DeviceEvents
  | where Timestamp > ago(90d) and ActionType == "PnpDeviceConnected"
  | extend Raw = tostring(AdditionalFields)
  | extend Class = case(
      Raw has_any (KvmWords)
        // optional: generic Linux USB gadget id, shared by any board emulating peripherals
        or Raw contains "VID_1D6B&PID_0104"
        // optional: GL.iNet also sells routers and travel hubs
        or Raw has "glinet"
        or Raw contains "VID_3346&PID_1009", "IP-KVM",
      // optional: capture cards are common alone; they only matter next to an IP-KVM
      Raw has_any (CaptureWords) or Raw contains "VID_345F&PID_2130", "CaptureCard",
      "")
  | where Class != ""
  | project Timestamp, DeviceName, Class, Signal = "usb-enrolment", Evidence = Raw ),
( DeviceFileEvents
  | where Timestamp > ago(90d) and ActionType in ("FileCreated", "FileModified", "FileRenamed")
  | where FolderPath contains "/ColorSync/Profiles/Displays"
  | where FileName has_any ("tinypilot", "pikvm", "glkvm")
  | project Timestamp, DeviceName, Class = "IP-KVM", Signal = "colorsync-profile", Evidence = FileName ),
( DeviceNetworkEvents
  | where Timestamp > ago(90d) and RemoteUrl has "tinypilot"
  | project Timestamp, DeviceName, Class = "IP-KVM", Signal = "tinypilot-lookup", Evidence = RemoteUrl ),
( DeviceProcessEvents
  | where Timestamp > ago(90d) and ProcessCommandLine has "tinypilot"
  | project Timestamp, DeviceName, Class = "IP-KVM", Signal = "tinypilot-command", Evidence = ProcessCommandLine )
| summarize FirstSeen = min(Timestamp), LastSeen = max(Timestamp), Classes = make_set(Class),
            Signals = make_set(Signal), Evidence = make_set(Evidence, 10) by DeviceName
| extend KvmAndCapture = set_has_element(Classes, "IP-KVM") and set_has_element(Classes, "CaptureCard")
| sort by KvmAndCapture desc, LastSeen desc
Lower-fidelity parts (3)
  • VID_1D6B&PID_0104 (generic Linux USB gadget id) — any Linux board emulating USB peripherals presents it, so it is a lead rather than a verdict. Remove: delete the // optional: generic Linux USB gadget id comment and the line under it
  • the `glinet` vendor string — GL.iNet also sells routers and travel hubs that can present the same vendor. Remove: delete the // optional: GL.iNet comment and the line under it
  • the capture-card branch (Guermok, UltraSemi, MacroSilicon, VID_345F&PID_2130) — these chipsets sit in many ordinary capture dongles, so a card alone is common. Remove: delete the // optional: capture cards comment and the line under it; hosts are then reported for IP-KVM matches only

Sigma

Written for this site, from indicators reported by Huntress, ReliaQuest

Matches the Windows Security 6416 enrolment event; it is the only rule here that keeps product: windows, because 6416 does not exist elsewhere.

title: IP-KVM or USB Capture-Card Hardware Recognized by a Corporate Endpoint
id: a60aaf7f-d5ee-592e-aa29-85af6afa4359
status: experimental
description: >
  Detects Windows recognizing an external device whose descriptor, hardware id
  or serial matches the KVM-over-IP and video-capture hardware reported in DPRK
  IT-worker laptop-farm cases (PiKVM, TinyPilot, NanoKVM, GL.iNet Comet,
  Guermok USB3 Video and the chipset names it enumerates under). Hardware of
  this class gives an operator console control of the host without any
  software an EDR agent inspects, so the enrolment event is often the only
  endpoint-side signal.
references:
  - https://www.huntress.com/blog/huntress-dprk-remote-worker-investigation
  - https://reliaquest.com/blog/threat-spotlight-identifying-north-korean-insider-threats
logsource:
  product: windows
  service: security
detection:
  selection_event:
    EventID: 6416
  selection_description:
    DeviceDescription|contains:
      - 'PiKVM'
      - 'TinyPilot'
      - 'GLKVM'
      - 'Guermok'
      - 'UltraSemi'
      - 'MacroSilicon'
      # optional: GL.iNet also sells routers and travel hubs
      - 'Glinet'
  selection_id:
    DeviceId|contains:
      - 'VID_345F&PID_2130'
      - 'VID_3346&PID_1009'
      - 'CAFEBABE'
      - '6b65796d696d657069'
      # optional: generic Linux USB gadget id, shared by any board emulating peripherals
      - 'VID_1D6B&PID_0104'
  condition: selection_event and (selection_description or selection_id)
falsepositives:
  - Out-of-band management hardware legitimately deployed in a lab, test bench or datacenter
  - VID_1D6B&PID_0104 is the generic Linux USB gadget identifier and is not unique to KVM hardware
level: high
Lower-fidelity parts (2)
  • the 'Glinet' description — GL.iNet also sells routers and travel hubs. Remove: delete the line under the # optional: GL.iNet comment and the comment
  • VID_1D6B&PID_0104 — generic Linux USB gadget id shared by any board emulating peripherals. Remove: delete the line under the # optional: generic Linux USB gadget id comment and the comment

Splunk SPL

Written for this site, from indicators reported by Huntress, ReliaQuest, mattysplo.it

Free-text matching over the raw events means it works without field extractions; kvm_and_capture=yes marks the pairing Huntress reports.

```Placeholders: index=wineventlog is WinEventLog:Security (event 6416); index=edr is your EDR process, file and DNS events (macOS and Windows); index=dhcp is DHCP leases.```
((index=wineventlog EventCode=6416) OR index=edr)
    ("PiKVM" OR "TinyPilot" OR "GLKVM" OR "CAFEBABE" OR "6b65796d696d657069" OR "VID_3346&PID_1009"
     ```optional: generic Linux USB gadget id, shared by any board emulating peripherals``` OR "VID_1D6B&PID_0104"
     ```optional: GL.iNet also sells routers and travel hubs``` OR "Glinet"
     ```optional: capture cards are common alone; they only matter next to an IP-KVM``` OR "Guermok" OR "UltraSemi" OR "MacroSilicon" OR "VID_345F&PID_2130")
| eval kvm=if(match(_raw, "(?i)pikvm|tinypilot|glkvm|cafebabe|6b65796d696d657069|vid_3346&pid_1009"), 1, 0)
```optional: generic Linux USB gadget id```
| eval kvm=if(match(_raw, "(?i)vid_1d6b&pid_0104"), 1, kvm)
```optional: GL.iNet```
| eval kvm=if(match(_raw, "(?i)glinet"), 1, kvm)
```optional: capture cards```
| eval capture=if(match(_raw, "(?i)guermok|ultrasemi|macrosilicon|vid_345f&pid_2130"), 1, 0)
| stats min(_time) AS first_seen max(_time) AS last_seen max(kvm) AS kvm max(capture) AS capture
        values(sourcetype) AS sources BY host
| eval kvm_and_capture=if(kvm=1 AND capture=1, "yes", "no")
```optional: Raspberry Pi and TinyPilot MAC prefixes in DHCP; every Pi on a home network matches. Delete from here to the closing bracket to drop it.```
| append
    [ search index=dhcp
      | eval mac_clean=lower(replace(mac, "[:.-]", ""))
      | eval oui=substr(mac_clean, 1, 6)
      | search oui IN ("04c98b", "b827eb", "28cdc1", "d83add", "dca632", "e45f01", "2ccf67", "3a3541", "88a29e", "98fe54")
      | stats min(_time) AS first_seen max(_time) AS last_seen values(ip) AS addresses
              values(hostname) AS hostnames BY mac_clean ]
| sort - kvm_and_capture - last_seen
| convert ctime(first_seen) ctime(last_seen)
Lower-fidelity parts (2)
  • the DHCP append block — Raspberry Pi prefixes match every hobbyist Pi on a home network. Remove: delete the lines from the ```optional: comment through the closing bracket of the append
  • the VID_1D6B&PID_0104 term — generic Linux USB gadget id shared by any board emulating peripherals. Remove: delete that term and its OR from the search and from the kvm match() pattern

CrowdStrike LogScale

Written for this site, from indicators reported by Huntress, ReliaQuest

Event-wide regex branches avoid assuming DcUsbDeviceConnected field names, which Falcon documents only inside the console; the command-line and DNS branches use standard fields.

// Hunt: IP-KVM and capture-card hardware. Device Control USB events, plus any command line or lookup naming tinypilot.
// The USB branches match the whole event, so no DcUsbDeviceConnected field name is assumed.
(#event_simpleName=DcUsbDeviceConnected or #event_simpleName=ProcessRollup2 or #event_simpleName=SyntheticProcessRollup2 or #event_simpleName=DnsRequest)
| case {
    #event_simpleName=DcUsbDeviceConnected /pikvm|tinypilot|glkvm|cafebabe|6b65796d696d657069|vid_3346&pid_1009/i | class := "IP-KVM";
    // optional: generic Linux USB gadget id, shared by any board emulating peripherals
    #event_simpleName=DcUsbDeviceConnected /vid_1d6b&pid_0104/i | class := "IP-KVM";
    // optional: GL.iNet also sells routers and travel hubs
    #event_simpleName=DcUsbDeviceConnected /glinet/i | class := "IP-KVM";
    // optional: capture cards are common alone; they only matter next to an IP-KVM
    #event_simpleName=DcUsbDeviceConnected /guermok|ultrasemi|macrosilicon|vid_345f&pid_2130/i | class := "CaptureCard";
    CommandLine=/tinypilot/i | class := "IP-KVM";
    DomainName=/tinypilot/i | class := "IP-KVM";
    * | class := "";
  }
| class != ""
| groupBy([aid, ComputerName], function=[min(@timestamp, as=firstSeen), max(@timestamp, as=lastSeen), collect([class]), count(class, distinct=true, as=classes)])
| sort(lastSeen, order=desc)
Lower-fidelity parts (3)
  • VID_1D6B&PID_0104 (generic Linux USB gadget id) — any Linux board emulating USB peripherals presents it, so it is a lead rather than a verdict. Remove: delete the // optional: generic Linux USB gadget id comment and the line under it
  • the `glinet` vendor string — GL.iNet also sells routers and travel hubs that can present the same vendor. Remove: delete the // optional: GL.iNet comment and the line under it
  • the capture-card branch (Guermok, UltraSemi, MacroSilicon, VID_345F&PID_2130) — these chipsets sit in many ordinary capture dongles, so a card alone is common. Remove: delete the // optional: capture cards comment and the line under it; hosts are then reported for IP-KVM matches only

Elastic

Written for this site, from indicators reported by Huntress, ReliaQuest

Reads the Windows 6416 event plus Elastic Defend file, process and network events; classes = 2 marks the IP-KVM and capture-card pairing.

FROM logs-system.security-*, winlogbeat-*, logs-endpoint.events.file-*, logs-endpoint.events.process-*, logs-endpoint.events.network-*
| WHERE @timestamp > NOW() - 90 days
| EVAL usb = TO_LOWER(CONCAT(COALESCE(winlog.event_data.DeviceDescription, ""), " ", COALESCE(winlog.event_data.DeviceId, "")))
| EVAL other = TO_LOWER(CONCAT(COALESCE(file.path, ""), " ", COALESCE(process.command_line, ""), " ", COALESCE(dns.question.name, "")))
| EVAL class = CASE(
    event.code == "6416" AND usb RLIKE ".*(pikvm|tinypilot|glkvm|cafebabe|6b65796d696d657069|vid_3346&pid_1009).*", "IP-KVM",
    event.code == "6416" AND usb RLIKE ".*(guermok|ultrasemi|macrosilicon|vid_345f&pid_2130).*", "CaptureCard",
    other RLIKE ".*(/colorsync/profiles/displays/.*(tinypilot|pikvm|glkvm)|tinypilot).*", "IP-KVM",
    "")
| EVAL class = CASE(class != "", class, event.code == "6416" AND usb RLIKE ".*vid_1d6b&pid_0104.*", "IP-KVM", "")
| EVAL class = CASE(class != "", class, event.code == "6416" AND usb RLIKE ".*glinet.*", "IP-KVM", "")
| WHERE class != ""
| STATS first_seen = MIN(@timestamp), last_seen = MAX(@timestamp), classes = COUNT_DISTINCT(class) BY host.name
| SORT classes DESC, last_seen DESC
Lower-fidelity parts (3)
  • the `| EVAL class = COALESCE(... vid_1d6b&pid_0104 ...)` line — generic Linux USB gadget id shared by any board emulating peripherals. Remove: delete that line
  • the `| EVAL class = COALESCE(... glinet ...)` line — GL.iNet also sells routers and travel hubs. Remove: delete that line
  • the CaptureCard CASE branch — capture cards are common alone. Remove: delete the second line of the first CASE (the one containing guermok); capture cards are then never reported

Cortex XQL

Written for this site, from indicators reported by ReliaQuest

Covers the three matches xdr_data records on both operating systems; USB enrolment needs the Windows event or osquery queries.

// Hunt: IP-KVM hardware. xdr_data carries the colour-profile, command-line and DNS matches; USB enrolment is not in it.
dataset = xdr_data
| filter (event_type = ENUM.FILE and action_file_path ~= "(?i)/ColorSync/Profiles/Displays/" and action_file_name ~= "(?i)tinypilot|pikvm|glkvm")
    or (event_type = ENUM.PROCESS and action_process_image_command_line ~= "(?i)tinypilot")
    or (event_type = ENUM.NETWORK and (dns_query_name ~= "(?i)tinypilot" or action_external_hostname ~= "(?i)tinypilot"))
| alter signal = if(event_type = ENUM.FILE, "colorsync-profile", if(event_type = ENUM.PROCESS, "tinypilot-command", "tinypilot-lookup"))
| comp min(_time) as first_seen, max(_time) as last_seen, values(signal) as signals by agent_hostname
| sort desc last_seen

osquery

Written for this site, from indicators reported by Huntress, ReliaQuest, mattysplo.it

Local state check for macOS and Linux endpoints: attached USB devices, ColorSync profiles that persist after a KVM is unplugged, and neighbours with Raspberry Pi prefixes.

-- Hunt: IP-KVM hardware on macOS (Linux for the USB and ARP branches); osquery has no usb_devices table on Windows.
SELECT 'usb-device' AS signal, vendor || ' ' || model || ' ' || serial || ' ' || vendor_id || ':' || model_id AS evidence
FROM usb_devices
WHERE vendor || model LIKE '%PiKVM%'
   OR vendor || model LIKE '%TinyPilot%'
   OR vendor || model LIKE '%GLKVM%'
   OR (vendor_id = '3346' AND model_id = '1009')
   OR serial IN ('CAFEBABE', '6b65796d696d657069')
   OR (vendor_id = '1d6b' AND model_id = '0104')  -- optional: generic Linux gadget id, shared by any board emulating peripherals
   OR vendor LIKE '%Glinet%'  -- optional: GL.iNet also sells routers and travel hubs
   OR (vendor_id = '345f' AND model_id = '2130') OR vendor || model LIKE '%Guermok%' OR vendor || model LIKE '%UltraSemi%' OR vendor || model LIKE '%MacroSilicon%'  -- optional: capture cards are common alone
UNION ALL
SELECT 'colorsync-profile', path || ' (created ' || btime || ')'
FROM file
WHERE (path LIKE '/Library/ColorSync/Profiles/Displays/%' OR path LIKE '/Users/%/Library/ColorSync/Profiles/Displays/%')
  AND (filename LIKE '%TinyPilot%' OR filename LIKE '%PiKVM%' OR filename LIKE '%GLKVM%')
UNION ALL
-- optional: Raspberry Pi and TinyPilot MAC prefixes in the ARP cache; every Pi on the segment matches
-- (macOS prints octets without the leading zero, so 04:c9:8b and e4:5f:01 each appear twice)
SELECT 'arp-neighbour', address || ' ' || mac
FROM arp_cache
WHERE mac LIKE '04:c9:8b:%' OR mac LIKE '4:c9:8b:%' OR mac LIKE 'b8:27:eb:%' OR mac LIKE '28:cd:c1:%'
   OR mac LIKE 'd8:3a:dd:%' OR mac LIKE 'dc:a6:32:%' OR mac LIKE 'e4:5f:01:%' OR mac LIKE 'e4:5f:1:%'
   OR mac LIKE '2c:cf:67:%' OR mac LIKE '3a:35:41:%' OR mac LIKE '88:a2:9e:%' OR mac LIKE '98:fe:54:%';
Lower-fidelity parts (3)
  • the generic gadget id (1d6b:0104) — any Linux board emulating USB peripherals presents it. Remove: delete that condition and the -- optional comment on it
  • the `Glinet` vendor match — GL.iNet also sells routers and travel hubs. Remove: delete that line
  • the arp_cache branch — Raspberry Pi prefixes match every hobbyist Pi on the segment. Remove: delete from the -- optional comment through the end of the statement and the UNION ALL above it

Shodan / Censys

Written for this site, from indicators reported by mattysplo.it, Grumpy Goose Labs

Internet-exposed KVM web interfaces; cross-reference the exported addresses against sign-in and VPN source addresses to find a workstation connecting from one.

http.title:tinypilot,pikvm
http.title:"PiKVM"
http.title:"TinyPilot"
http.html:'<script src="guacamole'
Lower-fidelity parts (1)
  • the Guacamole html match — it matches every Apache Guacamole login page, not only KVM gateways. Remove: delete the http.html line

False positives and tuning

VID_1D6B&PID_0104 is the generic Linux gadget identifier, shared by any Linux board emulating USB peripherals. Treat it as a lead and rely on the FriendlyName and serial, which are stock values that can be changed.

Out-of-band hardware is legitimate in labs and datacenters, so scope this to standard-issue laptops; a capture card alone is unremarkable for anyone who streams. An IP-KVM on a remote employee's laptop is the strong signal.

Raspberry Pi prefixes cover every Pi, including hobbyist Pi-hole and smart-home devices on home networks, so the network checks yield leads rather than alerts. Refresh the prefix list, as new blocks are issued.

Shodan and Censys queries find exposed KVMs generally, most unrelated to this campaign; Grumpy Goose Labs notes one on your network means the system is probably reachable unintentionally, not misused.

Sources

Tuning required before use This hunt is a starting point. Adapt the queries to your schema, validate them against your baseline and tune them for the false positives noted above. Indicators go stale as operators rotate hosts.