12. Detecting RCS
The easiest way to write a bad RCS detection is to start with Server: nginx.
The examined backend places that value on every REST response, and its error
pages imitate nginx. It is a real product behavior. It is also shared by an
enormous population of ordinary web servers.
Ports 80 and 443, Ruby, MongoDB, a ten-year certificate, ACME Corp, and a
directory named backup have the same problem. Each belongs in the
investigation. None independently identifies HackingTeam.
Reliable detection comes from combinations across boundaries. The default certificate issuer plus an RCS-specific route is useful. Either becomes much stronger when the same host exposes the expected adjacent WebSocket or MongoDB topology. A network lead becomes compelling when a seized Windows server also contains the exact RCS service names, installation root, licence schema, and per-target MongoDB collections.
I built the detection work around that layered approach. It concentrates on the operator and backend platform reconstructed in the lab. Implant-to-collector indicators appear only where static source supports them, and no implant or exploit was executed to validate a rule.
Confidence is a property of a combination
Every indicator in this research carries both provenance and confidence. Provenance says how it is known: observed in the lab, found in source, stated in a manual, or inferred from several facts. Confidence says how strongly a match supports the RCS hypothesis in the sensor position where it is used.
| Signal | Provenance | Standalone value | Best companion |
|---|---|---|---|
Server: nginx on an RCS response | SOURCE + LAB | Very low | RCS route and nginx-styled error body from a non-nginx stack |
| TCP 443 followed by WSS on the next port | SOURCE + LAB | Low | Default certificate issuer and operator API traffic |
CA issuer containing both Root Certification Authority and ACME Corp | SOURCE | Medium to high for an unmodified default | Ten-year leaf, adjacent RCS API/WSS, host artifact |
X-Auth-Frontend request header | SOURCE | High | Database-to-collector direction and RCS topology |
| HTTP 444 from a collector | SOURCE | Low | Fixed-size encrypted POST behavior and repeated decoy closes |
C:\RCS\DB plus the three RCS Mongo service names | SOURCE | High | Installer registry/firewall values and licence file |
| RCS licence YAML schema | SOURCE | High | RCS directory, database, or service artifacts |
evidence.<24-hex-id> plus paired target GridFS collections | SOURCE + LAB | High in MongoDB | items, audit, signatures, and RCS evidence fields |
Confidence can fall when an operator changes a default. The certificate common name is configurable. An anonymizer chooses a plausible generic CA label. The collector’s URI and cookie names are randomized by build. A later product version may change ports or field names. Detections must therefore explain both what a match means and how a deployment can evade it without changing the underlying product.
Scoring evidence without inventing certainty
A practical triage score should reward specificity and independence rather than raw match count. Three variations of the same nginx banner are one layer, not three confirmations. The following model is qualitative by design:
| Evidence class | Examples | Suggested interpretation |
|---|---|---|
| Generic environment | HTTPS, MongoDB, Ruby, port 443, nginx banner | Lead only; never name RCS from this class alone |
| Correlated default | Adjacent 443/444 roles, ten-year ACME/default-root certificate | Interesting when several properties coexist; configuration can change them |
| Product-specific protocol | X-Auth-Frontend, cluster of distinctive controller routes | Strong network/application evidence at the required sensor position |
| Product-specific host | Exact service names and RCS paths, launcher combinations, licence schema | Strong host evidence; distinguish operational installation from copied research material |
| Product-specific data model | Repeated target-scoped evidence/aggregate/GridFS namespaces plus RCS fields and global collections | High-confidence backend evidence when acquired directly and read-only |
| Independent contextual evidence | Matching process, certificate, logs, topology, historical infrastructure record | Raises confidence and helps separate production, lab, archive, and false positive |
An assessment can then use plain-language conclusions:
- Possible: one weak or configurable product-associated lead.
- Probable: one strong product-specific layer plus compatible context, or several correlated defaults with no contradiction.
- Confirmed platform artifact: two independent product-specific layers, or one internally self-authenticating acquisition such as the complete RCS database/application structure.
- Compromise, operation, or attribution: not a detection score; each needs separate evidence and analysis.
This is not a numeric formula because sensor quality, acquisition provenance, and environmental prevalence matter more than a universal weight. Teams can translate the classes into their case-management system, but should preserve the matched facts and reasoning rather than output only a number.
The database network surface
The database exposes HTTPS REST on its configured listening port and secure WebSocket on the next port. Defaults are 443 and 444. The worker uses 442, and the collector normally uses HTTP 80 plus an internal controller port 4499. MongoDB’s expected router, shard, and configuration roles use 27017, 27018, and 27019. A host presenting several members of that sequence is more interesting than a host presenting any one of them.
Port correlations are hunting filters, not signatures. MongoDB commonly uses 27017. HTTPS commonly uses 443. Port 444 has many unrelated applications. The useful question is whether the services behind them also share RCS protocol, certificate, and host evidence.
The REST path shape is /<controller>/<action>[/<id>]. Operator login is
POST /auth/login with JSON fields user, pass, and version; a successful
response establishes a session cookie. Subsequent routes expose unusually
specific nouns such as /agent/filesystems, /evidence/commands,
/backuparchive, /collector/del_logs, /injector/add_rule, /shard, and
/task/create. In a TLS-terminated reverse proxy, web application firewall,
or server access log, several such routes from one client session are a strong
behavioral cluster.
On the original encrypted listener, a passive sensor cannot see these URIs or
JSON fields. A rule that examines /auth/login must say that it requires TLS
termination, endpoint instrumentation, or another decrypted sensor position.
Applying an HTTP-content rule directly to port 443 and calling it tested would
be misleading.
RCS adds Server: nginx itself in the REST response code, including success
and error paths (lib/rcs-db/rest_response.rb:107,201,270). The HTML errors
imitate nginx’s sparse 403 and 404 pages. This becomes mildly unusual when the
TLS, timing, and headers show EventMachine behavior or when an authenticated
API response carries the banner without an nginx proxy in the path. It still
needs another product-specific fact.
The banner is assigned inside the Ruby response builder rather than supplied by a reverse proxy:
# rcs-db/lib/rcs-db/rest_response.rb:106-111
# fake server reply
@response.headers['Server'] = 'nginx'
@response.headers['Date'] = Time.now.getutc.strftime("%a, %d %b %Y %H:%M:%S GMT")
@response.headers['Content-Type'] = @content_type
@response.headers['Content-Length'] = @response.content.bytesize
That makes the header a source-backed behavior, while its generic value keeps it low-confidence when observed alone.
WebSocket traffic adds a version-specific clue. The bundled
em-websocket behavior treats the Connection header value case-sensitively:
Upgrade succeeds where lowercase upgrade can be dropped. This explains a
reproducible proxy failure in the lab and can help fingerprint the old stack.
It is fragile as a detector, however, because proxies normalize headers and
other old WebSocket implementations may share the quirk.
The sensor position determines which of these observations is even possible:
| Sensor position | Visible evidence | Hidden or unreliable evidence |
|---|---|---|
| Internet perimeter without TLS termination | IPs, ports, timing, TLS handshake/certificate where not intercepted | REST paths, cookies, JSON, WebSocket messages |
| Reverse proxy or WAF | Decrypted routes, methods, headers, response codes, session-level clusters | Backend process identity and internal component links unless separately logged |
| East-west network sensor | Frontend/component headers, Worker/Mongo relationships, internal topology | Host files and data meaning; TLS may still hide content |
| Windows endpoint telemetry | Services, command lines, registry, paths, process ancestry, network peers | MongoDB document schema unless database access is collected |
| Backend filesystem acquisition | Configuration, certificates, launchers, logs, licence and backup structure | Live volatile sessions and traffic not preserved on disk |
| MongoDB acquisition | Collections, indexes, shard keys, relationships and object state | Original packets, deleted unbacked state, and host-only artifacts |
A detection rule that requires the wrong sensor is not merely low confidence; it is inoperative. Rule documentation therefore needs the decryption point, event source, operating system, audit policy, database privilege, and retention assumptions alongside the pattern itself.
Certificates: useful defaults, dangerous conclusions
When RCS generates its database certificates, it creates a self-signed CA with
subject CN=Root Certification Authority, O=ACME Corp. It then signs a
database leaf whose common name is operator-configured and a collector leaf
whose common name is collector. The generated certificates use a 3,650-day
validity period (lib/rcs-db/config.rb:325-359 and
config/certs/openssl.cnf).
The combination of both default issuer attributes, long validity, and an RCS
port relationship is useful for historical hunting. Each component alone is
weak. Root Certification Authority is intentionally generic. ACME is a
widely used certificate-management acronym and company name. Long-lived
self-signed certificates are common in appliances. The database common name
can simply be an IP address.
The CA also may not be default. RCS can import other certificate material, and
anonymizer construction samples generic names such as server, test,
apache, nginx, development, web, and www. Those names should never
be blocklisted. Their defensive value lies in a broader certificate cluster:
shared key or issuer relationships, matching validity and generation times,
co-located RCS services, and supporting historical infrastructure evidence.
The initial Suricata rule therefore requires both default issuer strings in the certificate issuer buffer. It will miss custom certificates by design. A miss is not evidence that a candidate is benign, and a hit still warrants confirmation.
Certificate-hunting recipes
In a certificate inventory, the safest query keeps the individual properties visible rather than hashing them into one opaque rule. A platform-neutral schema might use:
SELECT observed_ip, port, subject_dn, issuer_dn, not_before, not_after,
sha256_fingerprint
FROM tls_certificates
WHERE issuer_dn LIKE '%CN=Root Certification Authority%'
AND issuer_dn LIKE '%O=ACME Corp%'
AND not_after >= not_before + INTERVAL '3500 days';
Syntax will vary by data lake. The 3,500-day threshold tolerates small date representation differences around the source’s 3,650-day setting; it is a hunt, not an exact product assertion. Results should be joined with service relationships on the same IP or nearby hosts, especially adjacent HTTPS/WSS ports and RCS-specific application routes.
For an acquired certificate file, a read-only local check can preserve the fields and fingerprint without exposing private keys:
openssl x509 -in candidate.crt -noout \
-subject -issuer -serial -dates -fingerprint -sha256
Do not upload an unknown private certificate or key to a public search service. Search infrastructure should use the public certificate fingerprint or public transparency data where legally and operationally appropriate. A match to the default issuer still needs host, protocol, or database corroboration.
Database-to-collector traffic
One network artifact is much more specific. The backend sends the shared
server signature to a frontend in the header X-Auth-Frontend. In the
examined source this path uses ordinary HTTP on port 80
(lib/rcs-db/frontend.rb:14-127). The header name describes an internal RCS
concept and is not a standard web authentication scheme.
A sensor that sees this header should preserve the transaction and examine both endpoints. The value is a credential and should be handled as sensitive; it does not need to be logged to raise the alert. Detection should capture the header name, flow direction, server addresses, timing, and nearby status or topology traffic while redacting the header value from routine output.
Cleartext reachability is a deployment condition. A reverse proxy, VPN, or later change may hide it. Conversely, security scanners or researchers can replay the header name. Host and database corroboration remain important.
The collector’s public listener uses deliberate decoy behavior. Invalid or
unauthenticated requests can receive nginx’s non-standard status 444 after a
delay or simply lose the connection. Unsupported non-public methods can enter
a HACK ALERT log path and return 405. Status 444 alone is low-confidence:
ordinary nginx configurations use it. Repeated 444 or delayed-close behavior
on a candidate that also has RCS certificate, port, or header evidence is much
more useful.
Implant-side traffic: what source can and cannot provide
The static capability audit improves the inventory of possible endpoint behaviors, but it does not manufacture network observations. Module factories and evidence writers support platform-specific collection claims; they do not show which build was shipped, whether a module ran, or what its traffic looked like on a historical network. Scout, Soldier, full cores, and companion layers also have different scope, so a detection must name the source snapshot and stage it is meant to cover. Appendices D–E record those distinctions.
Static source describes an authentication POST whose encrypted body is normally 112 bytes with up to 16 bytes of trailing variation. It uses AES-128-CBC under a customer signature, and build-side URI and cookie names can be randomized. User-Agent strings influence which platform payload the collector selects.
This suggests a hunting pattern: repeated short POSTs of a narrow size range to an otherwise static-looking HTTP site, followed by collector-specific response and file-transfer behavior. It is not sufficient for a production signature. Many telemetry beacons use short fixed-size posts; packetization can obscure body length; HTTPS or anonymizers can remove visibility; and the lab did not execute an implant-to-collector session.
For that reason the initial ruleset does not publish a “fixed-size POST equals RCS” alert. The behavior belongs in threat hunting with strict scoping and companion signals until a safe, representative PCAP corpus can measure both coverage and false positives. The capability audit may guide defensive host artifact review or evidence-type triage, but it is not itself an IOC set.
Windows server artifacts
The original Windows installer is less coy than the network protocol. It uses
C:\RCS\ as the root and places the database under C:\RCS\DB, alongside
bundled Ruby, MongoDB, Java, Python, collector, configuration, certificate,
log, backup, core, and exploit material according to the selected installation
roles (nsis/RCS.nsi).
It installs MongoDB roles under exact service names:
RCSMasterConfig, displayed as “RCS Master Config”;RCSMasterRouter, displayed as “RCS Master Router”; andRCSShard, displayed as “RCS Shard”.
The corresponding service descriptions explicitly mention “Remote Control
System,” and image paths point into C:\RCS\DB\mongodb\win\ with router,
configuration-server, or shard arguments (RCS.nsi:505-516). The combination
of an exact service name and exact RCS path is high-confidence. A service name
by itself is slightly weaker because short abbreviations can collide.
The installer writes a distinctive compatibility value:
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers\C:\RCS\Ruby\bin\ruby.exe = DisableNXShowUI
The complete path and exact value make this a useful registry detection
(RCS.nsi:296). It also adds Windows Firewall rules under the group RCS Firewall Rules with names beginning RCS_FWD, including Database, Database
Websocket, Mongo Router, Mongo Shard, and Mongo Config on the expected ports
(RCS.nsi:598-602).
Batch launchers repeatedly change directory to C:\RCS\DB and invoke names
such as ruby bin\rcs-db-status or ruby bin\rcs-worker-stats. The backend
may contain bin\ruby_x64.dll for HASP dongle support and haspdinst.exe.
Those filenames have other legitimate uses; their RCS directory and companion
files supply the confidence.
The initial Sigma set detects the registry value, service-install event, and MongoDB service command line. They are marked experimental because the source side is confirmed but representative Windows telemetry has not yet been replayed through a Sigma converter and target SIEM pipeline.
Read-only Windows host triage
On an acquired or safely isolated Windows host, defenders can test the exact service and registry evidence without starting any RCS component:
Get-CimInstance Win32_Service |
Where-Object Name -in 'RCSMasterConfig','RCSMasterRouter','RCSShard' |
Select-Object Name, DisplayName, State, StartMode, PathName
Get-ItemProperty -LiteralPath `
'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers' |
Select-Object -Property 'C:\RCS\Ruby\bin\ruby.exe'
Get-NetFirewallRule -Group 'RCS Firewall Rules' -ErrorAction SilentlyContinue |
Select-Object DisplayName, Enabled, Direction, Action
These queries read configuration; they do not stop services or open files.
Investigators should capture full service paths and firewall port filters before
concluding that a name collision is benign. If C:\RCS exists, inventory names,
sizes, timestamps, owners, alternate data streams, and cryptographic hashes
before previewing content. Licence files, configuration, logs, backups,
certificates, and MongoDB data can contain credentials or victim information
and need restricted evidence handling.
A filesystem hunt should favor combinations such as an RCS database launcher, the exact root, MongoDB role arguments, and the licence/configuration layout. Searching enterprise-wide for the three-letter directory name alone will produce unrelated matches and may collect sensitive content unnecessarily.
File-content detection
The RCS licence is a YAML document with a distinctive combination of product dimensions: serial, maintenance, users, desktop and mobile agent counts, individual historical platforms, collectors and anonymizers, shards, alerting, correlation, deletion, archive, OCR, translation, digest, signature, and integrity fields. Several names are generic, but the complete schema is unusual.
The first YARA rule requires a multi-field subset rather than a historical digest or signature value. This preserves coverage across customer licences while avoiding a rule that merely recognizes the leaked sample. It is bounded to small files and requires the YAML document marker at offset zero.
A second rule detects Windows batch launchers only when the exact RCS database
root occurs with an rcs-db or rcs-worker Ruby command. A third recognizes
the original certificate-generator source through the joint presence of the
default CA, database and collector certificate names, collector subject, and
anonymizer CA filename. The source rule is principally useful on seized
development or server trees; it is not an implant signature.
YARA 4.5.0 parsed the rules and matched the intended original licence, launcher, and configuration-source files. It produced no match on the initial three-file sanity set or an expanded 603-file, 27.1 MB local corpus containing executables, libraries, structured files, documents, and three rule-specific near misses. That proves syntax and expected positives against a materially better local negative set, not operational false-positive performance. An authorized representative Windows enterprise corpus is still needed.
What the experimental rules cover
The appendices preserve full rule text; the useful chapter-level question is where each family can see and what its tests establish.
| Rule family | Rules | Intended sensor | Positive basis | Remaining gate |
|---|---|---|---|---|
| Suricata | 4 | TLS metadata or decrypted/internal HTTP | Suricata 7.0.3 parse; four intended positive flows and two near-miss flows replayed | Representative benign PCAP corpus, sensor tuning, and performance |
| Sigma | 3 | Windows registry, service-install, and process telemetry | Sigma CLI check, pySigma Splunk conversion, three positive and eight near-miss fixture events | Target-SIEM field mapping and ingestion-normalization replay |
| YARA | 3 | Acquired server/source files | Frozen positives plus 603-file local negative corpus | Representative Windows/enterprise corpus and operational-image calibration |
Rules stay separate because combining them inside one engine can hide sensor assumptions. A Suricata alert cannot require a Windows registry key it cannot see; correlation belongs in the SIEM or investigation layer. Conversely, a YARA hit on a researcher’s copy of leaked source should not be promoted into an operational incident merely because the file content is exact.
Every rule record therefore carries provenance, configurable fields, expected coverage, companion signals, false positives, and validation status. That metadata is part of the detection. Removing it to obtain a shorter rule file would make deployment easier while making the resulting conclusion less safe.
MongoDB as a high-confidence discovery surface
On a seized or exposed database, collection topology is one of the strongest
backend indicators. RCS expects the database rcs and creates target-specific
namespaces:
evidence.<24-hex-target-id>;aggregate.<24-hex-target-id>;grid.<24-hex-target-id>.files; andgrid.<24-hex-target-id>.chunks.
The evidence collections use a compound shard key {type: 1, da: 1, aid: 1}.
Documents contain acquisition and receive times, relevance, report flag,
notes, an agent ID stored as a string, keyword arrays, and type-specific data.
GridFS references use _grid and _grid_size. Related global collections
include items, users, groups, signatures, audit, alerts, backups,
status, queue, collector, injector, connector, and topology data.
MongoDB applications commonly use GridFS and ObjectIds. The confidence comes from the repeated target ID across evidence, aggregate, files, and chunks, plus RCS-specific fields and global collections. Investigators should collect names and schema read-only before running application cleanup or restore. An unprotected database may itself be the compromise path described in Chapter 10.
A practical read-only hunt can begin with collection names matching the four patterns, then verify the shard key and sample only metadata necessary to establish schema. Sensitive evidence content should not be copied into a detection system merely to prove the product identity.
The following MongoDB 2.6-compatible discovery fragment lists names and index metadata without returning evidence bodies or changing state:
var rcsDb = db.getSiblingDB('rcs');
var targetPattern = /^(evidence|aggregate|grid)\.[0-9a-f]{24}(\.(files|chunks))?$/;
var scoped = rcsDb.getCollectionNames().filter(function (name) {
return targetPattern.test(name);
}).sort();
printjson(scoped);
scoped.filter(function (name) {
return name.indexOf('evidence.') === 0;
}).forEach(function (name) {
print(name);
printjson(rcsDb.getCollection(name).getIndexes());
});
db.getSiblingDB('config').collections.find(
{ _id: /^rcs\.(evidence|aggregate|grid)\./ },
{ _id: 1, key: 1, unique: 1, dropped: 1 }
).forEach(printjson);
The fragment should run only against an authorized acquisition or forensic
clone. A production query still changes access logs, cache state, and possibly
timing, even when it performs no writes. Appendix H maps the full schema, and
Chapter 13 supplies the preservation-first query catalogue. Discovery output
should retain BSON types and collection names; JSON-only export can erase the
string-versus-ObjectId distinction that matters to aid interpretation.
Logs and behavioral signals
Backend logs contain component and workflow language that can corroborate a candidate:
RCS Worker '<shard>' ready!;Listening for https on portfollowed byListening for wss on port;- evidence processing messages containing
ident:instance; HACK ALERTon the collector path;- component types such as collector, anonymizer, network controller, carrier, and worker; and
- monitor text such as “Not sending status update for more than 2 minutes.”
Log strings can be copied, and many fragments are generic. Their value rises when directory, process, certificate, and database evidence independently agree.
Two behaviors are useful for identification but poor as automatic alerts. First, logging in as one user invalidates the earlier session and queues a “used on another machine” logout push. Second, the reconstructed database can mark its own heartbeat stale after several minutes while REST and WebSocket traffic remain healthy. Both can explain operator reports and captured state; neither should trigger an RCS incident without stronger artifacts.
Playbooks for four common starting leads
Different leads require different confirmation paths. The initial fact should determine what is collected next, not predetermine the conclusion.
A certificate or adjacent-port lead
Preserve the full certificate chain, fingerprints, handshake metadata, IP/port, observation time, and sensor position. Determine whether the certificate came from the origin or a TLS-intercepting proxy. Look for the 443/444 relationship and other historical component ports, then seek decrypted route clusters or host evidence through authorized means.
The default issuer and ten-year validity make the lead interesting; they do not identify the operator, customer, implant, or victim. If the origin uses a custom certificate, route and host evidence may still confirm RCS. If only the default strings match, classify the lead as possible and keep hunting.
An exact Windows service or path lead
Acquire service configuration, binary and interpreter paths, registry values,
firewall rules, scheduled tasks, process ancestry, listening sockets, and file
hashes. Check whether the host is an operational server, a forensic image, a
research archive, or a reconstruction lab. The presence of source code or a
licence-schema sample on an analyst workstation has a different meaning from
running RCSMasterRouter beneath the expected installation root.
Do not start a stopped service to test it. Preserve configuration, logs, certificates, MongoDB paths, and volatile state first. If the service was running, relate its command line and network peers to the RCS role model rather than relying on the name alone.
A MongoDB namespace lead
Begin with database name, collection names, index definitions, shard metadata, and counts. Confirm the repeated target ID across evidence, aggregate, and GridFS namespaces, then look for the RCS global collection cluster and model fields. Preserve BSON types. Sample evidence content only when legally authorized and necessary; schema and relationships are normally enough for platform identification.
An exposed database is simultaneously a detection lead and a security incident. Chapter 10 shows that bundled all-in-one deployment can lack database authorization. Record access conditions and network placement, but do not use a default application login or run cleanup. Platform identification, database exposure, data access, and historical exploitation are four separate findings.
A collector-decoy or internal-header lead
Status 444 or delayed close begins as low confidence. Preserve timing, request
method, response bytes, TLS state, redirects, and repeatability without
aggressive probing. Seek the fixed component relationships, certificate cluster,
or host identity. The X-Auth-Frontend header is much more specific; alert on
its name, redact its credential value, and investigate both endpoints as
potentially sensitive components.
Because collector URIs and cookies can be randomized, absence of a known path is weak negative evidence. Because scanners can copy public signatures, a header-name hit without the surrounding RCS topology can also be simulated. Independent endpoint or database evidence resolves that ambiguity.
| Starting lead | Strongest next layer | Avoid concluding |
|---|---|---|
| Certificate/ports | Decrypted routes or host artifacts | Customer, operation, or victim identity |
| Windows service/path | Process, configuration, certificate, and MongoDB structure | That copied research files were operational |
| MongoDB namespaces | Global RCS schema, shard metadata, host role | That exposure was exploited or records are authentic |
| Collector/header behavior | Both endpoint identities and component topology | That generic 444 behavior alone is RCS |
Negative controls and configuration tests
A detector should be tested against both ordinary software and modified RCS defaults. The first measures false positives; the second measures how much of the rule is only configuration recognition.
Useful negative sets include ordinary nginx 444 configurations, self-generated
ACME-labelled certificates, unrelated applications under C:\RCS, standard
MongoDB/GridFS applications, Ruby service launchers, and generic YAML licences.
The corpus should be documented and legally shareable; a tiny set of operating-
system text files cannot represent enterprise software prevalence.
Configuration-variation tests should change one dimension at a time: certificate issuer, leaf subject, listener ports, installation root, service display names, proxy normalization, and TLS termination. Expected misses should be recorded as coverage limits, not patched by adding broad strings that raise false positives. Product-specific relationships—route vocabulary, collection families, model fields, component header, or exact multi-artifact combinations—should carry the detector when defaults change.
A staged hunting workflow
Detection should minimize both false accusation and unnecessary exposure of surveillance data.
- Collect a lead. Identify a certificate, header, service, file, database namespace, or route cluster. Record its provenance and sensor limitations.
- Seek an independent layer. Corroborate network evidence on the host, host evidence in MongoDB, or database evidence in logs and certificates.
- Test configuration alternatives. Determine whether certificates, ports, paths, and listener addresses were customized before interpreting a miss.
- Preserve before interaction. Do not log in with a default account, restore a backup, compact MongoDB, or use the UI to “look around” before acquiring state. Login changes sessions and audit; restore can replace collections and signatures.
- Separate platform from payload. A backend finding does not identify which implant version, exploit, customer, or targets were involved.
- Score the conclusion. Report confirmed RCS only when multiple specific artifacts agree. Label weaker cases possible or probable and state what would resolve them.
One reasonable high-confidence combination is the default issuer, the 443/444
service pair, and any exact Windows service or licence artifact. Another is
the X-Auth-Frontend header plus RCS-specific REST routes and the target-scoped
MongoDB layout. The precise scoring should be adapted to the environment, but
the principle is stable: prefer independent, difficult-to-fake layers.
False positives and negative evidence
Every published rule needs an explicit false-positive story.
| Rule family | Likely false positive | Tuning or confirmation |
|---|---|---|
| nginx banner or 444 status | Ordinary nginx and custom web applications | Require RCS route, certificate, or host evidence |
| Default CA strings | Lab appliances and locally generated certificates | Require both issuer attributes, validity context, and adjacent services |
| Login route | Unrelated APIs using /auth/login and common JSON names | Require additional RCS routes in the same session |
| Port topology | MongoDB and custom admin services | Fingerprint protocols and corroborate on host |
| Service names | Internal abbreviations or reconstruction labs | Require RCS path or service description |
C:\RCS path | Unrelated application using the acronym | Require database layout, services, licence, or registry value |
| License-schema YARA | A copied research artifact | Determine acquisition path; distinguish operational host from source archive |
| MongoDB collection pattern | Another target-scoped analytics product | Verify compound schema and RCS global collections |
Negative evidence also has limits. No default certificate may mean a custom
certificate. No C:\RCS may mean a non-Windows installation. No worker port
may mean a distributed topology or firewall. No exploit package says nothing
about whether the backend existed. Rules describe expected coverage; they are
not universal definitions of RCS.
Validation status
I deliberately label the research rules experimental.
YARA has executable validation against frozen positive files and a 603-file local negative corpus. Sigma CLI reports no rule, condition, or validation issues; all rules convert through pySigma’s Splunk backend, and their portable selections pass three positive and eight one-field near-miss events. Suricata 7.0.3 loads all four rules; each SID fires exactly once on its intended synthetic or certificate-only flow, while HTTP and ordinary-certificate TLS near misses produce no alert.
The one live lab interaction was a certificate-only loopback TLS handshake; it did not log in or send an application request. The cleartext HTTP traffic was generated from inert packet fixtures. The 444 fixture validates the rule, not the collector behavior: no collector ran. The detection ledger records which artifact is source-backed, previously observed, or newly validated.
The remaining production gate is narrower: repeat Suricata tests on the target sensor version and representative benign traffic; convert and execute Sigma in each intended SIEM with its real field mappings; scan an authorized Windows enterprise corpus with YARA; measure performance; and test how useful signal combinations remain after default certificates, ports, and paths are changed.
Validation material must preserve the same safety boundary as the research. Synthetic backend captures can test REST, WebSocket, certificate, and Worker rules. Collector coverage should use sanitized, lawfully obtained defensive captures or a separately approved non-operational fixture—not a rebuilt implant session. Negative corpora must exclude credentials and victim content. The validation ledger should record engine version, command, input hashes, expected alerts, actual alerts, misses, false positives, and sensor assumptions so a later rule revision can be compared rather than merely declared improved. Without that provenance, a successful alert is a demonstration, not validation.
Sources and evidence
- SOURCE:
rcs-db/lib/rcs-db/config.rb,rest_response.rb,frontend.rb,events.rb, evidence and GridFS models, andnsis/RCS.nsiat commit6cff59d28634d718cac9fdd17cb629fd59a3cf3f. - SOURCE: collector decoy and synchronization behavior from
rcs-collectorcommit42cf61af9ec3e7b886e87eac20e762c3ce51c78c; no collector runtime validation in the active lab. - SOURCE/METHOD:
research/hackingteam-rcs/IMPLANT-CAPABILITY-AUDIT.mdsupplies the platform- and stage-specific static capability inventory; it is not an implant traffic validation or IOC list. - LAB:
docker-lab/IOCs.md, backend REST/WSS observations, MongoDB storage tests, and console live-test contracts. - RULES:
research/hackingteam-rcs/detections/contains the experimental Suricata, Sigma, and YARA artifacts and their validation ledger. - LIMITATION: backend-focused; no implant or exploit execution; no new collector runtime capture; synthetic and certificate-only tests validate rule mechanics, not deployment-specific tuning, performance, or uniqueness.
↑ HackingTeam's RCS: Bringing a Commercial Spyware Platform Back to Life