case study · 01

From a single URL to a pan-European fake-voting PhaaS cluster.

How Bounce-CTI, an autonomous CTI pivoting agent, took two URLs received over WhatsApp and unmasked the Cloudflare-fronted operation behind them — and where it deliberately stopped short.

Research prototype Free & passive sources only Bounded, auditable pivots Defensive tradecraft
tl;dr

Six things this run shows.

  • 01

    Starting from one URL — a French-language "School votingFR" fake-voting page received over WhatsApp — Bounce-CTI fingerprinted the host, recognised it was Cloudflare-fronted, recovered the true origin server, and pulled the origin TLS certificate that bound several sibling domains together. From that single seed it mapped a 7-domain cluster.

  • 02

    The origin (217.145.226[.]186, AS205775, bulletproof hosting) was already known to a previous investigation. The agent recognised it as repeat actor infrastructure rather than starting from zero.

  • 03

    The strongest cluster evidence is the shared origin-certificate SAN and the shared origin IPnot the shared JARM. The JARM is a generic Cloudflare-edge fingerprint, and the agent explicitly down-weighted it to corroboration only. A tool that headlined "all domains share JARM X" would have been wrong.

  • 04

    The cluster was absent from every community and abuse feed queried (OTX, ThreatFox, Pulsedive, AlienVault, URLhaus). This makes the data set an early-warning view, with two confirmed cluster members still sitting at VirusTotal 0/94.

  • 05

    On request, the agent expanded the cluster to two dozen domains across four TLDs and three languages (French, German, Italian) — a recurring, multilingual pan-European operation, not a one-off French burst.

  • 06

    Confidence is reported as a gradient. The agent flagged what it could not prove, refused a false pivot, and stopped on yield instead of padding the graph.

The Bounce-CTI infrastructure graph after run 1 from a single seed: the konkurzfrance.click seed (blue) fans out to the origin IP 217.145.226.186 (orange square), the AS205775 ASN node, the Cloudflare JARM hub, Let's Encrypt cert serial nodes, the cluster certificate binding voteingmap.click and francedancingvotingfr.click, the co-hosted panek2n.shop, defused Cloudflare edge IPs and ns.cloudflare.com nodes (greyed), the Global Domain Group registrar, and the Investigation Summary star.
Figure 1 — One URL in. A 7-domain phishing cluster, its bulletproof origin, and the certificate that ties them together — built autonomously, in real time.
context

What you're looking at.

Bounce-CTI is a research prototype: an autonomous threat-intelligence pivoting agent. You give it one observable — a URL, domain, IP, or file hash — and it decides for itself which open sources to query next, builds an infrastructure graph live in the browser, and writes a structured analyst report at the end. Three design choices shape everything below.

  • reasons

    It reasons about pivots, it doesn't brute-force them. The agent chooses the next source based on what it has already found, and it defuses shared/benign infrastructure (CDN ranges, parking, sinkholes, DynDNS) before pivoting on it — so the graph never explodes into noise.

  • bounded

    It is bounded and auditable. Each investigation caps itself at a limited pivot depth and API budget. You can watch every decision stream past as it happens.

  • passive

    It is defensive by construction. Everything here is passive OSINT and threat-hunting enrichment. The agent never interacts with the infrastructure it describes; it has no shell and no filesystem access, only read-only intelligence tools.

The walk-through below follows three real runs: a single-seed investigation, a second seed merged into the same graph, and a conversational "find the rest of this campaign" expansion.

act 1

From one URL to a cluster.

The seed

The investigation starts with a single observable — a link that arrived, unprompted, in a WhatsApp message:

hxxps://konkurzfrance[.]click/home/votenam

A French-language "School votingFR" page — the classic fake-contest / fake-voting lure ("vote for my entry"). The link is pushed peer-to-peer through WhatsApp and Messenger, riding the trust of a known contact, which is also why it lands in front of victims long before it lands in any abuse feed. The second seed in Act 2 reached a different person through the same channel — two independent WhatsApp deliveries of the same kit, a week apart.

The WhatsApp lure as received: a French message reading 'Salut, pourrais-tu voter pour Francesca? C'est la fille de mes amis, le premier prix est un cours de danse gratuit, et c'est tres important pour elle!' followed by the link https://francevoice29.click/home/voteng. Only the message body is visible — no sender shown.
Figure 0 — Ground truth on the delivery vector: the actual WhatsApp message carrying the second seed (francevoice29[.]click). The pretext — “vote for my friends' daughter, the prize is a free dance class” — is the classic fake-voting lure, riding the trust of a known contact. Only the message body is shown; no sender details were captured.
a note on evidence

The WhatsApp delivery is a first-hand observation of the distribution vector — the messages were received directly. It is recorded as analyst-supplied context, not as something the graph proves; the infrastructure findings below stand on their own technical evidence. Keeping the two separate is the same discipline the agent applies throughout: strong markers and corroborating context are never conflated.

Triage and defusing

The agent's first move is to observe: resolve DNS, pull RDAP, query URLScan and VirusTotal. It immediately establishes that the domain is Cloudflare-fronted — its A records sit in Cloudflare ranges (104.21.21[.]216, 172.67.200[.]153), its nameservers are Cloudflare, and it carries the standard Cloudflare TLS fingerprint. This is the moment most automated OSINT tooling drowns. Pivoting on a Cloudflare IP returns millions of unrelated sites. Bounce-CTI instead defuses those nodes — tags them as CDN edge and refuses to pivot on them — and pivots on the registration and certificate surface instead.

Bounce-CTI node detail for Cloudflare edge IP 104.21.21.216: tagged cdn, seen by DNS, with metadata note 'Cloudflare range 104.21.0.0/16'. The node is shown greyed/defused (orange dashed icon) before any pivot.
Figure 2 — Cloudflare edge IPs are recognised and defused (greyed, tagged cdn) before the agent pivots — the single most important step in keeping infrastructure graphs signal-dense.

The reasoning is visible

Because the agent streams its decisions, you don't just get a verdict — you see why. In its own words, mid-run:

Cloudflare-fronted (A records in 104.21/172.67), registered 2026-04-11, Dynadot registrar. This triggers the origin-unmask step.

— Bounce-CTI agent log, run 1
The Bounce-CTI timeline panel mid-run: interleaved reasoning lines ('Cloudflare-fronted (A records in 104.21/172.67), registered 2026-04-11, Dynadot registrar. This triggers R14 origin-unmask') and MCP tool-call chips — mcp__graph__add_edge, mcp__graph__defuse, mcp__cti__rdap_domain, mcp__cti__dns_resolve, mcp__cti__urlscan_search, add_node — each timestamped.
Figure 3 — Every pivot decision streams to the analyst as it happens. The investigation is auditable, not a black box.

Unmasking the origin

A Cloudflare-fronted phishing page hides its real home. To find it, the agent runs a passive datascan (Onyphe) keyed on the host and certificate — and recovers the origin:

217.145.226[.]186

The node fills in fast, and the picture is unambiguous:

  • ASN

    AS205775 — NEON CORE NETWORK LLC (RIPE org TrafficTransitSolution LLC, geolocated RU; abuse info[at]traffictransitsolution[.]us) — bulletproof-style hosting.

  • panel

    Running nginx/1.18.0 (Ubuntu) with a Python/3.10 aiohttp panel on tcp/5001 — the PhaaS control panel itself, exposed.

  • ports

    Open ports 22/80/443/5001, OpenSSH 8.9p1, and a handful of version-banner-inferred CVEs (regreSSHion CVE-2024-6387, HTTP/2 Rapid Reset CVE-2023-44487, CVE-2021-23017). The agent recorded these as banner-derived context, not confirmed-exploitable findings — correct restraint.

Bounce-CTI node detail for origin IP 217.145.226.186: role origin_unmask, tagged suspicious / phishing / repeat_infrastructure / bulletproof / actor-origin, seen by 3 sources (onyphe, virustotal, abuseipdb). Product nginx/1.18.0 (Ubuntu), ASN AS205775 NEON CORE NETWORK LLC, geolocus RU. An 'Also seen in 2 prior investigations' panel links a prior URL and the origin-confirmed cert hash, and the cert_san list repeats the cluster domains.
Figure 4 — Behind the CDN: a bulletproof-hosted origin running the PhaaS panel on tcp/5001, recovered without ever touching the server.

The certificate that tied it together

The decisive evidence is the origin's TLS certificate:

  • serial

    06:97:88:8e:72:55:f2:31:11:cb:10:98:d1:ad:01:50:5d:f1

  • cn

    CN voteingmap[.]click, SHA-256 548b4f01…78497

  • SAN

    SAN-bound to multiple cluster domains: francedancingvotingfr[.]click, konkurzfrance[.]click, voteingmap[.]click

A single certificate on the origin server cryptographically links three of the sibling domains. Combined with a second domain (panek2n[.]shop) co-hosted on the same origin with its own certificate, this is strong, discriminating attribution — the kind that holds up.

the JARM is not the evidence — and the agent says so

Every domain in the cluster shares JARM 27d40d40d00040d1…3d525c. A naive tool would headline that as proof. Bounce-CTI flagged it as a generic Cloudflare-edge fingerprint that matches thousands of unrelated hosts, and treated it as corroboration only. A JARM membership sweep returned 324K characters of non-discriminating results and was discarded. The cluster is held together by the origin certificate and the shared origin IP — the JARM just rhymes with it.

This distinction — strong markers vs. generic ones — is the whole game in infrastructure CTI. Reporting a CDN fingerprint as a cluster signature is how false clusters get built.

A known address

When the agent enriched the origin, its cross-investigation memory flagged something: 217.145.226[.]186 — and the exact certificate SHA-256 548b4f01… — had appeared in prior investigations, already tagged phaas / actor-origin. This isn't a fresh discovery; it's repeat infrastructure from a returning operator.

Bounce-CTI node detail for the origin cluster certificate 06:97:88:8e:72:55:f2:31:11:cb:10:98:d1:ad:01:50:5d:f1, tagged origin_cluster_cert / phaas / actor-origin. CN voteingmap.click; the SAN list binds francedancingvotingfr.click, konkurzfrance.click and voteingmap.click; issuer Let's Encrypt E7; served_from 217.145.226.186; and a note recording that this cert's SHA-256 equals the seed hash of a prior investigation.
Figures 5 & 6 — One origin certificate, three domains in its SAN — this, not the JARM, makes the cluster a cluster. The same panel's note records that the cert's hash matches a prior investigation: repeat infrastructure, not a first sighting.

The cluster, Act 1

From one URL, the agent settled a 7-domain cluster:

DomainRoleFirst seenVT (at scan)
konkurzfrance[.]clickSeed (FR "School votingFR")2026-04-11malicious
voteingmap[.]clickOrigin cert CN2026-04-1011
francedancingvotingfr[.]clickOrigin cert SAN2026-04-110
panek2n[.]shopCo-hosted on origin (fake-shop variant)2026-05-140
danncervotting[.]clickSame kit /home/votenam2026-04-185
dancorevoting[.]clickSame kit /home/votenam2026-04-156
reeechka[.]clubOldest member; Italian variant2026-02-2211

Two members — francedancingvotingfr[.]click and panek2n[.]shop — were at VirusTotal 0/94 yet provably in-cluster. Those are exactly the domains defenders want to block before detection catches up.

act 2

A second seed, one graph.

A real investigation rarely has one starting point. A second link — delivered over WhatsApp to a different person, a week after the first — surfaces:

hxxps://francevoice29[.]click/home/voteng

Two independent WhatsApp deliveries of the same kit, reaching two different targets, is itself a signal: this is an active distribution campaign, not a dormant page. Dropped into the same investigation, the new link doesn't start a separate report — it merges into the existing graph. The agent enriches it (VirusTotal malicious 8/94: BitDefender, Fortinet, G-Data flag phishing; Sophos flags malware; alphaMountain categorises the domain Malicious) and the graph automatically draws the bridges to the existing cluster:

  • jarm

    It presents the same Cloudflare JARM (corroborative).

  • registrar

    It is registered through Spaceship, Inc. — the same registrar used by existing cluster member dancorevoting[.]click — inside the same April-2026 registration window.

  • kit

    It serves the identical kit at the same /home/vote* path.

honest limit, stated by the agent

Its true origin could not be recovered on free/passive sources (only the Cloudflare front was visible; a confirmed shared-origin link would need a paid datascan). So the tool placed it in the cluster on registrar + kit + corroborating JARM — and explicitly declined to assert a shared-origin-IP edge it couldn't prove.

The Bounce-CTI graph with two seeds merged: the konkurzfrance.click and francevoice29.click seeds both feed the shared cluster, with red bridge edges running konkurzfrance.click → dancorevoting.click → francevoice29.click via a same_registrant link, the shared Cloudflare JARM node, the Spaceship registrar node, and the Investigation Summary star at the centre.
Figure 7 — A second URL folds into the same graph, bridged to the original cluster by shared registrar and kit — with the unprovable link left undrawn.
act 3

"Find the rest of this campaign."

Bounce-CTI is also conversational. With the cluster mapped, a single instruction:

Find as much domains / URLs as possible, belonging to the same campaign.

— analyst prompt, chat panel

The agent ran a kit-fingerprint sweep (URLScan kit-path /home/voteng + page-title search) and returned 16 additional campaign domains, all serving the byte-identical "School votingFR" kit:

balletvotee38[.]click konkcurserr[.]cfd koncnckcurs[.]cfd concursere[.]cfd konkurser[.]cfd wvwrotrering[.]click vortertetre[.]lol voicefrschool1[.]cyou vovorenteng[.]click worvorting[.]click balletvotte1a[.]cfd wovovroter[.]click vvortertring[.]click vwvwroteng[.]click votingball14[.]click italyvoice215[.]click

Chips marked VT✓ were independently VirusTotal-confirmed.

Three findings make this the most important act:

  1. It's multilingual and pan-European.

    Alongside the French "School votingFR", the sweep surfaced a German variant ("School votingGR", koncnckcurs[.]cfd) and an Italian variant (italyvoice215[.]click). The mixed-language domain naming (konkurz/concours/konkcurs — competition across Slavic, French, and garbled forms) points to a PhaaS operator serving several language markets, not a France-only actor.

  2. The confidence is graded, not flattened.

    Two of the sixteen — balletvotee38[.]click (VT 12) and konkcurserr[.]cfd (VT 8, VirusTotal-tagged dga) — were independently VirusTotal-confirmed as exact cluster members carrying the cluster JARM and the same Dynadot/Global Domain Group registrar. The remaining fourteen rest on byte-identical kit + path evidence — high confidence on kit identity, with origin co-residency left explicitly unconfirmed (passive DNS on the bulletproof origin was empty; confirming it would need a paid JARM datascan).

  3. It told us the map is incomplete.

    The page-title sweep exceeded the tool's result limit — so the agent reported plainly that more members almost certainly remain and a paged follow-up would extend coverage. It didn't pretend the campaign was fully enumerated.

The Bounce-CTI chat panel: the analyst prompt 'Find as much domains / URLs as possible, belonging to the same campaign' and the agent's reply listing 16 additional campaign domains with multilingual and confidence caveats.
Figure 8 — A plain-language request expands the cluster — and the agent answers with its confidence gradient attached, not just a domain dump.
The full Bounce-CTI infrastructure graph after run 3: a dense radial cluster of two dozen-plus phishing domains and their /home/vote URLs (red octagons) fanning out from the konkurzfrance.click seed, the orange origin IP 217.145.226.186, the AS205775 node, the shared JARM hub, Let's Encrypt cert serials, defused Cloudflare edge IPs and ns.cloudflare.com nodes (greyed), the Dynadot and Spaceship registrars, an RU geo node, and the Investigation Summary star.
Figure 9 — The campaign at scale: two dozen domains across four TLDs and three languages, expanded from the original seven.
restraint

What the agent didn't do.

For a senior analyst, restraint is as telling as discovery. Across these runs Bounce-CTI:

  • refused

    Refused a false pivot. Two live domains shared an inline-script hash (2050f127…). The agent noticed both pages were actually returning Cloudflare 522 error pages and concluded the shared hash was the CDN error-page script, not a kit signature. It recorded the node at low confidence, tagged it cloudflare_522_artifact, and wrote "do not treat as a cluster pivot."

  • flagged

    Flagged a contradiction it couldn't resolve. Geolocation came back DE from AbuseIPDB but RU from Onyphe's geolocus. Rather than pick one, it recorded both and noted geo was unreliable for this host.

  • discarded

    Discarded its own typo artifact. An auto-generated stub (reeechka[.]click, a near-miss of the real reeechka[.]club) was caught and tagged ignore instead of being passed off as a finding.

  • stopped

    Stopped on yield. With the core cluster mapped, it noted that every remaining queued pivot would only return already-defused CDN or already-graphed values — and stopped, rather than inflating the graph to look busy.

These are the behaviours that separate a usable intelligence tool from a confident-sounding one.

for defenders

Defensive takeaways.

  • early

    This is an early-warning data set. The cluster was absent from OTX, ThreatFox, Pulsedive, AlienVault, and URLhaus at the time of investigation — attribution rests on the graph evidence (origin cert SAN, shared origin, identical kit), not on third-party verdicts.

  • vector

    The distribution vector is messaging, not email. Both seeds were delivered over WhatsApp, peer-to-peer — which sidesteps email gateways entirely. Defenders relying only on mail-flow controls won't see this class of lure.

  • block

    Block the silent members first. francedancingvotingfr[.]click and panek2n[.]shop were at VT 0/94 but provably in-cluster. Pre-emptive blocking is the whole value here.

  • kit

    Hunt the kit, not just the domains. The durable fingerprint is the /home/vote* "School voting(FR/GR)" kit template — it surfaces new domains the operator hasn't burned yet.

  • abuse

    Abuse routing. Registrar abuse: Dynadot / Global Domain Group (abuse[at]dynadot[.]com) and Spaceship (abuse[at]spaceship[.]com); Cloudflare for the fronting; RIPE info[at]traffictransitsolution[.]us for the origin.

  • rotation

    Expect rotation. Registrations span 2026-04-02 → 2026-05-24; the operator mints fresh domains continuously. A recurring sweep keeps the picture current.

mitre att&ck

Technique mapping.

TechniqueIDTactic
PhishingT1566Initial Access
Acquire Infrastructure: DomainsT1583.001Resource Development
Acquire Infrastructure: Virtual Private ServerT1583.003Resource Development
Proxy: Domain FrontingT1090.004Command and Control
methodology & limitations

How this was produced — and where it stops.

Every result above came from free, passive, open sources — DNS, RDAP, crt.sh, VirusTotal, URLScan, Onyphe, AbuseIPDB, CriminalIP, OTX, ThreatFox, Pulsedive, Wayback. No active scanning, no interaction with the infrastructure, no paid feeds.

That last point is also the main limitation, and the agent was candid about it: the origin co-residency of the expanded domain set could not be confirmed because passive DNS on a bulletproof, Cloudflare-fronted host is empty on free sources. A paid Shodan/Onyphe JARM datascan would close that gap. The campaign enumeration is also deliberately incomplete — the agent capped itself and reported where more results remain.

Findings are graph-native and map cleanly to STIX 2.1, so a cluster like this can be exported as a bundle for ingestion into OpenCTI, MISP, or TheHive rather than living only as a picture.

Bounce-CTI report panel: the phishing-kit-cluster hypothesis and the structured analyst summary describing the two-seed votingFR PhaaS investigation.
Bounce-CTI report panel: MITRE ATT&CK T1566 mapping, pivot suggestions, and the full IOC list of domains, URLs, IPs, certificate fingerprints and hashes.
Figure 10 — Each investigation ends in a structured, exportable report — hypothesis, summary, MITRE mapping, pivot suggestions, and a full IOC list, ready for handoff.
indicators of compromise

IOCs.

⚠ All indicators are defanged. Re-fang at your own risk, in an isolated environment only.

URL / seed domain IP · ASN · cert · hash

Seed URLs · 2

hxxps://konkurzfrance[.]click/home/votenam hxxps://francevoice29[.]click/home/voteng

Cluster domains — core · cert / origin / kit-confirmed · 8

konkurzfrance[.]click voteingmap[.]click francedancingvotingfr[.]click panek2n[.]shop danncervotting[.]click dancorevoting[.]click reeechka[.]club francevoice29[.]click

Cluster domains — expanded · kit-identical; two VT+JARM-confirmed · 16

balletvotee38[.]click konkcurserr[.]cfd koncnckcurs[.]cfd concursere[.]cfd konkurser[.]cfd wvwrotrering[.]click vortertetre[.]lol voicefrschool1[.]cyou vovorenteng[.]click worvorting[.]click balletvotte1a[.]cfd wovovroter[.]click vvortertring[.]click vwvwroteng[.]click votingball14[.]click italyvoice215[.]click

koncnckcurs[.]cfd → DE variant · italyvoice215[.]click → IT variant

Origin

217.145.226[.]186 AS205775 · NEON CORE NETWORK LLC / TrafficTransitSolution LLC 217.145.226[.]0/24 info[at]traffictransitsolution[.]us

Certificates

origin serial 06:97:88:8e:72:55:f2:31:11:cb:10:98:d1:ad:01:50:5d:f1 SHA-256 548b4f01a4de1a3e7858b821fae869922052a325bc3d06ddc4fb1ca17fd78497 CN voteingmap[.]click

Per-domain Let's Encrypt serials

5420c0bbb7408456c86b88fa189b1032d94 · konkurzfrance 519dfc569719b8ea46f5b4ddd07626c5ea4 · reeechka 5f4ea79faef1b2e334b562f30193ced8186 · dancorevoting 6c1c60327c5108d1a72092849793608022c · danncervotting 6484d1d71418b47bc8df0b6c25145d262f6 · voteingmap 57380cfc62b7b06211526f8e2c72f2d80cf · francedancingvotingfr 55f045cecba035d391bc75da9d494f9f9a5 · panek2n 682472d3d7ceadcc6e218ae77ed5318387a · francevoice29 69de2b5f26e2728c7d743f3ab2aaf8f94d · balletvotee38 6ad038b512021e6a840decd98b7edcbcfe6 · konkcurserr

TLS fingerprint · corroborative only — generic Cloudflare edge

JARM 27d40d40d00040d1dc42d43d00041d6183ff1bfae51ebd88d70384363d525c

Defused · benign / CDN — do not pivot

104.21.21[.]216 172.67.200[.]153 104.21.52[.]113 172.67.198[.]123

Host fingerprint

nginx/1.18.0 (Ubuntu) Python/3.10 aiohttp PhaaS panel · tcp/5001 kit path /home/vote* page title "School votingFR / votingGR / voting"

This case study was produced end-to-end by Bounce-CTI, an autonomous CTI pivoting agent, from free and passive open sources. Bounce-CTI is a research prototype. Live demo available on request.