Skip to content

ADB sensor

An Android TV set-top box with adbd listening on TCP 5555 and no authentication, as on the many boxes with ro.adb.secure=0 that botnets scan for. The sensor never asks for AUTH.

It listens on container port 5555. Compose maps the host port ADB_HOST_PORT (default 5555) to it.

  • Banner. The device model is chosen from a random per-deployment secret. It is one of a few cheap TV boxes on Android 7.1.2 or 9, with plausible properties, serial number and MAC address.
  • Shell. shell: (interactive or one-shot) and exec: run in an emulated Android sh. It has a toybox command set, getprop, pm, am, dumpsys, /sdcard and a writable /data/local/tmp. Nothing is executed.
  • Files. sync: (STAT, LIST, RECV, SEND) works on the fake file system. A pushed file is hashed and dropped. Only its first 8 KiB are kept in memory for the session, so ls -l looks right.
  • Installs. exec:cmd package install is accepted. The APK is hashed and thrown away, and the reply is Success.
  • Mirai-style loaders print plausible BusyBox output when the box has BusyBox. The URL is recorded and a stub file is left. A dropped “binary” does nothing when it is run.
  • Other services (tcp:, localabstract:, forward, jdwp:) are refused as adbd refuses them, and recorded.

All events use the shared Event schema.

Event typeContent
connectbanner (the sensor’s identity), client_version, client_banner.
commandinput, output_preview, cwd, user, service (shell or exec), interactive, flags. Pushes add path, sha256, size, mode. Installs add sha256 and size.
download_attempturl, tool (wget, curl, tftp, ftpget or command-line), command.
scanRaw payloads, refused services (adb_service), adb_auth, connection_summary.
disconnectduration_s, reason, commands, downloads, pushes, installs, streams_opened, replay.

There is no login on ADB, so there are no login_attempt events.

The session replay of an interactive shell is kept in the disconnect event, as on the SSH sensor. See SSH sensor.

Rules live in ingest/rules/services.yaml.

TagSet when the sensor flags
malware-dropadb_push or adb_install, or any download_attempt.
miraiA shell command with BusyBox loader tokens (busybox, ecchi, mirai, /dev/watchdog), or a download made with BusyBox.

Other flags on the session: adb_shell, adb_pull, adb_reboot and adb_service.

Compose sets ADB_MAX_CONNECTIONS to 200 and ADB_MAX_PER_IP to 8. The sensor’s own defaults are in its README.

ScopeLimit (environment variable, default)
ConnectionsSENSOR_MAX_CONNECTIONS and SENSOR_MAX_PER_IP, see above.
New connectionsSENSOR_CONN_RATE_PER_IP 1 per second per source, burst 10.
TimeoutsHandshake 20 s, message 30 s, idle 300 s, whole session 1800 s.
Streams8 open streams per connection, 200 in total. A stream that is not acknowledged after 512 messages is no longer written to.
Input and hashing24 MiB of input and 16 MiB hashed per connection (SENSOR_MAX_INPUT_MB, SENSOR_MAX_HASH_MB).
CommandsSENSOR_MAX_COMMANDS 2000 per connection. SENSOR_LINE_BUDGET 0.15 s of CPU per command line.
CPU and memorySENSOR_SHELL_CPU_SHARE 0.3 CPU-seconds per second for all sessions, shared fairly between sources. SENSOR_MEMORY_BUDGET_MB 112 for all sessions.
EventsSENSOR_EVENTS_PER_SEC 20 connect events per source, SENSOR_GLOBAL_EVENTS_PER_SEC 200 for the sensor.

Same hardening as the other sensors: non-root (UID 10001), read-only root file system, tmpfs at /tmp, all capabilities dropped, no-new-privileges, 256 MB of memory with no swap, 0.5 CPU and 128 processes. Health check: python -m adb_sensor.healthcheck. The profile secret is kept in the adb-sensor-data volume.