AdaptixC2: Fingerprinting an Open-Source C2 Framework at Scale

C2, Research, Threat Intelligence

Executive Summary

  • AdaptixC2 is an open-source post-exploitation C2 framework whose default configuration ships branded HTTP headers (Server: AdaptixC2, Adaptix-Version: v1.2) on every unauthenticated request, making deployed servers trivially identifiable from passive scanning.
  • As of 16 June 2026, Censys tracks 412 web properties across 236 hosts running AdaptixC2 with default or near-default settings.
  • Three beacon listener clusters (Hivelocity, M247, PSB Hosting) – each spanning multiple IPs across adjacent subnets with identical default TLS certificates – suggest individual operators running coordinated, redundant callback infrastructure.
  • One host (2.26.229[.]254) was actively serving payloads, including a Linux installer with 12 persistence mechanisms and Russian-language comments.
  • Operators who modify the Server header to evade detection leave the default 404 page body intact. Querying on both signals catches this class of evasion.
  • All detections are available in Censys via the THREAT-0210 threat label.

AdaptixC2 is an open-source post-exploitation framework with a default configuration that makes deployed servers trivially identifiable from passive scanning. As of 11 June 2026, Censys tracks 390 web properties — each a distinct IP or hostname and port pair — across 217 hosts running AdaptixC2 with default or near-default settings. This includes three distinct beacon-listener clusters that suggest coordinated multi-server deployments and one host serving implants from an open directory. The framework ships branded HTTP headers on every unauthenticated request, so the first passive probe identifies the framework without authentication or endpoint knowledge.

Not all of these hosts represent malicious activity. Some are almost certainly authorized red team infrastructure. What we can say from passive scanning is that the infrastructure exists, it’s detectable, and defenders who understand the fingerprint can make informed decisions about what to block or monitor.

What Is AdaptixC2?

Post-exploitation frameworks provide the tooling operators use after gaining an initial foothold: maintaining access, running commands, moving laterally, and collecting data from compromised systems.

AdaptixC2 is a publicly available post-exploitation framework written in Go (teamserver) and C++/Qt (GUI client). It’s designed for red team engagements, though like most offensive frameworks it sees use in unauthorized operations as well. The project is at v1.2 and has less public analysis coverage than older frameworks like Cobalt Strike, Havoc, or Sliver.

The framework ships two agent families. In C2 terminology, an agent is an implant that runs on a compromised host and checks in with the operator for tasking, not an AI agent. The Beacon agent is a C++ implant supporting Beacon Object File (BOF) execution on Windows, Linux, and macOS; the Gopher agent is a Go implant with async BOF support across the same platforms. The framework implements listeners as loadable plugins (“extenders”) covering HTTP/S, DNS/DoH, SMB named pipes, and raw TCP transports. The teamserver exposes a full REST and WebSocket API for operator control — credential management, agent tasking, screenshot capture, tunnel management, and multi-operator collaboration.

What makes AdaptixC2 detectable at scale is a design choice in profile.yaml: the error block sets Server: AdaptixC2 and Adaptix-Version: v1.2 on every unmatched route. They appear on any request that doesn’t match the configured endpoint — no authentication required, no prior knowledge of the endpoint path needed. Passive scanners see the banner on the first probe.

Architecture

Teamserver

The teamserver is a single Go binary. At startup it loads profile.yaml to configure the network interface, port, endpoint path, password, and HTTP response behavior. It then generates or loads a self-signed TLS certificate, loads extender plugins from disk, starts an HTTPS server via gin, and restores state from a SQLite database.

The router hierarchy in connector.go defines four distinct groups under the configured endpoint (default /endpoint):

Anything outside the /endpoint prefix, and any path under /endpoint that isn’t registered, hits the NoRoute handler, which returns the configured error response — the 404 page with the branded headers.

Authentication Model

Authentication is two-tier. The /login endpoint takes a JSON body with a username and password and returns a short-lived JWT access token (12 hours) and a long-lived refresh token (168 hours, or seven days). Each startup generates fresh JWT signing keys via crypto/rand and signs tokens with HS256.

OTP tokens gate WebSocket upgrades and one-time file transfers. An authenticated operator calls /otp/generate with a JWT access token to create a 64-character hex OTP. These tokens are single-use — calling the corresponding endpoint twice with the same token fails.

Extender System

Listeners compile to Go shared libraries (.so files) that load at runtime. When a listener starts, it can register routes on either the api_group (JWT-protected) or the public_group (unauthenticated). This is the correct design for agent callbacks — agents don’t carry operator credentials, so their check-in endpoints can’t require JWT auth.

In practice, the HTTP beacon listener (BeaconHTTP extender) doesn’t use the teamserver’s public endpoint group at all. It starts its own separate HTTP server on the operator-configured callback port, independent of the teamserver:

This is why the Censys scan finds two distinct populations — teamservers (typically port 4321, operator API) and beacon listeners (high ports like 43211, agent callbacks). Both surfaces return the default 404 page, but they serve different purposes.

The Fingerprint

Detection relies on two independent signals from the default configuration, both visible without authentication.

The headers. The default profile.yaml sets these headers in HttpServer.error.headers:

HttpServer:
  error:
    status: 404
    headers:
      Content-Type: "text/html; charset=UTF-8"
      Server: "AdaptixC2"
      Adaptix-Version: "v1.2"
    page: "404page.html"

Because this is the error handler, not a specific route, these headers appear on any path that doesn’t match the configured endpoint. Even when an operator uses the default /endpoint path, API access still requires a valid JWT. But any request to /, /robots.txt, /favicon.ico, or any arbitrary path returns a 404 with Server: AdaptixC2 in the response.

The 404 body. The default 404page.html contains:

<h1>AdaptixC2 404</h1>
<p>You need to enter the correct connection details.</p>

This string is specific enough to use as a standalone indicator when an operator has changed the response headers.

Combined query:

host.services.endpoints.http.headers: (key: "server" and value: "AdaptixC2") or host.services.endpoints.http.headers: (key: "adaptix-version" and value: "v1.2")

Follow Along in Censys

Body-only fallback (catches header-modified deployments):

host.services.endpoints.http.body: "You need to enter the correct connection details."

DNS listener (tertiary signal). The BeaconDNS extender sets AA=true on every response and returns TXT "OK" for any query that doesn’t match its beacon protocol format — specifically, any query with fewer than five labels. Censys captures this as a DNS service with version: "OK" on UDP/53.

host.services.dns.version: "OK" and host.services.protocol = "DNS"

This query returns around 30 hosts globally. Most are legitimate DNS servers hiding their BIND version with a custom string, so the signal needs cross-referencing, either against the Adaptix C2 threat label or via active probe. Querying a random short hostname returns TXT "OK" (what Censys captures), while a query formatted as a beacon-check-in (five or more dot-separated labels in the BeaconDNS protocol format) returns A 127.0.0.1 on a genuine listener. Default TTLs jitter between 10 and 70 seconds). On hosts that aren’t running BeaconHTTP, this is the only passive signal.

Discovery

We started from the source code. AdaptixC2’s profile.yaml and 404page.html are both in the public GitHub repository — the fingerprint follows directly from reading them, no prior infrastructure exposure needed. We confirmed the expected headers against live deployments and ran both queries against Censys.

The combined scan returned 236 unique hosts. The default configuration is explicit enough that a single query captures most of the population. The harder work was making sense of what those hosts represent.

Censys ARC Perspective

The hosts break down across a range of ASNs and geographies, with clustering that suggests organized deployment.

Port Distribution

PortCountNotes
432146Default teamserver port
4321115Common beacon listener port
8080 / 8443 / 8989~3 eachNon-default teamserver ports
Various (1337, 9999, 8562, etc.)50+Operators choosing non-standard ports

The 46 hits on port 4321 confirm that many operators deploy with the default configuration and leave the port unchanged. The 15 hits on 43211 concentrate in two of the three beacon listener clusters described below.

Top ASNs

ASNNameHostsNotes
AS29802HVC-AS (Hivelocity)13Beacon listener cluster; multiple active AdaptixC2 servers observed across 23.227.203.0/24, 46.21.153.0/24
AS9009M2479Beacon listener cluster; 38.132.122.x, 146.70.87.x
AS132203Tencent7Port 4321; servers hosted in HK and CN Tencent Cloud regions
AS9081PSB Hosting6Beacon listener cluster; 45.155.69.x,
AS20473Vultr5Geographically spread

Geographic Distribution

CountryHosts
US38
HK18
CN14
NL12
SG8
DE8
FR5
RU3

The US count is high partly because Hivelocity is a US-based provider, and those hosts are almost certainly beacon listeners rather than teamservers. The Hong Kong and China hosts cluster on Tencent Cloud, consistent with East Asia-based operators or operators targeting that region.

Notable Hosts

IPPortNotes
185.190.142[.]664321Contabo FR; RDP (3389) also open; certificate O=OpenClaw on port 443
89.125.255[.]294321RoyaleHosting NL; self-signed certificate with C=RU, ST=as, O=as
38.147.173[.]248562Lucidacloud HK; port 50050 also open
156.225.22[.]2011337cognetcloud HK; non-standard port
202.95.8[.]92 / .97 / .984321CTG Server HK; three sequential IPs

The cert on 89.125.255[.]29 stands out: C=RU, ST=as, O=as — “as” filled in twice when prompted for state and organization. 185.190.142[.]66 has both AdaptixC2 on port 4321 and RDP open on 3389, which suggests an operator working directly on the teamserver box rather than managing it remotely through a jump host.

38.147.173[.]24 runs AdaptixC2 on port 8562 and also has port 50050 open. Port 50050 is the default Cobalt Strike teamserver port. We can’t confirm from a passive scan that a live Cobalt Strike instance is present — port 50050 could be in use for something else, or the process may not be running at scan time. The combination suggests an operator working with multiple offensive tools.

Infrastructure Clusters

The most informative finding from the Censys scan isn’t the individual hosts — it’s three beacon listener clusters that likely represent single operators running multiple callback servers.

These are beacon listeners, not teamservers. A teamserver needs to be reachable by the operator for API access — typically a single port on a fixed IP. A beacon listener only needs to be reachable by agents on compromised hosts. Operators often run multiple beacon listeners across different providers, ports, and geographies for redundancy and to complicate takedown. Shared TLS certificate patterns tie these clusters together.

  • Hivelocity cluster. Eight or more IPs across two subnets (23.227.203.0/24 and 46.21.153.0/24) all serving the AdaptixC2 404 page on randomized high ports (42215, 42235, 43211, 43435, 43655). Every host in this cluster uses the default OpenSSL self-signed certificate: C=AU, ST=Some-State, O=Internet Widgits Pty Ltd. That certificate is what OpenSSL generates when you run openssl req and accept all defaults. Its presence across eight IPs on two adjacent subnets from the same provider strongly suggests a single operator who stood up a batch of callback servers without customizing the TLS configuration.
  • M247 cluster. Eight IPs across two subnets (38.132.122.x and 146.70.87.x), almost all on port 43211. Same default OpenSSL certificate as the Hivelocity cluster. M247 is a popular choice for red team and grey-area infrastructure. The shared port and shared cert pattern point to the same operator or the same deployment tooling.
  • PSB Hosting cluster. Six IPs across two subnets (45.155.69.x and 185.242.245.x) on randomized ports in the 42xxx44xxx range. Smaller than the other two clusters but the same behavioral signature: adjacent IPs, randomized high ports, default cert.

The sequential or near-sequential IP allocation within each cluster suggests these were provisioned at the same time, probably from the same provider account. Operators who spin up beacon listeners in bulk tend to take consecutive IPs because that’s what you get when you order multiple VMs in the same region in the same session. Whether any of these are authorized engagements, passive scanning can’t say — the clustering pattern describes how the infrastructure was built, not what it was used for.

A Live Deployment: 2.26.229[.]254

The clearest evidence of an active operation in this dataset is 2.26.229[.]254. It ran AdaptixC2 listeners on ports 4433 (BeaconHTTP) and 4455 (GopherTCP) and simultaneously served payloads over an open HTTP directory on port 7000. No authentication required — the files were publicly accessible to anyone who connected.

Payloads

FilenameSHA256Type
install.sh479b7abd5df2f6ab3de8c32a36478c15012dbc8217f9fa825fd4b9cb7e9b8d13Linux persistence installer
timesync.binfb1f4f5a4ef76960577462634f4a104fb307e161fc2791b9231a07a2c751becaGopher agent (ELF x64)
svhost.exe06b13dfd84493b01a020eecdabff6308b5b790ed4cd4c7a96a30ae6be1ca325dBeacon (Windows x64)
svc_timesync.x64.exe7d35d687ae8d4056e394905e9f8962512e6d55ff98664ed1facee6554a565624Beacon (Windows x64)
agent.x86.exe51fba778dae6f108f7afa800bdb7745e6a0f6d2630a37ecc84c1d4a1609f9692Beacon (Windows x86)

timesync.bin is a Gopher agent (ELF x64) for Linux. The three .exe files are Windows Beacon implants in both x64 and x86 variants. A legitimate VC_redist.x86.exe was also present, likely as a runtime dependency.

install.sh: Linux Persistence Installer

The installer presents itself as a routine package update — fake apt output, fake kernel unpacking — while running the actual installation in a background subshell. Russian-language comments throughout the script indicate the author’s working language. It deploys timesync.bin to /usr/local/lib/systemd/timesync and establishes 12 independent persistence mechanisms before shredding itself.

  1. Hidden user — creates systemd-timesync (UID 9999) with a random password and a hardcoded operator SSH key in authorized_keys. SSH access survives agent removal.
  2. Fake systemd service — overwrites systemd-timesyncd.service to execute the beacon, masquerading as the NTP sync daemon.
  3. Three cron jobs at 5-minute, 10-minute, and 15-minute intervals across separate crontab locations. Any one survivor restarts the agent.
  4. Initramfs hook — drops a script into /etc/initramfs-tools/scripts/init-premount/ and rebuilds the initrd via update-initramfs. The agent runs before the root filesystem mounts.
  5. GRUB init replacement — appends init=/usr/local/lib/systemd/systemd-persistence.sh to GRUB_CMDLINE_LINUX_DEFAULT and rebuilds grub.cfg. The kernel hands PID 1 to the attacker’s script instead of systemd on next boot. This survives service removal, cron purges, and user deletion.
  6. LD_PRELOAD library — writes and compiles libsystemd-override.so, registered in /etc/ld.so.preload. A GCC constructor causes every dynamically linked process to fork and exec the beacon. Removing the binary alone is not sufficient.
  7. Kernel thread masquerading — two beacon instances launched as [kworker/0:0] and [kthreadd] via exec -a, blending into kernel thread entries in ps output.
  8. Integrity monitormonitor.sh running as [kworker/u:0], checking every 60 seconds and re-downloading the agent from hxxp://2.26.229[.]254:7000/timesync.bin if it’s absent.
  9. Shell profile injection — appends agent launch to .bashrc and .profile for every user in /home/* and root.
  10. DNS hijacking — sets 2.26.229[.]254 as the primary systemd-resolved DNS server. All DNS queries route through the C2 host.
  11. eBPF hook — if bpftool is present, loads a kprobe on sys_getdents64 returning 0, attempting to hide processes from directory listings.
  12. Systemd timersystemd-timesync.timer firing two minutes after boot and every 10 minutes thereafter.

Cleanup: zeroes all files under /var/log, clears bash history, and shreds the installer with shred -u.

The combination of GRUB init replacement and LD_PRELOAD means the implant survives most detection-and-removal workflows short of a full OS reinstall. The eBPF hook — loading a kprobe on sys_getdents64 to zero out process directory entries — aims to make running processes invisible to standard userspace tools, adding a kernel-level hiding layer on top of the process name masquerading in items 7 and 9.

Beacon Config (Extracted via Static Analysis)

The Agents section below covers config extraction from Windows beacon binaries. The three .exe samples from 2.26.229[.]254 all call back to the same listener:

  • C2: hxxp://2.26.229[.]254:4433
  • Callback URIs: /api/v1/status, /updates/check.php, /content.html
  • Custom header: X-ISS
  • User-Agent: Mozilla/5.0 (Windows NT 6.2; rv:20.0) Gecko/20121202 Firefox/20.0
  • RC4 key: 1baccab4cbd2b84f6bc54bf8e6551f93
  • Sleep: 10 seconds

The API Surface

The teamserver’s REST API is spelled out in server.go and connector.go. Here’s what’s behind it.

The authentication flow:

  1. Operator calls POST /endpoint/login with a JSON credential body. Server returns access token (12hr) and refresh token (168hr).
  2. Operator attaches the access token as Authorization: Bearer <token> on all subsequent requests.
  3. Before opening a WebSocket channel, operator calls POST /endpoint/otp/generate to get a one-time token, then upgrades via GET /endpoint/connect?otp=<token>.
  4. Expired access tokens are refreshed via POST /endpoint/refresh with the refresh token.

Authentication and session:

EndpointMethodAuthPurpose
/loginPOSTNoneIssue access and refresh tokens
/refreshPOSTNoneRotate access token using refresh token
/otp/generatePOSTJWTGenerate OTP for WebSocket or file transfer
/otp/upload/tempPOSTOTPUpload a file for agent tasking
/otp/download/syncGETOTPDownload a file from the server
/connectGET (WS)OTPOpen operator WebSocket channel
/channelGET (WS)OTPOpen secondary channel (terminal/build/tunnel)
/syncPOSTJWTSynchronize state for a connecting operator

Agents and tasks:

EndpointMethodPurpose
/agent/listGETList all registered agents
/agent/generatePOSTBuild and return an implant binary
/agent/command/executePOSTIssue a command to an agent
/agent/command/rawPOSTSend raw task payload
/agent/command/filePOSTUpload a file for agent tasking
/agent/task/listGETList completed tasks
/agent/task/cancelPOSTCancel a pending task

Infrastructure and collection:

EndpointMethodPurpose
/listener/createPOSTStart a new listener
/listener/listGETList all configured listeners
/creds/listGETList harvested credentials
/creds/addPOSTAdd credential entries
/screen/listGETList captured screenshots
/screen/imageGETRetrieve a screenshot image
/tunnel/start/socks5POSTStart a SOCKS5 proxy tunnel
/tunnel/start/lportfwdPOSTStart a local port forward
/download/listGETList files pulled from agents
/targets/listGETList tracked target hosts

What Is and Isn’t Exposed Without Authentication

The teamserver management API is reasonably secured when the password is set correctly. The unauthenticated surface on the teamserver port is limited:

EndpointAuthWhat it exposes
ANY /<path>NoneServer: AdaptixC2 and Adaptix-Version: v1.2 in headers; 404 body with branding
POST /endpoint/loginNoneReturns tokens if password correct; 404 otherwise
POST /endpoint/refreshNoneReturns new access token if refresh token valid; 404 otherwise

All 50+ data endpoints require a valid JWT access token. There’s no unauthenticated path to agent lists, credentials, screenshots, downloads, or operator sessions through the teamserver API.

The OTP-gated endpoints (/connect, /channel, /otp/upload/temp, /otp/download/sync) require a valid OTP generated by an authenticated operator. OTP tokens are single-use and expire quickly.

Error Response Behavior

Failed authentication attempts — wrong password, missing token, expired token — all return HTTP 404 with the same Server: AdaptixC2 branded response. The server doesn’t distinguish between “wrong password” and “path doesn’t exist” in its response to the client. This is intentional: it prevents an attacker from confirming which endpoint paths are valid by observing different status codes.

The side effect is that the Server: AdaptixC2 header appears on every response, including failed auth attempts. An attacker probing the server learns the framework identity from the first probe, before making any authentication attempts.

Agents

AdaptixC2 ships two distinct agent families.

Beacon is a C++ implant targeting Windows, Linux, and macOS. Its primary capability beyond standard C2 tasks is BOF (Beacon Object File) execution — a technique popularized by Cobalt Strike that lets operators run compiled C code in-process without touching disk. This makes Beacon harder to detect for endpoint tools focused on child process creation. The default watermark embedded in config.yaml is be4c0149.

Beacon supports multiple transport protocols through its extender system:

  • BeaconHTTP: HTTP/S callback with configurable URIs, headers, and User-Agent rotation
  • BeaconDNS: DNS-based callback channel. The listener replies with TXT "OK" to any short-label or unrecognized query and sets the authoritative-answer bit on every response, which Censys surfaces as dns.version: "OK" — a usable passive fingerprint on its own.
  • BeaconSMB: Named pipe communication for peer-to-peer pivoting within compromised networks
  • BeaconTCP: Bind-style TCP channel for internal pivots

The transports differ in external visibility. BeaconHTTP, BeaconDNS, and BeaconTCP all expose a socket reachable by any internet scanner. BeaconSMB has no external footprint at all — the teamserver-side Start() for the SMB extender is a no-op. The named pipe lives on a victim machine already running another beacon, which acts as an SMB relay for the rest of the network. An SMB-only deployment is invisible to Censys or any other internet scanner.

Gopher is a Go implant covering the same platforms. It supports async BOF execution, meaning tasks run in a background goroutine and the agent continues polling without waiting for completion. The default watermark is 904e5493. Gopher compiles to a statically linked binary with no external runtime dependency, which makes Linux deployment straightforward.

Both agents use watermarks — short hex strings baked into the compiled binary — to associate callbacks with a specific build. The defaults (be4c0149, 904e5493) are identifiable in memory or binary dumps if an operator doesn’t change them.

Agent Beacon Protocol

When a BeaconHTTP listener starts, it runs its own HTTP server on the configured callback port, completely separate from the teamserver. Agent callbacks don’t go to port 4321 — they go to the listener’s dedicated port. That’s why the Hivelocity cluster (all high ports, no operator API) looks different from individual teamservers (single port, full REST API).

On check-in, the agent sends a request to the configured URI path with a custom header containing a base64-encoded, RC4-encrypted “beat” blob. The listener decrypts the beat using the pre-shared encrypt_key (32 hex chars configured when the listener is created) and extracts the agent type, agent ID, and beacon data. The request body contains any outgoing task data from the agent. The response body contains pending tasks for the agent, embedded in the configured page-payload template string.

The RC4 key is specific to each listener instance and is set by the operator at listener creation time. Agents compiled for a given listener embed this key. This provides meaningful separation between the callback protocol and the teamserver API.

Beacon Config Extraction

Beacon implants embed an RC4-encrypted configuration blob in the .rdata section of the compiled PE. MinGW builds (the default toolchain) place it at the start of .rdata. The layout, derived from the Go-side serialization in pl_main.go and the C++ parser in AgentConfig.cpp:

[4-byte LE: ciphertext_size]
[ciphertext_size bytes: RC4 ciphertext]
[16 bytes: RC4 key]

Decryption requires no external keys — the RC4 key is stored in the binary itself. Slice the ciphertext using the 4-byte size field, use the trailing 16 bytes as the key, and decrypt. The first four bytes of the plaintext are the agent watermark (0xBE4C0149 for Beacon, 0x904E5493 for Gopher). C2 host strings follow as length-prefixed fields, each immediately followed by a 4-byte port value.

Because the number of header fields between the watermark and the first host string varies across build configurations, the most reliable extraction approach scans the plaintext for strings that match IP or hostname patterns rather than parsing at fixed offsets. Non-MinGW toolchains may place the blob at a non-zero offset within .rdata; a 4-byte-aligned sliding search over the section recovers it in those cases.

Any Beacon implant recovered from an endpoint, pulled from a staging server, or retrieved from a sandbox can be parsed for its C2 server, callback URIs, and the listener RC4 key — without executing the binary. The 2.26.229[.]254 samples above demonstrate this: three independently compiled executables, all pointing to the same listener config.

Third-Party Extensions: KharonHTTP

AdaptixC2’s extender system supports loading third-party listeners as Go plugins. KharonHTTP (github.com/entropy-z/Kharon) is one — we found it running on two hosts in this dataset.

KharonHTTP implements a malleable C2 profile system — operators configure URI paths, response headers, User-Agent patterns, request body prepend/append wrappers, and cookie or parameter encoding via a JSON profile. This is similar to Cobalt Strike’s Malleable C2 profiles: a single listener binary that takes on different network personas depending on operator configuration. KharonHTTP uses a custom block cipher (“LokyCrypt”) — an 8-byte block, 16-round Feistel construction with XOR post-processing — instead of AdaptixC2’s default RC4.

We found KharonHTTP active on two hosts. 1.14.172[.]47 ran two KharonHTTP listeners on ports 56743 and 56744. 104.236.230[.]184 ran one on port 443. The callback domain llmscience.top was extracted from the listener config on 1.14.172[.]47. The hardcoded agent type identifier is c17a905a.

One behavioral note for defenders running active scans: KharonHTTP returns the literal string "Bad Request" in the response body when the Host header doesn’t match any configured callback. This fires before the operator’s malleable profile is consulted, so it’s consistent regardless of what profile is loaded. KharonHTTP listeners run plain HTTP by default — operators configure TLS separately — so this response is readable in cleartext even on non-standard ports.

Operator Profile

The infrastructure doesn’t suggest a single threat actor; it’s a mixed population with varying levels of operational discipline.

The three beacon listener clusters — Hivelocity, M247, PSB — show operators who understand multi-server deployment. Spinning up eight servers across two subnets and pointing agents at all of them is not a default behavior; someone made a deliberate choice to run redundant callback infrastructure. Whether those campaigns are authorized is a separate question.

The default OpenSSL certificate (C=AU, ST=Some-State, O=Internet Widgits Pty Ltd) visible across these clusters indicates operators who aren’t concerned about TLS fingerprinting — they either don’t know it’s a detection vector or don’t consider it a priority for their specific operations.

The outlier hosts show more varied configurations. 89.125.255[.]29 uses C=RU, ST=as, O=as in the certificate — someone who customized the TLS config but filled in “as” twice for state and organization. 185.190.142[.]66 carries an O=OpenClaw certificate on port 443 alongside an active AdaptixC2 instance and open RDP. The install.sh installer distributed from 2.26.229[.]254 has Russian-language comments throughout. These are observations about individual hosts, not a basis for connecting them to each other.

The three sequential CTG Server IPs (202.95.8[.]92, 202.95.8[.]97, 202.95.8[.]98), all on port 4321, were likely provisioned by the same operator. Port 4321  appeared on .92 on May 26th, .98 on May 29th, .97 appeared on May 30th: three consecutive IPs from the same provider, all coming online within a four-day window.

The “TestCoonection” variant is the most instructive signal in the dataset for detection purposes. Changing the Server header requires editing profile.yaml and restarting the teamserver — the operator made a deliberate choice to evade header-based detection. The Server value contains a consistent typo: “Coonection” with a double-o, present across multiple scans. Querying on the 404 body string still catches it.

That’s the pattern across this population: operators at varying stages of OPSEC maturity, some running defaults, some making targeted changes. The ones making targeted changes tend to address one detection vector at a time and leave others intact. That’s what makes layered detection — headers and body, passive and active — worth maintaining.

IOCs

Detection Queries

Threat label (simplest — finds all detections including evasion variants):

host.services.threats.name: "Adaptix C2" or web.threats.name: "Adaptix C2"

Follow Along in Censys

Header-based (primary):

web.endpoints.http.headers: (key: "Server" and value: "AdaptixC2")

Version-specific:

web.endpoints.http.headers: (key: "Adaptix-Version" and value: "v1.2")

Body-based (catches header-modified deployments):

web.endpoints.http.body: "You need to enter the correct connection details."

DNS listener (tertiary — requires cross-reference):

host.services.dns.version: "OK" and host.services.protocol = "DNS"

Censys threat detection: THREAT-0210 (includes body hash, header, and “TestCoonection” variant)

Representative Infrastructure

Hivelocity beacon listener cluster:

IPPortASNNotes
23.227.203[.]20543211HVC-ASDefault OpenSSL certificate
46.21.153[.]14643211HVC-ASSame certificate; randomized high ports
46.21.153[.]14843211HVC-ASSame certificate; randomized high ports

M247 beacon listener cluster:

IPPortASNNotes
38.132.122[.]14143211M247Default OpenSSL certificate
38.132.122[.]14543211M247Same certificate
38.132.122[.]16143211M247Same certificate
146.70.87[.]2343225M247Same certificate pattern
146.70.87[.]6443211M247Same certificate pattern
146.70.87[.]9643211M247Same certificate pattern
146.70.87[.]21842445M247Same certificate pattern
146.70.87[.]23743211M247Same certificate pattern

PSB Hosting beacon listener cluster:

IPPortASNNotes
45.155.69[.]10642211PSB HostingRandomized high ports
45.155.69[.]15343345PSB HostingSame pattern
45.155.69[.]17542455PSB HostingSame pattern
185.242.245[.]444355PSB HostingSame pattern
185.242.245[.]2744875PSB HostingSame pattern
185.242.245[.]12042534PSB HostingSame pattern

Notable individual hosts:

IPPortNotes
185.190.142[.]664321Contabo FR; RDP open; O=OpenClaw certificate on port 443
89.125.255[.]294321RoyaleHosting NL; C=RU, ST=as, O=as certificate
38.147.173[.]248562Lucidacloud HK; port 50050 also open
156.225.22[.]2011337cognetcloud HK
202.95.8[.]924321CTG Server HK; sequential with .97 and .98
167.17.47[.]121443 / 4321 / 53TRUNKNETWORKS-AS SG; teamserver + active DNS beacon listener (dns.version: "OK")
91.230.94[.]2354321 / 53NETRACK-AS RU; teamserver + active DNS beacon listener (dns.version: "OK")

Samples and Artifacts (2.26.229[.]254)

FilenameSHA256Type
install.sh479b7abd5df2f6ab3de8c32a36478c15012dbc8217f9fa825fd4b9cb7e9b8d13Linux persistence installer
timesync.binfb1f4f5a4ef76960577462634f4a104fb307e161fc2791b9231a07a2c751becaGopher agent (ELF x64)
svhost.exe06b13dfd84493b01a020eecdabff6308b5b790ed4cd4c7a96a30ae6be1ca325dBeacon (Windows x64)
svc_timesync.x64.exe7d35d687ae8d4056e394905e9f8962512e6d55ff98664ed1facee6554a565624Beacon (Windows x64)
agent.x86.exe51fba778dae6f108f7afa800bdb7745e6a0f6d2630a37ecc84c1d4a1609f9692Beacon (Windows x86)

Operator SSH public key (hardcoded in install.sh):

ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIoi/bPuWr2EOQZo2OVDqG8XsRMz5epEGqG9sjcwZGJ1 timesync-manager

Presence of this key in authorized_keys on any host links the infection to this operator.

BeaconHTTP RC4 key (extracted from Windows samples): 1baccab4cbd2b84f6bc54bf8e6551f93

Agent Watermarks

AgentDefault Watermark
Beacon (C++)be4c0149
Gopher (Go)904e5493

Find AdaptixC2 Infrastructure on Censys

All hosts in this dataset are tagged under the Adaptix C2 threat label (THREAT-0210) in Censys. The threat detection covers both the default header-based detection and the body-based fallback, including the “TestCoonection” evasion variant.

host.services.threats.name: "Adaptix C2" or web.threats.name: "Adaptix C2"

Follow Along in Censys

Takeaways

  1. Default branding makes passive detection trivial. The Server: AdaptixC2 and Adaptix-Version: v1.2 headers appear on every unauthenticated request because they’re set in the error handler, not a specific route. No credential or endpoint knowledge is needed to identify a default-configuration deployment.
  2. Operators trying to evade headers leave the body string behind. The “TestCoonection” variant confirms that at least one operator modified the response headers to avoid detection but left the default 404 page intact. Body-based detection catches this class of evasion. Defenders should query both signals.
  3. Three beacon listener clusters suggest coordinated multi-server operations. The Hivelocity, M247, and PSB clusters — identifiable from sequential IPs, shared ports, and identical default OpenSSL certificates — likely represent single operators running redundant callback infrastructure. The shared cert pattern is the clustering signal.
  4. External visibility varies by transport. BeaconHTTP, BeaconDNS, and BeaconTCP all expose sockets that passive scanning can reach. BeaconSMB does not — the SMB extender binds no socket on the teamserver, and the named pipe lives on an already-compromised victim. Operators who pivot entirely through SMB after initial access leave nothing for internet scanners to find. The deployments counted here are necessarily those that kept at least one externally-reachable listener running.
  5. 412 web properties across 236 hosts is a population worth monitoring — with the caveat that passive scanning can’t separate authorized engagements from unauthorized ones. Some of these are authorized red team engagements. Passive scanning can’t distinguish them from unauthorized activity. What it can do is surface the infrastructure so analysts can make that determination themselves. The fingerprint is in production (THREAT-0210) and covers both header-based and body-based detection paths, including the evasion variant. Defenders can use the queries above to identify AdaptixC2 deployments in their threat intelligence pipelines.
A young man with blonde hair wearing a blue shirt outdoors with greenery and pink blossoms in the background.
AUTHOR
Aidan Holland
Senior Security Researcher

Aidan Holland is a Senior Security Researcher with Censys ARC, where he specializes in threat intelligence and internet-wide security research. His work focuses on identifying and analyzing malicious infrastructure, tracking threat actors, and developing tools for security analysis at scale. Aidan is an active contributor to the open source security community, building and maintaining tools for threat hunting, data analysis, and security automation.