All Posts

Behind the WAF: NeTiS and Cloudflare-Aware C2 Beaconing (Part 1)

Static analysis of a MIPS ELF bot that stages cross-architecture payloads, kills rival implants, and prepares an encrypted control channel
Zenyard
7
min read
May 6, 2026
This analysis was generated by Zenyard Agent without human-in-the-loop input and is presented as raw output, as produced by the system. However, in real reversing workflows, the agent is designed to augment the researcher, not replace them. The goal of this experiment is to demonstrate how far a purpose-built AI agent for reversing can go when applied to real-world samples, and the value it can deliver in helping researchers shorten time to insight.

This first part examines the NeTiS sample’s role as a Gafgyt/BASHLITE-derived Linux IoT botnet implant: its multi-architecture propagation model, downloader orchestration, process masquerading, competitor suppression, and trap-based anti-analysis behavior. The focus is on how the sample gets resident, spreads across heterogeneous IoT targets, and shapes the local environment before the encrypted C2 and Cloudflare-aware beaconing logic come into play.

Key Judgments

·       NeTiS extends established Gafgyt/BASHLITE tradecraft with a propagation model that stages 12 payload names across 9 architecture families, allowing one infected device to seed heterogeneous IoT fleets.

·       The implant uses a runtime-supplied command-and-control endpoint and a length-prefixed encrypted TCP protocol, which reduces the value of static blocklists and shifts detection toward protocol fingerprints and execution behavior.

·       The malware parses and reuses cf_clearance cookies inside browser-mimicking HTTP requests, enabling operators to place tasking or staging behind Cloudflare-gated infrastructure while making the traffic look less like a bot.

·       The bot increases dwell time on constrained devices by killing competing processes, masquerading as httpd, and dropping staged binaries into standard writable locations such as /tmp and /var.

·       Anti-analysis is built into normal execution. The initialization path installs a SIGTRAP handler, drives a trap-based state machine, and routes system interaction through function-pointer tables rather than stable call sites.

Overview

NeTiS is a Linux IoT botnet implant in the Gafgyt/BASHLITE lineage. The analyzed sample is a MIPS big-endian ELF recovered from an embedded device and built to participate in distributed denial-of-service operations while propagating architecture-specific binaries across routers, DVRs, IP cameras, NAS devices, and other embedded Linux targets.

Zenyard Agent produced this analysis from a raw MIPS ELF binary and Ghidra-derived static artifacts, with no prior context or labeling provided and no human analyst involvement. The sample self-identifies through an embedded taunting banner containing the name “NeTiS,” carries a set of 12 payload filenames spanning 9 architecture families, and implements downloader logic that cycles through  wget, curl, ftpget, tftp, and busybox to maximize install success on stripped-down firmware builds. The embedded profane banner is reproduced verbatim only where needed as a clustering artifact and indicator, not as Zenyard’s language.

What makes this sample worth a full technical write-up is not the family label. It is the way familiar Gafgyt mechanics are combined with more modern operator conveniences: encrypted control traffic, runtime infrastructure assignment, browser-shaped HTTP beaconing, and cf_clearance reuse layered onto an implant still optimized for noisy botnet scale.

Technical Findings

Initialization and execution flow

The sample does not rely on a heavyweight packer. Its execution flow is dominated instead by staged initialization, process control, downloader orchestration, and fan-out across multiple target architectures. Early in execution, the implant performs one-shot environment setup guarded against re-entry. That logic initializes internal communication state, resets transient structures, and prepares the bot for long-running daemonized operation. The recovered setup code also imposes a 2 MB-aligned stack-related boundary that is consistent with avoiding out-of-memory triggers on resource-constrained devices, although the static evidence shows the limit exists rather than the developer’s explicit intent.

From there, the core propagation path is straightforward. The malware derives or receives a C2 or staging location at runtime, selects a target binary name based on platform, and attempts download-and-execute using whatever transfer utility exists on the device. The sequence is intentionally redundant:

for tool in [wget, curl, ftpget, tftp, busybox]:
    if present(tool):
        download(target_binary, writable_dir)
        chmod +x(target_binary)
        exec(target_binary)
        break

The writable directories are exactly the places defenders would expect on embedded Linux systems: /tmp, /var, /mnt, /root, /boot, and /data/local/tmp.  The payload names embedded in the sample are main_x86, main_x86_64, main_mips, main_mipsel, main_arm, main_arm5, main_arm6, main_arm7, main_ppc, main_m68k, main_sh4, and main_spc.  That is 12 payload names covering 9 architecture families if the ARM variants are grouped together. This single MIPS implant is therefore a propagation hub, not a universal binary.

Once resident, the process daemonizes and renames itself to blend into appliance workloads. The primary masquerade string is httpd, with additional names such as telnetd, dropbear, encoder, and system available from an embedded table. On stripped-down firmware where process listings are sparse and operators rely on familiar service names, that disguise is enough to buy time.

The supplied function naming included set_persistence_registry_values, but that label is analytically wrong for a Linux ELF. The code is better understood as writing internal configuration slots that preserve C2 and startup-related state for later reuse. The important fact is not the decompiler label. The important fact is that the sample stores control data redundantly and sets flags consistent with autostart, respawn, and network persistence behavior elsewhere in the execution path.

Anti-analysis techniques

NeTiS treats anti-analysis as part of normal execution. The most explicit mechanism is a four-stage initialization state machine that installs signal handlers, zeroes status structures, and then deliberately triggers a trap instruction path that becomes unstable under debugger control. In a normal run, the malware’s own SIGTRAP handler absorbs the event and execution continues. Under interactive debugging, the trap is surfaced to the analyst instead, interrupting or derailing the session.

This matters because the trap path is wired into initialization. Analysts cannot simply skip “the anti-debug function” without also skipping setup required for later behavior. That design raises the cost of dynamic inspection on real hardware and on emulated appliance images.

The sample also hides intent by routing system interaction through global function-pointer tables rather than stable imported call sites. On ELF malware that already runs on minimal systems with reduced symbol visibility, this pushes more recovery work onto the analyst. String protection is lighter but still deliberate. Several attack identifiers are XOR-encoded with key 0x2E, including strings associated with Source Engine traffic and completion markers, which removes easy wins from naive static string extraction.

A second layer of defense is operational rather than analytical. The implant enumerates running processes and kills unapproved ones with SIGKILL, while exempting its own process and honoring a runtime-populated allowlist. That is competitor suppression, but it also functions as environment shaping: it removes rival implants, interrupts watchdogs or admin tooling that might expose instability, and reduces the number of local artifacts analysts can correlate after infection.

Part 1 Conclusion

Part 1 shows NeTiS as a propagation-focused IoT implant that does not need a heavyweight packer to complicate analysis. Its strength is in redundancy and fit-for-purpose execution: multi-architecture staging, fallback downloader logic, writable-directory deployment, process masquerading, competitor suppression, and trap-based initialization all support long-running operation on constrained embedded devices.

Part 2 continues with the sample’s stream-cipher-based C2 protection, Cloudflare-aware cf_clearance reuse, DDoS tasking behavior, attribution limits, detection opportunities, IOCs, and YARA hunting logic.

Annex A: Indicators of Compromise

Indicator Type Value Description
Static string Self Rep Fucking NeTiS and Thisity 0n Ur FuCkInG FoReHeAd We BiG L33T HaxErS Variant self-identification and clustering pivot; reproduced verbatim as an IOC, not Zenyard’s language
Static string cf_clearance= Cookie parsing logic used in the HTTP beacon flow
Static string expand 32-byte k Stream-cipher family anchor in the encryption routine
Static blob c2 d2 53 6d 3f 91 7e 4a d7 65 2c b8 e2 44 9f 1a f1 c3 ab 89 91 72 5d 3e d3 a8 b6 c4 96 1c 2e 7f Hardcoded 256-bit encryption key
Session constant 0x0B6F0B73 C2 session magic in the connect header
Session header 0x73c0 Control-channel connect header
Port 5632/TCP Primary command channel
Port 26999/TCP Secondary encrypted data channel noted in analysis
Port 11211/TCP Memcached-style probe traffic
HTTP artifact Content-Length: 10485760 Oversized POST flood template
HTTP artifact PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n HTTP/2-preface flood or confusion traffic
Network string stats\r\n Memcached probe string
Network string M-SEARCH * HTTP/1.1 SSDP amplification traffic
Filename cluster main_mips, main_mipsel, main_arm, main_arm5, main_arm6, main_arm7, main_x86, main_x86_64, main_ppc, main_m68k, main_sh4, main_spc Multi-architecture propagation set
Filesystem path /root/dvr_gui/, /root/dvr_app/, /anko-app/, /data/local/tmp Embedded-device targeting and staging indicators
Behavioral Process rename to httpd after daemonization Host-level masquerade behavior

Annex B: YARA Hunting Rules

This rule is scoped to the NeTiS-labeled Gafgyt variant and adds the hardcoded encryption key as an alternate anchor. That keeps the rule useful even if a future build strips the taunting banner but preserves the same crypto material and surrounding execution artifacts.

rule Linux_Gafgyt_NeTiS_Variant
{
    meta:
        description = "Detects the NeTiS-labeled Gafgyt/BASHLITE IoT bot variant"
        author = "Zenyard Agent"
        date = "2026-03-21"

    strings:
        $anchor_id = "Self Rep Fucking NeTiS and Thisity 0n Ur FuCkInG FoReHeAd We BiG L33T HaxErS" ascii
        $anchor_key = { C2 D2 53 6D 3F 91 7E 4A D7 65 2C B8 E2 44 9F 1A F1 C3 AB 89 91 72 5D 3E D3 A8 B6 C4 96 1C 2E 7F }

        $ctx1 = "cf_clearance=" ascii
        $ctx2 = "expand 32-byte k" ascii
        $ctx3 = "stats\\r\\n" ascii
        $ctx4 = "M-SEARCH * HTTP/1.1" ascii
        $ctx5 = "main_mipsel" ascii
        $ctx6 = "main_arm7" ascii
        $ctx7 = "main_x86_64" ascii
        $ctx8 = "/root/dvr_gui/" ascii
        $ctx9 = "/anko-app/" ascii

    condition:
        uint32(0) == 0x464C457F and
        filesize < 2MB and
        any of ($anchor_*) and
        4 of ($ctx*)
}

Join Our Newsletter

This field is required
Thank you for subscribing!
Oops! Something went wrong while submitting the form.
By subscribing to our newsletter, you consent to the collection and use of your information as described in this Privacy Policy.