REPORT
CEPATO Technical Note2025.12.16

Rescuing a Linux Host With Nothing but an Android Phone: A Deep Dive Into USB Gadget

Using an Android phone as a keyboard to unbrick a machine: USB Gadget emulating HID, and using the IO LEDs to rescue an Ubuntu box you can't SSH into

Chongxi
Author:Chongxi
steam: —·spotify: —
Tags:#Android#Linux
ANALYSIS

0. Introduction#

First, meet the star of this post. Chongxi previously bought a little OneCloud mini PC, flashed Ubuntu armv7 onto it, and used it as a lightweight server running small things like AdGuard Home. While heavily modifying it, a config file error killed the host’s network interface, making SSH impossible. With no physical keyboard or HDMI monitor available in the environment, and no reset button on the host, the machine was left half-crippled.

0.1 Ingredients#

First, the rescue tools:

  • A rooted Android phone
  • A USB cable Software needed:
  • USB Gadget Tool
  • Android HID Keyword

All the needed files can be downloaded from the GitHub links provided, or you can grab them all in one click from Atlas 快递站.

1. How it works#

It’s actually very simple: turn the Android device into a keyboard and type into the host. As for how to judge command output without HDMI for visualization? The answer is the IO LEDs.
Yes, you heard that right. Most people may have heard of debugging with the motherboard’s IO LEDs, but rarely of using IO LEDs to judge input and output while rescuing an Ubuntu host. When you input commands and when the host produces output, the IO LEDs blink — and this post diagnoses everything from those LEDs.

Now that we know the principle, the rest of the rescue must be simple… right?

1.1 The obstacle#

First of all, it’s definitely not as simple as “plug in the cable, then open Gboard and start typing.”
The USB protocol has a strict master-slave relationship. Once you plug into the host, odds are the host treats you as the device to be debugged, not the other way around.
Then there’s the BadUSB risk. A quick primer on the basics:

NOTE

BadUSB

BadUSB is one of the classic attack techniques. The USB protocol has a trust flaw: the host unconditionally trusts a device’s declaration of its own identity. Say you’re a keyboard and it will believe you, with no additional verification. A simple BadUSB attack goes like this:

  1. Plug the attack device into the host
  2. The attack device declares itself as a USB flash drive to the host, and the host trusts it and loads it
  3. The attack device disconnects on its own and reconnects declaring itself as HID; the host doesn’t verify whether it’s really a keyboard, just loads the driver, and accepts all input from the device with no defenses
  4. The attack device starts injecting commands into the host (such as launching PowerShell to download a trojan), and to the host it just looks like a human typing very fast, so nothing stops it
WARNING

What does this have to do with your Android phone?

If your Android device has full USB Gadget permissions, it can become the most powerful and stealthy BadUSB in OURWORLD — who would suspect a harmless phone that’s just charging? You can write attack scripts in Termux to inject into a target device while the other side thinks you’re just charging — in reality you’re emulating a keyboard, or even acting as a USB network card to hijack traffic and launch a man-in-the-middle attack. NetHunter is a penetration-testing ROM built specifically for Android devices; it can control the phone’s USB port at will and disguise it as all kinds of devices

OEMs, Google and the Android community all understand this. Faced with such an enormous security risk, the decision was very simple: just cut it out.
For ordinary consumers, USB transfer at most means swapping photo files and network sharing; killing Gadget outright is undoubtedly the inevitable choice for OEMs — the risk is simply too severe

So how did I get an Android device to successfully emulate HID and type into Ubuntu?

2. How it’s implemented#

Talk is cheap, show me the code.

Let’s go straight to the Linux kernel’s official configfs.txt to explain why a userspace program can control kernel-level hardware behavior

2.1 The kernel provides blueprints, not finished products#

PRTCL // TXT
Where sysfs is a filesystem-based view of kernel objects, configfs is a filesystem-based manager of kernel objects

That is, sysfs lets you look at things the kernel has already created (like your CPU temperature), while configfs lets you ask the kernel to create new things for you. When the Android kernel is compiled with the CONFIG_USB_GADGET and CONFIG_USB_HID options enabled, the kernel doesn’t immediately create a USB keyboard device. It merely prepares the basic tools under /config/usb_gadget/, waiting for you to do the assembling

2.2 mkdir#

PRTCL // TXT
A configfs config_item is created via an explicit userspace operation: mkdir(2).

Every directory you create in configfs is equivalent to calling a kernel function

For example

PRTCL // BASH
Terminal window
mkdir /config/usb_gadget/g1
  • When this command runs, configfs notifies USB Gadget: the user wants to create a new Gadget instance, g1
  • The kernel module then allocates a chunk of memory to describe the USB device about to be created

2.3 Directories and files#

PRTCL // TXT
The item's attributes will also appear at this time.

After mkdir succeeds, the kernel immediately generates a bunch of config files in the new directory for you; these files are the configurable attributes of the new object

For example, after mkdir g1, ls /config/usb_gadget/g1 might show something like this:

PRTCL // PLAINTEXT
idVendor # vendor ID
idProduct # product ID
strings/ # various string descriptors, such as the vendor name
functions/ # defines what device this Gadget can act as
configs/ # the actual USB configuration bindings
UDC # binds the configured Gadget to the physical USB controller

2.4 Writing the config#

PRTCL // TXT
write(2) can store new values.

In other words, using echo to write into these attribute files is equivalent to setting the parameters of that object in the kernel

For example, to make it emulate a keyboard

PRTCL // BASH
Terminal window
mkdir /config/usb_gadget/g1/functions/hid.usb0
# configure parameters
echo "..." > /config/usb_gadget/g1/functions/hid.usb0/report_desc
# create a USB configuration and bind the keyboard function
mkdir /config/usb_gadget/g1/configs/c.1
ln -s /config/usb_gadget/g1/functions/hid.usb0 /config/usb_gadget/g1/configs/c.1

2.5 Activation#

PRTCL // TXT
[configfs handles] the filesystem representation... allowing the subsystem to ignore all but the basic show/store interaction.

The kernel module itself doesn’t care how you created and configured things; it only waits for activation at the last step

Example

PRTCL // BASH
Terminal window
# find your phone's USB controller name (such as a12345.dwc3), then write it into the UDC file
echo "a12345.dwc3" > /config/usb_gadget/g1/UDC

When the UDC file is written, the kernel’s USB Gadget module receives a Commit signal
It reads all the configuration you just did in the g1 directory and assembles it into a complete USB device descriptor
Then it commands the physical USB controller to disconnect the current connection and reconnect to the host as a keyboard

And with that, the Android device has become a keyboard input device.

3. How I rescued it#

  1. Make sure your Android phone is rooted, install the two open-source tools mentioned above, grant su permission in Gadget Tool, and check HID Keyboard to enable it — that completes the Android device emulating a keyboard.

  2. Connect the Android device to the Ubuntu host with a USB cable. The phone is now recognized as an input device. When you press keys on the soft keyboard provided by HID Keyboard, you can see the IO LEDs blink; from here on, all diagnosis relies on the IO LEDs.

  3. Try entering the password and wait ten seconds. I recommend just using the root account to save yourself the trouble of sudo. Worrying about user-group security in this situation is pointless. Then run ls and watch whether the IO LEDs blink heavily; heavy blinking means ls successfully produced output. To be safe, I decided to reboot, and the host restarted, confirming our login worked.

  4. Chongxi had prepared a recovery script in advance to guard against this kind of dumb situation; its main job is to restore the backed-up contents of the network interface. Judging the input again via the IO LEDs, I ran the recovery command directly, the host restarted, and when I opened OpenWrt I saw normal traffic on the LAN port corresponding to Ubuntu — SSH connected fine, and the rescue was a success.

4. Conclusion#

This post really goes beyond the scope of ordinary Linux desktop use — you could call it pure showing off. It requires kernel support on your device and root access, so it’s a solution that demands that everything line up.

For Linux players, there is no absolute dead end — only backdoors you haven’t discovered yet. Such is the excellence of openness

Chongxi
CHONGXIAuthor
Steam—
Spotify—
Published at:2025.12.16
Classified
Distribution Notice

Rescuing a Linux Host With Nothing but an Android Phone: A Deep Dive Into USB Gadget

Author CHONGXI/2025.12.16/CEPATO-2025-1216-AKEYBO

This work is licensed under CC BY-NC-SA 4.0. Redistribution, remixing and adaptation are allowed for non-commercial use, provided the same license is used and the original author is credited.

SubscribeDonate
Discussion
Archive_Ref
Copyright © 2011–2026 Chongxi & CEPATO
Powered by Astro & CEPATO-NEXT
StatusNon-Collaborative_Entity // CEPATO_NEXT_v27.0

Type a keyword to search