From Exposed Camera to DDoS Cannon

An internet-facing camera can become useful to an attacker without anyone looking at its video. If the attacker can run a command on the device, they can try to install a bot and use its connection to send traffic elsewhere. The camera's owner supplies the hardware, power and bandwidth.
An exposed payload directory gave investigators a view of how that process was intended to work. It held scanners, shell loaders, architecture-specific binaries and debugging scripts. Together, those files describe a chain from finding an exposed service to preparing a device for remote control.
This post preserves the technical behavior while masking provider and device-vendor names, domains, addresses, sample identifiers and hashes. Square-bracketed values are replacements; standard commands, protocols and system paths retain their meaning. Request examples are reconstructed from the analysis, not packet captures. The bot was examined statically, not executed, and successful camera infections or DDoS attacks were not established.
An open directory reveals the intended chain
The investigation began with a payload request recorded by a sensor. The requested file returned 404 Not Found, but the root of the same server exposed a directory listing. That listing contained architecture-named binaries, shell loaders, scanner scripts and download-debugging tools. A missing payload at one path had not removed the delivery service around it.
Several scripts used the same delivery infrastructure. Some loaders shared identical contents despite having different names. These relationships connect the recovered components, but they do not identify the person operating them. Similar filenames or a shared hosting provider would not establish that separate activity belonged to the same operator.
From exposure to attack traffic
- Find an exposed service A scanner tests a management interface or login.
- Attempt command execution A vulnerability or weak credential gives the attacker a possible entry point.
- Retrieve and start a payload A loader selects a binary for the device and fetches it from [staging server].
- Establish remote control The bot is designed to check in with [control server] and attempt persistence.
- Send traffic when instructed If installation and control succeed, the device could send attack traffic directly or through a relay.
The scanner, staging service and control service have different jobs. The scanner tests potential victims. The [staging server] supplies scripts and binaries. The [control server] gives an installed bot its instructions. Those roles can share infrastructure; the files do not require them to be separate machines.
Find a device that can run a command
The recovered scanners read address lists and test particular weaknesses. The camera probe sends an unauthenticated HTTP PUT to a management endpoint, with shell command substitution inside an XML field. Its first check uses sleep 4 and measures the response time. The simplified request structure is:
PUT /[camera-management-path] HTTP/1.1
Host: [sensor]
<language>$(sleep 4)</language>
The path and sensor address are masked. The $(...) expression and delay explain the test: if the vulnerable request handler passes the field into a shell, command substitution can introduce a measurable pause. The second check attempts a wget callback to [staging server]:[callback-port].
The distinction matters. A timing response can suggest that a command ran even when its output is hidden. A callback tests whether the device can reach the delivery infrastructure. The operator wants a device that is both vulnerable and able to fetch a payload. Neither check alone proves that a bot was installed.
The other scanners use different entry points:
| Target class | Recovered behavior | What the test establishes |
|---|---|---|
| Camera management interface | XML command injection, a timing check, then an outbound callback | Possible command execution and outbound reachability |
| File service | Collect session cookies, then check whether a path parameter expands {hostname} |
Server-side interpretation of a template expression; not a demonstrated bot installation |
| Content-management application | Read a page token, then attempt to upload PHP disguised as a profile XML file | An attempted upload-to-execution chain whose payload retrieves a setup script |
The toolkit also contains a default-password list covering camera/recorder accounts, router administration and generic weak logins. Vendor-specific credentials are withheld. These are alternative entry paths: exploiting an unauthenticated command-injection flaw does not necessarily require a password.
Camera-oriented probes and credential entries support the conclusion that cameras were intended targets. The probe's results were not recovered, so the material does not establish how many cameras, if any, were compromised.
Deliver a binary the device can run
After gaining command execution, the intended next step is to fetch a shell loader. It maps the output of uname -m to an architecture-specific payload. The recovered mappings cover x86_64, x86, aarch64, armv7l, mips, mipsel, m68k, powerpc and sh4.
The loader then works through a sequence of compatibility checks:
Identify CPU: uname -m -> [architecture]
Find a location: /tmp -> /dev/shm -> /var/tmp -> /var/run -> /
Try retrieval: wget -> curl -> busybox wget -> toybox wget
-> Python urllib -> raw /dev/tcp read
Prepare payload: chmod 777 [local-payload]
Start process: setsid or nohup, passing [device-class-tag]
This is a summary of the recovered loader, not a shell script. It attempts directories in order and needs a writable one; those paths are not universally writable. The broad permission change makes the downloaded file executable. setsid and nohup are used to detach it from the launching session or reduce its dependence on that session.
The loaders pass a device-class tag to the binary. That gives the control service a way to distinguish installation paths without maintaining a completely different bot for each target type. A loader's filename or tag suggests its intended use, but does not prove that a corresponding exploit worked.
Download a binary in small pieces
One variant retrieves the binary in 4,096-byte chunks and appends them locally until the file stops growing. Script comments describe large transfers stalling on constrained devices. The request carries an architecture, byte offset and requested chunk length:
/[chunk-endpoint]?arch=[architecture]&o=[offset]&n=4096
/[telemetry-endpoint]?tag=[device-tag-and-byte-count]
The endpoint names and tag values are masked; the query keys and chunk length are retained. Debug variants encode byte counts in the telemetry tag, apparently to report download progress. For a network analyst, a sequence of requests to one destination with an advancing o value and a stable n=4096 is more useful than a single unfamiliar download URL.
The directory also contained a loader for another payload, but some retrieved binaries were empty. Their filenames are not evidence of executable content, and their behavior could not be analyzed.
Inspect the bot without executing it
The analyzed bot was a stripped, statically linked x86-64 ELF. Its file-type description, with the sample name replaced, was:
[bot-x86_64]: ELF 64-bit LSB pie executable, x86-64,
version 1 (SYSV), static-pie linked, stripped
The binary takes a device tag as its first argument. Its strings include registration text, process-inspection paths, download fallbacks and persistence references. A stripped binary can still contain useful strings even when its symbol names are absent.
Static strings show which artifacts are present in a file. They do not prove that every referenced feature is reachable, works on a particular device or ran during an intrusion.
Try to keep control of the device
The binary contains references to hidden copies, cron entries, initialization scripts and a watchdog. The table preserves the locations and startup mechanisms while replacing the module-specific names.
| Mechanism | Anonymized path or pattern |
|---|---|
| Hidden copies | /tmp/.[bot], /var/run/.[bot], /usr/lib/.[bot] |
| System cron entry | /etc/cron.d/[service], containing @reboot root /tmp/.[bot] |
| Init script | /etc/init.d/[service] |
| Runlevel startup link | /etc/rc[runlevel].d/S90[service] |
| Watchdog and lock strings | [watchdog-marker], [lock-marker] |
| Alive marker and debug log | /tmp/.[alive-marker], /tmp/[debug-log] |
These are structural patterns, not literal filenames to paste into a blocklist. In a system cron file, root is the user field; a per-user crontab has a different format.
They are not proof of reliable persistence on every device. Permissions, startup mechanisms and filesystem behavior differ. A startup entry that points to a file in a temporary location cannot restore that file if it has disappeared. The recovered strings identify mechanisms to inspect; they do not demonstrate survival across a reboot.
The sample reads /proc/self/status and checks TracerPid, a field used to identify a tracing process. It also contains --guardian and --debug options and references to terminating competing bots and miners. The embedded process and file lists show intended rival removal, not which competing processes were present on any victim.
For defenders, the useful pattern is the combination: an unexpected executable, a new startup reference, recurring network contact and attempts to stop unrelated processes. An unfamiliar filename on its own is a much weaker signal.
Prepare to receive attack instructions
Static analysis found the following check-in and registration strings:
POST /%08x
REGISTER linux ...
/proc/meminfo
/%08x is a format string, not the literal request URI: it describes a hexadecimal value padded to at least eight digits. The registration text appears to include the device tag and memory information read from /proc/meminfo. The exact field order and full exchange were not established by executing the bot.
The binary also contains HTTP download strings and a BusyBox TFTP fallback, a static key value, control-address placeholders and a debug switch. The live destinations, key and sample-specific debug names are withheld. A download fallback can keep the delivery path working when one transfer method fails; it does not by itself demonstrate an alternative command channel.
Attack-method strings and proxy support
The binary contains method-like labels and protocol material consistent with several possible traffic-generation modes:
| Possible capability | Static evidence |
|---|---|
| TCP flooding | A TCP-related method label |
| TLS and browser-like HTTP traffic | Encrypted-web method labels, browser User-Agent strings, the HTTP/2 connection preface, and OPTIONS and DELETE verbs |
| Game/service queries | Service-specific method labels and a getstatus query string |
| SSH traffic | Multiple SSH version banners |
| Attack bookkeeping | A log-format string with fields for method, destination, port and duration |
The bot embeds a list of HTTP, SOCKS4 and SOCKS5 proxy endpoints. These labels describe the protocols used to connect to a proxy, which can relay traffic to a destination. An HTTP CONNECT routine suggests support for tunneling through proxies. The list was sorted by address, which is consistent with an aggregated list but does not establish where it came from.
Those findings indicate possible capabilities. Strings alone cannot establish that a method works, that a listed proxy is reachable or controlled by the operator, or that any attack was launched. No attack volume or victim outage can be inferred from this material.
The intended traffic path nevertheless explains the camera's role. If the chain succeeds, the compromised device can send traffic under remote instruction. A proxy may relay some traffic onward. The address visible to a target may therefore belong to a compromised device or relay, while the person directing it remains elsewhere.
Look for the sequence in your own telemetry
The most useful detection opportunities connect events across the chain. A request to a management interface becomes more concerning when it is followed by a download, executable creation and recurring outbound contact.
| Stage | What to investigate | What it does not prove by itself |
|---|---|---|
| Initial access | Unexpected requests to a device's management interface or unfamiliar remote logins | That the request succeeded |
| Delivery | A camera or recorder fetching an executable from an unfamiliar destination | That the downloaded file ran |
| Execution | A new process launched from a temporary or shared-memory directory | That the process belongs to this scenario |
| Persistence | New startup entries, hidden executable copies or watchdog processes | That the mechanism survives a reboot |
| Control and traffic | Repeated external check-ins followed by unusual outbound connections or traffic | The operator's identity or a confirmed DDoS attack |
Correlate network records with device logs and process information where available. Compare destinations and protocols with the device's expected operation. Firmware updates and legitimate remote management can also create outbound traffic, so a single request to an unfamiliar host needs context.
YARA example for static triage
The source's sample-specific rule relied on identifying strings that are withheld here. The following generalized example instead combines the ELF header, registration text, process inspection and a cron-startup string described in the analysis:
rule Linux_Bot_Registration_Persistence_Triage
{
meta:
description = "Generic static triage; not family attribution"
author = "Cypho Research Team"
strings:
$register = "REGISTER linux" ascii
$status = "/proc/self/status" ascii
$tracer = "TracerPid" ascii
$memory = "/proc/meminfo" ascii
$startup = "@reboot" ascii
condition:
uint32(0) == 0x464c457f and all of them
}
This is a new triage example, not a validated signature for the original sample. Requiring all strings makes the condition explicit, but can miss a variant that constructs or encodes them. A match still needs analyst review and comparison with benign files. The integer read and string-set condition follow the YARA rule syntax.
Suricata example for chunked delivery
This generalized rule looks for the retained query structure without using a real host or endpoint name:
alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"Possible chunked executable delivery - triage"; flow:established,to_server; http.uri; content:"&n=4096"; fast_pattern; pcre:"/[?&]arch=[^&\s]+&o=[0-9]+&n=4096(?:&|$)/"; sid:1000001; rev:1;)
http.uri selects the request URI for inspection, as described in the Suricata HTTP keyword documentation. This example expects the shown parameter order and a decimal offset. It does not inspect the downloaded bytes or prove that a response contains malware. It also needs visible HTTP; encrypted traffic cannot be matched this way without appropriate inspection.
Treat a hit as a starting point. Look for repeated requests with advancing offsets, a completed file transfer and execution on the same host. Tune against legitimate download/update traffic and choose an unused local SID before deployment. An anonymized domain string is not a substitute for a real network indicator, so no placeholder-domain blocking rule is included.
Break the chain at the device boundary
Start with exposure. Remove unnecessary port forwards, disable automatic port mapping where it is not needed and put remote administration behind a controlled access path. Keep firmware current and replace devices that can no longer receive security updates. Change default credentials and disable unused remote-access services.
Separate cameras and recorders from other systems. Limit their outbound connectivity to the destinations and services they need. A vulnerable device that cannot retrieve an arbitrary payload or reach a control service gives an attacker fewer opportunities to complete this chain.
If a device appears compromised, isolate it and review the available evidence before restoring it through a trusted recovery process. Address the entry point as well as the suspected malware. A reboot alone does not establish that the device is clean, and leaving the original exposure in place permits another attempt.
For the potential DDoS target, prepare upstream filtering and service-level controls before an incident. Blocking individual sources may help during response, but a changing set of compromised devices and relays limits what source blocking can achieve.
The recovered toolkit shows how an operator tries to connect an exposed service to payload delivery and remote control. Each transition is also a place to interrupt the attempt. Removing unnecessary exposure, restricting downloads and investigating unexpected execution can stop a device from reaching the next stage.