Exfiltrating Data Through Your Keyboard LEDs: Inside USBpwn-Host
Hook
Your keyboard's Num Lock LED can betray you. While security teams monitor networks, USB drives, and clipboard access, three tiny lights are silently blinking out your credentials at 2 bytes per second—and no antivirus will catch it.
Context
Air-gapped systems and heavily restricted corporate environments present a unique challenge for security researchers and red teams. When you can't access the network, can't write to USB drives, can't run unauthorized software, and every file transfer is logged, how do you prove a system is vulnerable? Traditional data exfiltration methods—network sockets, file drops, clipboard manipulation—all leave traces that modern EDR systems catch immediately.
USBpwn-host explores an unconventional attack vector: keyboard LED indicators. Every keyboard has them—Num Lock, Caps Lock, Scroll Lock—controlled by the operating system but visible to anyone with line-of-sight. These LEDs are designed for legitimate user feedback, but they're also writable hardware outputs that applications can manipulate without administrator privileges. The tool treats them as a primitive output device, encoding binary data as LED blink patterns. On the receiving end, a smartphone camera, Raspberry Pi, or even a human observer can decode the light patterns back into the original data. It's absurdly slow, completely impractical for real attacks, but conceptually fascinating as a demonstration of how creative adversaries think about side channels.
Technical Insight
The architecture is refreshingly simple: a synchronous 2-bit parallel protocol using three keyboard LEDs. Num Lock and Caps Lock serve as data bits (D0 and D1), while Scroll Lock acts as a clock signal. The protocol is stateful and requires acknowledgement—the receiver must press Enter after each 4-bit nibble to signal readiness for the next frame.
The Win32 implementation relies on keybd_event() to toggle LED states by simulating key presses with the KEYEVENTF_EXTENDEDKEY flag. Here's the core transmission logic:
void send_nibble(unsigned char nibble) {
// Set data bits (lower 2 bits of nibble)
if (nibble & 0x01) {
keybd_event(VK_NUMLOCK, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
keybd_event(VK_NUMLOCK, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}
if (nibble & 0x02) {
keybd_event(VK_CAPITAL, 0x3a, KEYEVENTF_EXTENDEDKEY, 0);
keybd_event(VK_CAPITAL, 0x3a, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}
// Pulse clock signal (Scroll Lock)
keybd_event(VK_SCROLL, 0x46, KEYEVENTF_EXTENDEDKEY, 0);
keybd_event(VK_SCROLL, 0x46, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
// Wait for Enter key acknowledgement
wait_for_enter();
}
The protocol sends bytes LSB-first, breaking each 8-bit value into two 4-bit nibbles. Before transmitting file contents, it sends an ASCII length header surrounded by dashes (e.g., "----256----") so the receiver knows exactly how many bytes to expect. This eliminates the need for complex framing or termination sequences.
The synchronous design is crucial. Unlike asynchronous protocols that require precise timing and buffering, this approach lets a human receiver (or a simple camera script) work at their own pace. Press Enter when you've recorded the LED states, and the next nibble appears. No race conditions, no buffer overruns, no missed frames. The hardware acknowledgement loop is trivially implemented:
void wait_for_enter() {
while (1) {
if (GetAsyncKeyState(VK_RETURN) & 0x8000) {
Sleep(200); // Debounce
return;
}
Sleep(50);
}
}
What makes this technique viable on restricted systems is the privilege model. Unlike raw HID manipulation or kernel driver installation, toggling keyboard LEDs through keybd_event() requires no special permissions. It's the same API call that accessibility tools use—completely legitimate from the operating system's perspective. No UAC prompts, no administrator rights, no traces in the event log beyond standard keyboard input events.
The receiving end can be equally low-tech. A smartphone app using OpenCV can detect LED state changes by monitoring pixel brightness in the keyboard region. Alternatively, a Raspberry Pi with a light sensor positioned near the keyboard can decode the signal automatically. For proof-of-concept demonstrations, even a human observer with a notepad works—write down each LED pattern as 00, 01, 10, or 11, then reassemble the bytes later.
The data rate is abysmal by modern standards—roughly 1-2 bytes per second with human acknowledgement, maybe 5-10 bytes per second with automated receiving equipment. Exfiltrating a 1KB SSH private key would take 3-5 minutes under ideal conditions. But that's not the point. The point is demonstrating that data barriers are only as strong as your creativity in finding unexpected output channels.
Gotcha
The manual acknowledgement requirement kills any pretense of stealth. Every time the tool waits for Enter, it blocks the keyboard for user input, creating noticeable lag if the victim tries to type. If you're hoping to run this silently in the background while a user works normally, forget it—the first time their cursor doesn't move when they press a key, the jig is up. Automated receiving hardware could eliminate the acknowledgement step by having the receiver signal readiness through another side channel, but then you're adding complexity that defeats the tool's minimalist elegance.
The Windows-only implementation is another practical limitation. The concept is platform-agnostic—Linux and macOS both expose keyboard LED control through their respective APIs (ioctl calls on /dev/console for Linux, IOKit's HID framework for macOS). But this repository only includes the Win32 version, so you'll need to port it yourself if you want cross-platform demonstrations. Additionally, modern laptops increasingly lack physical LED indicators, using on-screen overlays instead. The attack requires actual hardware LEDs that respond to API calls, which rules out many ultrabooks and tablets. Finally, the line-of-sight requirement is non-negotiable—you need a camera or sensor positioned to see the keyboard, which severely limits remote attack scenarios.
Verdict
Use if: You're conducting red team exercises or security research that needs to demonstrate unconventional exfiltration vectors, especially in air-gapped or heavily monitored environments where proving the conceptual vulnerability matters more than actual data theft. It's perfect for "defense in depth" training scenarios, showing security teams that even seemingly innocuous hardware features can become attack surfaces. Also valuable if you're exploring side-channel communications for academic research or building education materials about creative adversarial thinking. Skip if: You need any kind of practical data exfiltration tool, require stealth or background operation, or expect to transfer more than a few hundred bytes. The glacial speed and manual acknowledgement make it useless for real attacks. Also skip if you're targeting modern laptops without physical LED indicators or need cross-platform support without doing your own porting work. This is a proof-of-concept demonstrator, not a penetration testing utility.