blog.ganska.latRSS

An EasyPark smishing campaign, from SMS to live card relay

EasyPark smishing campaign: infrastructure, cloaking, and a live-relay phishing kit

A browsable version of this report, split by section with every cited evidence record one click away, is at /dossier/.

Prepared 2026-09-19 from evidence collected 2026-09-18 and 2026-09-19.

Intended readers: IT professionals and law enforcement handling this campaign, including Swedish police, CERT-SE, registrar and host abuse desks, and EasyPark’s security team. A separate blog rendering of this material, with additional redactions, is intended for a general journalist and public audience.

1. Summary

A single SMS impersonating EasyPark reached a Swedish mobile subscriber on 2026-09-18 at 16:46:15 CEST, that is 2026-09-18T14:46:15Z, from the alphanumeric sender ID InfoSMS, claiming an unpaid parking fee. [REPORTED] (2.2, 12.9) The address in it is a redirector: three 302 hops, refusing nobody, hand the visitor to a landing host serving a live-relay phishing kit. [OBSERVED] (2.3)

Confirmed from collected envelopes: four hostnames, easypank.se-45564.xyz, easypank.se-9626654.pics, avcoa.click and btalning.click, all resolving to 220.158.232.231; four NameSilo, LLC registrations on three dnsowl.com nameservers, each carrying one Let’s Encrypt certificate; and se-45564.xyz registered 6 h 55 min 17 s before the reported delivery. [OBSERVED] (4.1, 4.2, 4.3, 4.7)

The landing host applies two independent gates. A Swedish mobile-carrier connection with a mobile User-Agent was served the 140535-byte kit; the same handset 18 seconds later with a desktop User-Agent, and all 56 requests from a Tor exit on a run whose control request was healthy, were served nine bytes of Not Found. [OBSERVED] (5.1, 5.2, 5.3) A reviewer opening a reported URL from a desktop sees what looks like a campaign already taken down. [INFERRED] (3)

One session against the operators’ live backend is preserved, 930 WebSocket frames and 40 HTTP envelopes. Card number, expiry, CVV, cardholder name and phone were streamed to the server as typed, over 38 input_text frames and 17 POSTs to /JisiRmktje/api/input, before any submit; each submitted card drew a bank-identification-number lookup and a reject verdict. [OBSERVED] (7.4, 7.5, 7.8)

Two limits must not be over-read. The session was a controlled test run with fabricated data, not a real victim’s. [REPORTED] (7.1) Both cards were rejected, so no verification-code or app-approval step was ever reached. [OBSERVED] (7.1, 7.8) The second-factor relay is kit capability read from the preserved bundle, not observed behaviour of these operators. [SOURCE] (6.4, 7.1)

Inferred rather than observed: the token expiry of mint time plus eight hours (2.4), a division of labour across at least four parties, and the cash-out step, of which this investigation holds nothing (3).

Not established: any artifact of the SMS or its delivery route, whether Swedish fixed broadband passes the source-network gate, an owner name for AS38623, and any location for the operators. [INFERRED] (9.7, 11.1)

Requested actions (section 13):

Indicator What it is Confidence Full set
easypank.se-45564.xyz lure host named in the SMS; HTTP redirector [OBSERVED] 12.1
easypank.se-9626654.pics landing host; served the kit and the live relay [OBSERVED] 12.1
220.158.232.231 origin address of all four confirmed hostnames [OBSERVED] 12.3
/ESZNhaXCmd with _v=valid_<14-digit timestamp>_<32 hex> landing path and single-use token grammar [OBSERVED] 12.5
POST /JisiRmktje/api/input and the result_type socket event field exfiltration channel and the operator’s only control event [OBSERVED] 12.5, 12.8

How to read this report

Every factual sentence in this report carries one of four evidence labels:

A number with no label and no anchor does not appear in this report.

Section 12, Indicators of compromise, carries confirmed campaign infrastructure, each row beside its own evidence label. Hosts of the same phishing platform that are not this campaign’s infrastructure appear there only inside a separate table marked as such. Everything not confirmed, including certificate-transparency hostnames that share the brand misspelling but do not resolve, lives in section 9, Unconfirmed leads and claims not made, and is never repeated as fact elsewhere in this report.

2. The lure

2.1 The message

The campaign reached its target as a single SMS claiming an unpaid parking fee and threatening a fine and a damaged credit rating. [REPORTED] Two renderings of the body are preserved, in two different repositories; neither repository holds an artifact of the message itself. [REPORTED]

Rendering used by this repository (design spec lines 14-16;
osint/report/render.py:483-487). ASCII, diacritics dropped, no URL scheme:

SMS from InfoSMS: Din parkeringsavgift ar fortfarande obetald. Sen betalning
hog botesavgift samre kreditvardighet. Betala nu: easypank.se-45564.xyz/se

Rendering recorded in the kit repository (TAKEDOWN_REPORT.md:107-116).
Swedish diacritics present, https scheme present:

Din parkeringsavgift är fortfarande obetald. Sen betalning hög bötesavgift
sämre kreditvärdighet. Betala nu: https://easypank.se-45564.xyz/se

English gloss: “Your parking fee is still unpaid. Late payment, high fine, worse credit rating. Pay now: …”. [REPORTED] The brand is misspelled easypank rather than easypark. The hostname requested in the capture is easypank.se-45564.xyz, and the registrable domain behind it is se-45564.xyz, which RDAP returns as a domain object registered through NameSilo, LLC. [OBSERVED] (evidence/raw/cloak-phone/20260918T161229Z-http___easypank.se-45564.xyz_se.json, payload.url; evidence/raw/rdap/20260918T162140Z-se-45564.xyz.json, payload.raw.ldhName and payload.facts.registrar) The label to the left of that registrable domain is easypank.se, so on a narrow phone screen the visible left part of the hostname reads as a Swedish country tag rather than as a subdomain of a .xyz registration. [INFERRED]

2.2 Delivery

The sender ID was the alphanumeric string InfoSMS, which carries no originating number at recipient level. [REPORTED] (kit repository TAKEDOWN_REPORT.md:107-116) Delivery is recorded as 2026-09-18 16:46:15 CEST, that is 2026-09-18T14:46:15Z. [REPORTED] (same anchor) Both the sender ID and the delivery time rest on the recipient’s statement alone: no screenshot, PDU, message export or carrier record exists in either repository, and the receiving ROM did not retain the service-centre address, so no route artifact was recoverable from the handset. [REPORTED] (kit repository TAKEDOWN_REPORT.md:238-239)

The recipient’s own first click is not recorded either, but it can be placed. The landing URL preserved from that click carries the token _v=valid_20260918232359_861d698a2bab901a380af4686943d595, which is the URL replayed in both handset spent-token envelopes. [OBSERVED] (evidence/raw/cloak-phone/20260918T161229Z-https___easypank.se-9626654.pics_ESZNhaXCmd__v_valid_20260918232359_861d698a2bab.json and evidence/raw/cloak-phone/20260918T161229Z-https___easypank.se-9626654.pics_ESZNhaXCmd__v_valid_20260918232359_861d698a2bab.1.json, payload.url) The token’s timestamp component is an expiry set to mint time plus eight hours (2.4), so the mint time was 2026-09-18T23:23:59Z minus 8 h = 2026-09-18T15:23:59Z, or 17:23:59 CEST. [INFERRED] On the reported delivery time that puts the first click about 37 minutes after the message arrived, and it bounds the delivery time independently: the SMS was received on or before 15:23:59Z. [INFERRED]

The address in the SMS is a redirector, not the phishing page. A request to http://easypank.se-45564.xyz/se is answered with three consecutive 302 Found responses before any content is served. [OBSERVED] (evidence/raw/cloak-phone/20260918T161229Z-http___easypank.se-45564.xyz_se.json, payload.headers_text)

HTTP/1.1 302 Found                       # hop 1, scheme upgrade
Date: Fri, 18 Sep 2026 16:10:52 GMT
Location: https://easypank.se-45564.xyz/se
Server: GoFrame HTTP Server
Via: 1.1 Caddy

HTTP/1.1 302 Found                       # hop 2, hand-off to the landing host
Date: Fri, 18 Sep 2026 16:10:53 GMT
Location: http://easypank.se-9626654.pics/ESZNhaXCmd?_v=valid_20260919001053_54bbe8e57f0bad4be717b02350064502
Server: GoFrame HTTP Server
Set-Cookie: gfsessionid=1is0mob1szv2acdliknx9wqy3nq954ix; Path=/; Expires=Sat, 19 Sep 2026 16:10:53 GMT
Via: 1.1 Caddy

HTTP/1.1 302 Found                       # hop 3, scheme upgrade again
Date: Fri, 18 Sep 2026 16:10:53 GMT
Location: https://easypank.se-9626654.pics/ESZNhaXCmd?_v=valid_20260919001053_54bbe8e57f0bad4be717b02350064502
Server: GoFrame HTTP Server
Via: 1.1 Caddy

The block above is abridged to the fields discussed here; the full response headers of all three hops are in payload.headers_text of that envelope. [OBSERVED] (same envelope)

Hop 2 is where the campaign hands the visitor from the lure host to the landing host and where the gfsessionid cookie is set, with a 24-hour expiry measured from the same second as the response Date. [OBSERVED] (same envelope) Hop 2 also targets http://, so the handover travels in cleartext for one hop before hop 3 upgrades it again. [OBSERVED] (same envelope) The same three-hop shape, with the same two hosts and the same ordering, is present in the redirect chains recorded over Tor. [OBSERVED] (evidence/raw/cloak/20260918T160754Z-http___easypank.se-45564.xyz_se.json, payload.summary.redirect_chain)

The redirector itself applies no filter. It issued all three hops and a fresh token to every requester observed, including Tor exits and desktop User-Agents. [OBSERVED] (of the 56 envelopes in evidence/raw/cloak/, the 28 that start at the lure URL, each a chain of length 3, covering seven client profiles, six User-Agent strings including Windows Chrome, Linux Firefox and curl/8.5.0 plus requests sent with no User-Agent header at all) The filtering happens one host further on, at the landing page, where the same envelopes record a 404 as the final response; section 5 sets out the two gates there. [OBSERVED] (same 28 chains, payload.summary.status_code)

2.4 The _v= token

Every minted landing URL carries _v=valid_<14-digit timestamp>_<32 hex>. [OBSERVED] (30 distinct mints across evidence/raw/cloak/ and evidence/raw/cloak-phone/) Three properties of that parameter are established from the captures:

The derivation of the 32-hex component is unknown. It is consistent with a per-send or per-victim identifier, but nothing in the captured traffic or in the kit bundle shows how it is generated or what the server looks up with it. [INFERRED] A practical consequence for investigators and for abuse desks: a 404 from one of these URLs usually means a spent or expired token, not a dead site, and captures against a live campaign URL are not repeatable. [INFERRED]

2.5 The path segment

The path segment /ESZNhaXCmd is constant. It appears in all 30 observed mints, always on easypank.se-9626654.pics, never varying with the token. [OBSERVED] (same 30 chains) The same segment appears on a second campaign host: a urlscan scan of btalning.click performed at 2026-09-03T08:38:40Z recorded the URL https://btalning.click/ESZNhaXCmd?bls=QTX0es&_v=valid_20260903163832_c2d6beb87657d474a50a691f87da7674 on the same origin address. [OBSERVED] (evidence/raw/urlscan/20260918T175939Z-page.ip__220.158.232.231_.json, payload.results[4], and the identical row at payload.results[0] of evidence/raw/urlscan/20260919T105718Z-page.domain__btalning.click_.json) Those envelopes hold the scan time and the URL and nothing else about that visit: a scan at 2026-09-03T08:38:40Z carrying a token that expires at 2026-09-03T16:38:32Z, 7 h 59 min 52 s later. [OBSERVED] (same two envelopes) That interval is what the mint-plus-eight-hours rule predicts for a token minted a few seconds before the scan, so the 2026-09-03 host behaves like the 2026-09-18 one; the mint itself was not captured, and the mint time cannot be read from these envelopes except through that rule. [INFERRED] The constant path and the shared token grammar tie the two hosts to the same deployment fifteen days apart, independently of the shared origin address discussed in section 4. [INFERRED] The extra bls= parameter in the 2026-09-03 URL has no counterpart in any 2026-09-18 capture. [OBSERVED] (the same 30 mints) Nothing held here shows what it carries or which component reads it. [INFERRED]

3. How the operation works, step by step

This section walks the operation from domain registration to cash-out, one step per paragraph, each pointing at the section holding its detailed evidence.

The work is divided between at least four parties. [INFERRED] The bundle served to the victim is a multi-tenant product rather than a build made for this campaign: it carries the Swedish parking flow, an unrelated Spanish-language toll-payment and address flow, Spanish, English and Czech strings hardcoded alongside the Swedish copy (PATENTE CONSULTADA, Peaje base, Total Amount Due, Platba dokončena, one occurrence each in kit repository kit_original/assets/index-d25ac0d4.js), a Danish lang attribute over Swedish text, and no backend hostname of its own. [SOURCE] (docs/kit-analysis.md sections 1 and 6; the bundle registers one locale, locale:"dk" with a single Swedish string table, at this repository’s kit_prettified/assets/index-d25ac0d4.js:24992) The same files therefore work on any domain that serves them, which is the shape of a kit written by one party and deployed by another. [INFERRED] Deployment, registration and the live console are a second role; the SMS a third, since an alphanumeric sender ID is a bulk-messaging product a handset cannot originate; and whoever turns the authorised transaction into money a fourth, of which this investigation holds nothing. [INFERRED]

Step 1, domain registration and host setup. [OBSERVED] The lure and landing domains were registered through NameSilo, LLC: se-9626654.pics on 2026-09-09T06:43:13Z and se-45564.xyz on 2026-09-18T07:50:58Z. [OBSERVED] (evidence/raw/rdap/20260918T162141Z-se-9626654.pics.json and evidence/raw/rdap/20260918T162140Z-se-45564.xyz.json, payload.raw.events) Both delegate to ns1.dnsowl.com, ns2.dnsowl.com and ns3.dnsowl.com. [OBSERVED] (evidence/raw/dns/20260918T160849Z-se-45564.xyz.json and evidence/raw/dns/20260918T160850Z-se-9626654.pics.1.json) A Let’s Encrypt certificate for one hostname each was issued the same day as the registration beneath it: not_before 2026-09-09T05:55:00Z for easypank.se-9626654.pics, 2026-09-18T07:27:20Z for easypank.se-45564.xyz. [OBSERVED] (evidence/raw/certspotter/20260918T164232Z-se-9626654.pics.json and evidence/raw/certspotter/20260918T164231Z-se-45564.xyz.json, payload.issuances) Both hostnames resolved to 220.158.232.231. [OBSERVED] (evidence/raw/dns/20260918T160845Z-easypank.se-45564.xyz.json and evidence/raw/dns/20260918T160846Z-easypank.se-9626654.pics.json) RDAP returns that address inside the range 220.158.232.0 - 220.158.232.255, name BUCT-BD, country BD, described as BUCT COMMUNICATION, with abuse contact yennp@viettel.com.vn; urlscan scan-time data for the same address gives AS38623. [OBSERVED] (evidence/raw/rdap/20260918T162147Z-220.158.232.231.json and evidence/raw/urlscan/20260918T175939Z-page.ip__220.158.232.231_.json) Section 4 sets out the infrastructure.

Step 2, the SMS send. [REPORTED] One message reached the recipient’s handset at 2026-09-18 16:46:15 CEST, that is 2026-09-18T14:46:15Z, with the alphanumeric sender ID InfoSMS, claiming an unpaid parking fee, threatening a fine and a damaged credit rating, and carrying a single link. [REPORTED] (kit repository TAKEDOWN_REPORT.md:107-116) The sender ID and the delivery time both rest on the recipient’s statement; no artifact of the message exists, and the handset retained no service-centre address, so the delivery route is visible only in carrier records. [REPORTED] (same anchor) Section 2 holds the message and the independent bound on the delivery time; section 13 the referrals that can trace the route.

Step 3, redirector and gated landing page. [OBSERVED] The address in the SMS is a redirector: three consecutive 302 Found responses hand the visitor to a second host, set a gfsessionid cookie on the way, and mint a fresh single-use _v= token for every requester, refusing nobody: not desktop browsers, not curl, not Tor exits. [OBSERVED] (evidence/raw/cloak-phone/20260918T161229Z-http___easypank.se-45564.xyz_se.json, payload.headers_text; sections 2.3 and 2.4) The filtering is at the landing page: a source-network check and a User-Agent check, the kit served only when both pass. A Swedish mobile-carrier address with a mobile User-Agent received the 140535-byte page, the same address with a desktop User-Agent seconds later a 9-byte Not Found, and every request over Tor the same 9 bytes on a run whose control request was healthy. [OBSERVED] (evidence/raw/cloak-phone/20260918T161229Z-http___easypank.se-45564.xyz_se.json and its .1.json counterpart; section 5) The page therefore does not exist for anyone not holding a Swedish phone. [INFERRED]

Step 4, live harvesting of what the victim types. [SOURCE] A visitor who passes both gates is shown an EasyPark-branded page asking first for a vehicle registration plate and then, on a payment screen, for a card number, cardholder name, expiry, CVV and phone number; each field is streamed to the server as it is typed, over the live socket and a parallel HTTP channel, with no submit button needed. [SOURCE] (docs/kit-analysis.md sections 1 and 5) The captured session shows both channels in use, with 38 streamed field updates on the socket and 17 POSTs to the kit’s field-exfiltration endpoint /JisiRmktje/api/input. [OBSERVED] (kit repository tools/ws_evidence.jsonl; evidence/raw/har/20260919T105202Z-https___easypank.se-9626654.pics_JisiRmktje_api_input_token_755a9f6f-b4bc-4ef8-9.json and its 16 siblings) Abandoning the form therefore withdraws nothing: a partially typed card number has already left the handset. [INFERRED] Sections 6 and 7 carry the screens, field names and frames.

Step 5, automated card checking. [OBSERVED] When the payment form is submitted the client routes nothing itself and waits on a loading spinner, the next screen being the operator’s to choose. [SOURCE] (docs/kit-analysis.md section 1) The server answers the submission with a card-network lookup of the leading digits, returning issuing bank, country, scheme, card type and level together with a verdict. [OBSERVED] In the captured session two card numbers were submitted and each answered with a rejection, the first enriched to a named bank in India, the second to a card scheme and country. [OBSERVED] (frames 273, 275, 463, 509 and 513, kit repository tools/ws_evidence.jsonl) This is automated validation and enrichment of stolen cards at the moment of theft, not passive logging, sorting the cards worth working from the rest. [INFERRED] Sections 6 and 7 carry the detail.

Step 6, session relay and second-factor capture. [SOURCE] mechanism, [INFERRED] live use. The kit gives the operator a console-driven hold over the victim’s screen: the victim can be moved to a code-entry screen, to one telling them to approve a request in their bank’s app, or to one styled to imitate the target bank’s own verification; a submitted code can be rejected with an operator-written error and asked for again, another card can be demanded, and the victim can be bounced to the real easypark.com at any moment. [SOURCE] (docs/kit-analysis.md sections 1, 2 and 4) On the wire all of this arrives as the result_type event, whose content names the action; the correction behind that reading names one further wire event, reload, which this capture does not contain, while my-event, otp-valid and app-valid in the kit repository’s protocol tables are internal in-browser signals that never cross the network. [OBSERVED] (all three inbound control frames in the capture are result_type, and neither reload nor any of the internal names appears in any of the 930 frames, kit repository tools/ws_evidence.jsonl; correction at KIT_ANALYSIS.md:199-204) That is the point of the kit: the code or approval reaches a person who is at that moment entering the stolen card into the real banking flow, so the second factor authorises the attacker’s transaction rather than the victim’s, and the retry loop takes as many codes as the bank issues. [INFERRED] Both test cards were rejected, so no verification screen was reached and this step is a kit capability, not observed behaviour of these operators. [OBSERVED] (no verification submission among the 930 frames) Sections 6 and 7 carry it.

Step 7, session close. [SOURCE] On the operator’s command the victim is shown a fake payment confirmation and, three seconds later, redirected to the real https://www.easypark.com/sv-se. [SOURCE] (docs/kit-analysis.md section 1) The victim is left on the genuine brand’s site with nothing obviously wrong, which delays the moment they call their bank. [INFERRED] Section 6 carries it.

Step 8, cash-out. [INFERRED] Nothing in this investigation shows what happens to the money. A stolen second factor is worthless within minutes, so the charge, wallet provisioning or transfer it authorises must happen inside the same session, and the parking fee in the lure is cover for a transaction of a different size. [INFERRED] Section 13 sets out the referrals.

Two properties make the scheme work. The first is that the domains are disposable and young. se-45564.xyz was registered at 2026-09-18T07:50:58Z. [OBSERVED] (evidence/raw/rdap/20260918T162140Z-se-45564.xyz.json) The SMS was delivered six hours and fifty-five minutes later. [REPORTED] (kit repository TAKEDOWN_REPORT.md:107-116) The token preserved from the recipient’s own click puts them on the page inside eight hours of the registration. [INFERRED] (section 2.2) A domain that young has no reputation for a filter or blocklist to act on, and the lure and landing hosts are separate registrations, so blocking the address in the message does not block the page it leads to. [INFERRED] The second is that the two gates hide the page from everyone who is not a Swedish phone: a reviewer at a registrar, host or brand who opens the reported URL from a desktop gets nine bytes of Not Found, which looks like a campaign already taken down. [OBSERVED] (the desktop-User-Agent row in evidence/raw/cloak-phone/20260918T161229Z-http___easypank.se-45564.xyz_se.1.json; section 5) An abuse report about this campaign therefore has to carry the captured evidence, because its recipient cannot reproduce the finding. [INFERRED]

4. Infrastructure

This section holds the names, addresses, registrations, certificates and response fingerprints an abuse desk works from, each with the envelope it was read from. Every DNS answer was resolved over DNS-over-HTTPS through Tor and every registration record over RDAP; there is no whois here, so a failed lookup is a gap rather than a value from elsewhere (section 10).

4.1 Hosts and addresses

Hostname Role A record First observed Latest observation
easypank.se-45564.xyz lure host named in the SMS; HTTP redirector 220.158.232.231 2026-09-18T16:08:45Z 220.158.232.231 at 2026-09-19T10:54:51Z
easypank.se-9626654.pics landing host; serves the kit 220.158.232.231 2026-09-18T16:08:46Z no A record at 2026-09-19T10:55:12Z
avcoa.click sibling name on the same address 220.158.232.231 2026-09-18T18:14:09Z 220.158.232.231 at 2026-09-19T10:56:36Z
btalning.click sibling name on the same address 220.158.232.231 2026-09-18T18:14:15Z 220.158.232.231 at 2026-09-19T10:56:59Z

[OBSERVED] (evidence/raw/dns/20260918T160845Z-easypank.se-45564.xyz.json, evidence/raw/dns/20260919T105451Z-easypank.se-45564.xyz.json, evidence/raw/dns/20260918T160846Z-easypank.se-9626654.pics.json, evidence/raw/dns/20260919T105512Z-easypank.se-9626654.pics.json, evidence/raw/dns/20260918T181409Z-avcoa.click.json, evidence/raw/dns/20260919T105636Z-avcoa.click.json, evidence/raw/dns/20260918T181415Z-btalning.click.json, evidence/raw/dns/20260919T105659Z-btalning.click.json)

Neither registrable parent has an A record of its own, and the two easypank.* labels have no NS, MX, TXT, CNAME, SOA or AAAA records, so they are plain hostnames inside their parents’ zones. [OBSERVED] (evidence/raw/dns/20260918T160848Z-se-45564.xyz.json and evidence/raw/dns/20260918T160849Z-se-9626654.pics.json for the parents; evidence/raw/dns/20260918T160845Z-easypank.se-45564.xyz.1.json and evidence/raw/dns/20260918T160846Z-easypank.se-45564.xyz.json with its .1 to .4 siblings, and evidence/raw/dns/20260918T160847Z-easypank.se-9626654.pics.json with its .1 and .2 siblings and evidence/raw/dns/20260918T160848Z-easypank.se-9626654.pics.json with its .1 and .2 siblings, for the two hostnames)

4.2 Registrations

All four registrable domains are NameSilo, LLC registrations, IANA registrar id 1479, all delegated to ns1.dnsowl.com, ns2.dnsowl.com and ns3.dnsowl.com. [OBSERVED] (the four envelopes below, payload.raw.entities and payload.facts.nameservers)

Domain RDAP handle Registered (UTC) Expiry Envelope
se-45564.xyz D644515746-CNIC 2026-09-18T07:50:58.0Z 2027-09-18T23:59:59.0Z evidence/raw/rdap/20260919T105537Z-se-45564.xyz.json
se-9626654.pics D639688650-CNIC 2026-09-09T06:43:13.0Z 2027-09-09T23:59:59.0Z evidence/raw/rdap/20260919T105554Z-se-9626654.pics.json
avcoa.click DO_1dcdb4021fe3d6faa62b10e826192166-INAMING 2026-09-05T15:55:26.273Z 2027-09-05T15:55:26.273Z evidence/raw/rdap/20260919T105655Z-avcoa.click.json
btalning.click DO_b07f16df9e824d61205c08078811f578-INAMING 2026-09-02T08:23:58.644Z 2027-09-02T08:23:58.644Z evidence/raw/rdap/20260919T105717Z-btalning.click.json

RDAP returned the following state for each registration on 2026-09-19. [OBSERVED] (the same four envelopes, payload.raw.status, payload.raw.events and the abuse entity nested under the registrar entity)

Domain Last changed RDAP statuses Abuse contact
se-45564.xyz 2026-09-18T07:51:03.0Z server transfer prohibited, client transfer prohibited, add period abuse@namesilo.com, tel +1.4805240066
se-9626654.pics 2026-09-18T23:47:11.0Z server hold, server transfer prohibited, client hold, client transfer prohibited abuse@namesilo.com, tel +1.4805240066
avcoa.click 2026-09-10T15:55:52.041Z client transfer prohibited support@namesilo.com, tel +1.6024928198
btalning.click 2026-09-07T08:24:52.299Z client transfer prohibited support@namesilo.com, tel +1.6024928198

The same registrar publishes two different abuse addresses across these four registrations. [OBSERVED] (same four envelopes, payload.facts.abuse_email) A report covering all four registrable domains therefore has to carry both. [INFERRED]

se-9626654.pics was not on hold when first collected: at 2026-09-18T16:21:41Z it carried only the two transfer-prohibited statuses and a last-changed of 2026-09-17T09:24:08.0Z. [OBSERVED] (evidence/raw/rdap/20260918T162141Z-se-9626654.pics.json) At 2026-09-19T10:55Z it carries both hold statuses, and every record type queried in that zone answers empty. [OBSERVED] (evidence/raw/rdap/20260919T105554Z-se-9626654.pics.json; the seven DNS-over-HTTPS envelopes of 2026-09-19, evidence/raw/dns/20260919T105539Z-se-9626654.pics.json (A), evidence/raw/dns/20260919T105541Z-se-9626654.pics.json (AAAA), evidence/raw/dns/20260919T105543Z-se-9626654.pics.json (NS), evidence/raw/dns/20260919T105545Z-se-9626654.pics.json (MX), evidence/raw/dns/20260919T105547Z-se-9626654.pics.json (TXT), evidence/raw/dns/20260919T105550Z-se-9626654.pics.json (CNAME) and evidence/raw/dns/20260919T105552Z-se-9626654.pics.json (SOA), each payload.values empty) The landing domain was suspended between those two observations, which is why the host that served the kit no longer resolves; nothing here records who requested the hold, and the lure domain was not suspended. [INFERRED] (4.1)

Each zone’s SOA is served by dnsowl.com with a distinct serial: 1789718403 for se-45564.xyz, 1788936584 for se-9626654.pics, 1788623804 for avcoa.click, 1788337543 for btalning.click, all with the identical hostmaster.dnsowl.com. <serial> 7200 1800 1209600 600 tail. [OBSERVED] (evidence/raw/dns/20260918T160849Z-se-45564.xyz.4.json, evidence/raw/dns/20260918T160851Z-se-9626654.pics.1.json, evidence/raw/dns/20260918T181414Z-avcoa.click.1.json, evidence/raw/dns/20260918T181421Z-btalning.click.json)

4.3 Certificates

Certificate covers Issuer not_before not_after Cert Spotter id Envelope
easypank.se-45564.xyz C=US, O=Let's Encrypt, CN=YE1 2026-09-18T07:27:20Z 2026-12-17T07:27:19Z 17251662632 evidence/raw/certspotter/20260919T105728Z-se-45564.xyz.json
easypank.se-9626654.pics C=US, O=Let's Encrypt, CN=YE2 2026-09-09T05:55:00Z 2026-12-08T05:54:59Z 17072948686 evidence/raw/certspotter/20260919T105729Z-se-9626654.pics.json
avcoa.click C=US, O=Let's Encrypt, CN=YE1 2026-09-05T15:05:21Z 2026-12-04T15:05:20Z 17004487410 evidence/raw/certspotter/20260919T105724Z-avcoa.click.json
btalning.click C=US, O=Let's Encrypt, CN=YE1 2026-09-02T07:30:50Z 2026-12-01T07:30:49Z 16939788574 evidence/raw/certspotter/20260919T105725Z-btalning.click.json

Each certificate carries one name and no wildcard, and each query used include_subdomains=true, so these are every issuance Cert Spotter holds for the four registrable domains. [OBSERVED] (the four envelopes, payload.issuances[*].dns_names and payload.url) crt.sh holds neither of the two easypank certificates: the easypank% query, which covers both of those hostnames, returns 6 rows over two other hostnames, neither a campaign host (section 9). [OBSERVED] (evidence/raw/ct/20260919T105739Z-easypank_.json, payload.row_count and payload.names) No crt.sh query covering avcoa.click or btalning.click was run: the only .click query attempted was the structural %.se-%.click, which covers neither name and is recorded as a read timeout after three attempts. [OBSERVED] (evidence/raw/ct/20260919T111715Z-.se-.click.json, status and payload.error and payload.attempts) A crt.sh miss is not evidence that no certificate exists; for these four registrable domains Cert Spotter is the only certificate transparency source that returned an issuance here. [INFERRED]

In all four cases the certificate’s not_before precedes the RDAP registration event. [OBSERVED] (the four Cert Spotter envelopes above and the four RDAP envelopes in 4.2)

Domain Certificate not_before RDAP registration Certificate precedes by
btalning.click 2026-09-02T07:30:50Z 2026-09-02T08:23:58.644Z 53 min 8.644 s
avcoa.click 2026-09-05T15:05:21Z 2026-09-05T15:55:26.273Z 50 min 5.273 s
se-9626654.pics 2026-09-09T05:55:00Z 2026-09-09T06:43:13.0Z 48 min 13 s
se-45564.xyz 2026-09-18T07:27:20Z 2026-09-18T07:50:58.0Z 23 min 38 s

A certificate cannot be validated for a domain the requester does not yet control, so the two timestamps cannot both record when the operators took the name, and nothing in these envelopes distinguishes a registry timestamp from a registrar one or shows what the certificate authority put in not_before relative to issuance. [INFERRED] Section 11 records it as unresolved; until it is, the registration event and not the certificate is the timestamp to cite for first control of a name. [INFERRED]

4.4 The origin address

All four hostnames resolved to the single address 220.158.232.231 when they were collected on 2026-09-18, and the three that still resolve on 2026-09-19 still resolve to it. [OBSERVED] (the eight DNS envelopes in 4.1) Its reverse lookup is empty. [OBSERVED] (evidence/raw/dns/20260918T160855Z-220.158.232.231.json, PTR for 231.232.158.220.in-addr.arpa) RDAP returns the following, quoted as the envelope has it. [OBSERVED] (evidence/raw/rdap/20260919T105723Z-220.158.232.231.json)

handle:       220.158.232.0 - 220.158.232.255
startAddress: 220.158.232.0
endAddress:   220.158.232.255
ipVersion:    v4
name:         BUCT-BD
type:         ASSIGNED NON-PORTABLE
country:      BD
remarks:      description: BUCT COMMUNICATION

entity, role abuse: IRT-VIETTEL-CAMBODIA-KH
  kind:  group
  email: yennp@viettel.com.vn

entity, roles technical and administrative: BCA3-AP
  fn:    BUCT Communication administrator
  kind:  group
  tel:   +880-2-8153246
  email: admin@buctbd.com
  adr:   Suite 601-602, 5th Floor, Mahabub Plaza, 4/A, Indira Road,
         Dhaka-1215, Bangladesh, Dhaka Dhaka 1215

That object holds no autonomous system number: it has no autnum field and no occurrence of the string 38623. [OBSERVED] (same envelope) AS38623 appears in this evidence only as urlscan scan-time data on individual scans of hosts at this address, never as a routing fact collected here, and no owner name for that system exists in any envelope, so none is asserted. [OBSERVED] (evidence/raw/urlscan/20260918T175939Z-page.ip__220.158.232.231_.json, the asn field of each result; section 11)

One adjacent address appears in the evidence: 220.158.233.4, which urlscan recorded serving easypark.se-toyota.homes at 2026-08-24T10:02:57Z and easypark.se-toyota.lol at 2026-08-24T10:15:14Z, neither of them confirmed infrastructure of this campaign. [OBSERVED] (evidence/raw/urlscan/20260919T100041Z-page.server__GoFrame_HTTP_Server__AND_page.domain__easypark_.json; sections 8 and 9)

4.5 The HTTP stack

Both campaign hosts answer with the same header set. Every 404 whose headers were recorded, over Tor and from the handset alike, carries exactly these ten headers. [OBSERVED] (all 56 envelopes in evidence/raw/cloak/, payload.summary.headers; the final block of evidence/raw/cloak-phone/20260918T161229Z-http___easypank.se-45564.xyz_se.1.json, payload.headers_text)

Access-Control-Allow-Headers: *
Access-Control-Allow-Methods: *
Access-Control-Allow-Origin: *
Alt-Svc: h3=":443"; ma=2592000
Content-Type: text/plain; charset=utf-8
Date: <response time>
Server: GoFrame HTTP Server
Trace-Id: <32 hex, distinct per response>
Transfer-Encoding: chunked
Via: 1.1 Caddy

The 302 responses, two of them from the lure host and the third from the landing host, carry the same set with a Location added, without Alt-Svc on the first and third hop, and the second hop adds the Set-Cookie. [OBSERVED] (evidence/raw/cloak-phone/20260918T161229Z-http___easypank.se-45564.xyz_se.json, payload.headers_text) Trace-Id is unique per response: the 56 Tor envelopes carry 56 distinct values; the four responses of the desktop-User-Agent handset chain, three 302 and a 404, carry four distinct values, while the mobile-User-Agent chain carries three, one per 302, the 200 having none. [OBSERVED] (all 56 envelopes in evidence/raw/cloak/, payload.summary.headers; evidence/raw/cloak-phone/20260918T161229Z-http___easypank.se-45564.xyz_se.1.json and evidence/raw/cloak-phone/20260918T161229Z-http___easypank.se-45564.xyz_se.json, payload.headers_text) The gfsessionid cookie is set on exactly one response, the second redirect hop, with a 24-hour expiry measured from that response’s own Date (section 2.3). [OBSERVED] (the same handset envelope)

The 200 that served the kit carries a different set, with no Server header and no Trace-Id. [OBSERVED] (evidence/raw/cloak-phone/20260918T161229Z-http___easypank.se-45564.xyz_se.json, fourth header block)

Accept-Ranges: bytes
Access-Control-Allow-Headers: *
Access-Control-Allow-Methods: *
Access-Control-Allow-Origin: *
Alt-Svc: h3=":443"; ma=2592000
Cache-Control: no-store, no-cache, must-revalidate
Content-Length: 140535
Content-Type: text/html; charset=utf-8
Date: Fri, 18 Sep 2026 16:10:54 GMT
Etag: "12d5585e1626af891dc3c1cca51d90c6"
Last-Modified: Wed, 26 Aug 2026 08:00:40 GMT
Pragma: no-cache
Referrer-Policy: strict-origin-when-cross-origin
Via: 1.1 Caddy
X-Content-Type-Options: nosniff

The split is between responses the application generates and files it serves, so a rule keyed on Server: GoFrame HTTP Server never matches the phishing page itself, only its redirects and refusals; that banner identifies the hosting platform rather than these operators (sections 6 and 12). [INFERRED]

No content delivery network sits in front of the origin: the control request to https://example.com/ over the same Tor circuit returned Server: cloudflare, CF-RAY: a3d19acd3eec0d30-AMS and cf-cache-status: HIT, while no campaign response carries any such header. [OBSERVED] (evidence/raw/cloak-control/20260918T160737Z-https___example.com_.json; a case-insensitive grep for cf-ray, cf-cache, cloudflare, fastly and akamai over evidence/raw/cloak/, evidence/raw/cloak-phone/ and evidence/raw/kit-asset/ returns zero) Via: 1.1 Caddy shows a reverse proxy at the origin itself; whether 220.158.232.231 runs the kit or fronts another host is not established here. [INFERRED]

The static assets the landing page loads are not gated: both were retrieved over a Tor exit with a mobile User-Agent at 2026-09-18T18:09:46Z, two hours after every Tor request for the page HTML had been refused (section 5). [OBSERVED] (evidence/raw/kit-asset/20260918T180946Z-https___easypank.se-9626654.pics_assets_index-d25ac0d4.js.json and evidence/raw/kit-asset/20260918T180946Z-https___easypank.se-9626654.pics_assets_index-742a24eb.css.json)

Asset Status Bytes Content-Type Etag Last-Modified
/assets/index-d25ac0d4.js 200 444050 application/javascript; charset=utf-8 "2821cadf038408cf8d42852f3389a3bd" Wed, 26 Aug 2026 08:00:51 GMT
/assets/index-742a24eb.css 200 34797 text/css; charset=utf-8 "e0a9d2ebc25ed7bb6efecf1a149a934b" Wed, 26 Aug 2026 08:00:40 GMT

Both carry Cache-Control: public, max-age=31536000, immutable. [OBSERVED] (same two envelopes) That gap is what made offline analysis of the kit possible from a Tor exit, and it lets a third party confirm a report about one of these hosts without a Swedish handset. [INFERRED] (section 6)

4.6 Naming scheme

Element easypank.se-45564.xyz easypank.se-9626654.pics
Brand label easypank, one letter from easypark easypank
Parent prefix se- se-
Digits 45564, 5 digits 9626654, 7 digits
TLD .xyz .pics

[OBSERVED] (the envelopes in 4.1 and 4.2) What the se- prefix buys the operators is covered in section 2.1. The digit counts observed are 5 and 7, so the two differ from each other and the 5-digit case falls outside the se-<6-8 digits> of the design document, and the scheme also takes a word in place of the digits, as se-toyota.homes and se-toyota.lol show. [OBSERVED] (the envelopes in 4.1 and 4.2 for the digits, the urlscan envelope in 4.4 for the se-toyota names; section 11 for the design document’s wording) A hunting rule should key on the se- prefix and the brand typo, not on a digit count. [INFERRED]

The two sibling names use a different generation: no se- prefix and no subdomain, just a typosquat of a word a Swedish victim expects, avcoa.click against the parking operator APCOA and btalning.click against betalning, Swedish for “payment”. [INFERRED] (4.2) The discovery loop watches nine cheap top-level domains. [SOURCE] (osint/discover.py:24) Three of them, .xyz, .pics and .click, carry confirmed infrastructure here. [OBSERVED] (4.1)

4.7 Timeline of the infrastructure

Every row is [OBSERVED] except the SMS delivery, which is the recipient’s statement (section 2.2).

Timestamp (UTC) Event Anchor
2026-08-24T10:02:57Z, 10:15:14Z easypark.se-toyota.homes and .lol scanned at 220.158.233.4; naming-scheme variants, not confirmed campaign infrastructure evidence/raw/urlscan/20260919T100041Z-page.server__GoFrame_HTTP_Server__AND_page.domain__easypark_.json
2026-08-26T08:00:40Z, 08:00:51Z Last-Modified of the kit HTML and CSS, then the JS: the build the landing host later served evidence/raw/cloak-phone/20260918T161229Z-http___easypank.se-45564.xyz_se.json, evidence/raw/kit-asset/20260918T180946Z-https___easypank.se-9626654.pics_assets_index-742a24eb.css.json, evidence/raw/kit-asset/20260918T180946Z-https___easypank.se-9626654.pics_assets_index-d25ac0d4.js.json
2026-09-02T07:30:50Z Certificate not_before for btalning.click evidence/raw/certspotter/20260919T105725Z-btalning.click.json
2026-09-02T08:23:58.644Z btalning.click registered at NameSilo evidence/raw/rdap/20260919T105717Z-btalning.click.json
2026-09-03T08:38:40Z btalning.click scanned on the origin serving /ESZNhaXCmd with a _v= token (section 2.5) evidence/raw/urlscan/20260919T105718Z-page.domain__btalning.click_.json
2026-09-05T15:05:21Z Certificate not_before for avcoa.click evidence/raw/certspotter/20260919T105724Z-avcoa.click.json
2026-09-05T15:55:26.273Z avcoa.click registered at NameSilo evidence/raw/rdap/20260919T105655Z-avcoa.click.json
2026-09-06T06:30:24Z, 09:30:17Z avcoa.click scanned on the origin address evidence/raw/urlscan/20260919T105656Z-page.domain__avcoa.click_.json
2026-09-09T05:55:00Z Certificate not_before for easypank.se-9626654.pics evidence/raw/certspotter/20260919T105729Z-se-9626654.pics.json
2026-09-09T06:43:13.0Z se-9626654.pics registered at NameSilo evidence/raw/rdap/20260919T105554Z-se-9626654.pics.json
2026-09-17T09:24:08.0Z se-9626654.pics last changed, one day before the SMS; what changed is not recorded evidence/raw/rdap/20260918T162141Z-se-9626654.pics.json
2026-09-18T07:27:20Z Certificate not_before for easypank.se-45564.xyz evidence/raw/certspotter/20260919T105728Z-se-45564.xyz.json
2026-09-18T07:50:58.0Z se-45564.xyz registered at NameSilo; last changed 07:51:03.0Z evidence/raw/rdap/20260919T105537Z-se-45564.xyz.json
2026-09-18T14:46:15Z SMS delivered, 6 h 55 min 17 s after that registration [REPORTED] kit repository TAKEDOWN_REPORT.md:107-116
2026-09-18T16:07:37Z to 16:08:30Z Tor probe grid, 56 cells and 2 controls evidence/raw/cloak/, evidence/raw/cloak-control/
2026-09-18T16:10:52Z to 16:11:12Z Four handset requests; the kit served once. The range is the Date headers of the two lure-host chains; the two spent-token requests carry no response timestamp evidence/raw/cloak-phone/20260918T161229Z-http___easypank.se-45564.xyz_se.json, evidence/raw/cloak-phone/20260918T161229Z-http___easypank.se-45564.xyz_se.1.json
2026-09-18T18:09:46Z Kit JS and CSS retrieved over Tor evidence/raw/kit-asset/20260918T180946Z-https___easypank.se-9626654.pics_assets_index-742a24eb.css.json
2026-09-18T23:47:11.0Z se-9626654.pics last changed; by the next observation it was on registry and registrar hold evidence/raw/rdap/20260919T105554Z-se-9626654.pics.json
2026-09-19T10:55:12Z easypank.se-9626654.pics no longer resolves evidence/raw/dns/20260919T105512Z-easypank.se-9626654.pics.json

4.8 Vantage points

Three Tor exit addresses appear in the envelopes, recorded per request in an exit_ip field. [OBSERVED] (the envelopes counted below) No geolocation of any of them exists in this evidence, so none is asserted. [OBSERVED] (the envelopes record the exit address and nothing else about the exit; section 11)

Exit address Envelopes When
185.220.101.150 56 in evidence/raw/cloak/ and 2 in evidence/raw/cloak-control/ 2026-09-18T16:07:37Z to 16:08:30Z
171.25.193.131 2 in evidence/raw/kit-asset/ 2026-09-18T18:09Z
192.42.116.60 62 in evidence/raw/tier3-verify/ 2026-09-19T10:03:05Z to 10:06:14Z

[OBSERVED] (the exit_ip field of each of those 122 envelopes) The one capture not made over Tor is the handset session; section 5 has its path, section 10 the method.

5. Gating and cloaking

The landing host serves the phishing kit only to requests that pass two independent checks, and answers everything else with nine bytes. [INFERRED] (5.1, 5.3) This section records what each combination of source network, client and token was served, together with the control request that makes a refusal interpretable at all. It describes the operators’ access control as observed; it is not a procedure for reaching the page, and section 10 holds the constraints the capture was made under.

5.1 The observation matrix

Every row is 2026-09-18. “Fresh” means a token minted by the lure host in the same chain; “spent” means the recipient’s own SMS token, already consumed (section 2.4).

Source network User-Agent Token Result Envelope
Swedish mobile carrier, cellular LTE Android Chrome mobile fresh 200, the kit, 140535 bytes evidence/raw/cloak-phone/20260918T161229Z-http___easypank.se-45564.xyz_se.json, case lure-mobile-ua
the same handset and connection, 18 s later desktop Chrome on Windows fresh 404, 9 bytes evidence/raw/cloak-phone/20260918T161229Z-http___easypank.se-45564.xyz_se.1.json, case lure-desktop-ua
the same handset and connection Android Chrome mobile spent 404, 9 bytes evidence/raw/cloak-phone/20260918T161229Z-https___easypank.se-9626654.pics_ESZNhaXCmd__v_valid_20260918232359_861d698a2bab.json, case spent-token-mobile-ua
the same handset and connection desktop Chrome on Windows spent 404, 9 bytes evidence/raw/cloak-phone/20260918T161229Z-https___easypank.se-9626654.pics_ESZNhaXCmd__v_valid_20260918232359_861d698a2bab.1.json, case spent-token-desktop-ua
Tor exit 185.220.101.150, 28 cells from the lure URL 7 client profiles, including 3 mobile fresh, a distinct one per cell 404, 9 bytes, all 28 cells the 28 se-45564 envelopes in evidence/raw/cloak/
Tor exit 185.220.101.150, the same 28 cells against the landing URL the same 7 profiles spent 404, 9 bytes, all 28 cells the 28 861d698a2bab envelopes in evidence/raw/cloak/

[OBSERVED] (the four evidence/raw/cloak-phone/ envelopes, payload.case, payload.status_code, payload.body_length and payload.body_sha256; all 56 evidence/raw/cloak/ envelopes, payload.summary)

The 56 Tor cells are uniform: every one a status: ok envelope with status code 404, body_length 9, body sha256 0019dfc4b32d63c1392aa264aed2253c1e0c2fb09216f8e2cc269bbfb8bb49b5, Content-Type: text/plain; charset=utf-8 and exit_ip 185.220.101.150, collected between 2026-09-18T16:07:39Z and 16:08:30Z; no error cell, no other status code. [OBSERVED] (aggregation over all 56 envelopes in evidence/raw/cloak/) That body is preserved byte for byte: the ASCII string Not Found, no markup. [OBSERVED] (evidence/artifacts/0019dfc4b32d63c1392aa264aed2253c1e0c2fb09216f8e2cc269bbfb8bb49b5.html) The single 200 carries the 140535-byte kit page, sha256 a98ddbfa1083b0c6893b60c6bc019b9ffef3dbc36528e0820dc332e8d78691d8. [OBSERVED] (evidence/raw/cloak-phone/20260918T161229Z-http___easypank.se-45564.xyz_se.json, payload.body_sha256)

The 28 cells are 7 client profiles, six User-Agent strings (iPhone Safari, Android Chrome, iPad Safari, desktop Chrome, desktop Firefox and curl/8.5.0) plus requests sent with no header at all, by 2 Accept-Language values by 2 Referer values. [SOURCE] (osint/collect/cloak.py:29-61 and :64-78) Each combination was run once against each URL. [OBSERVED] (the 28 distinct payload.cell_id values, each appearing twice in evidence/raw/cloak/)

5.2 The control request

A phishing kit refusing Tor exits and a content delivery network refusing Tor exits look identical from the client side, so a run of nothing but 404s proves nothing on its own. [INFERRED] Each probe run therefore verifies the circuit first: it calls exit_identity() against check.torproject.org, fetches the non-campaign control URL https://example.com/ over the same session, and only then runs the grid, the control envelope being written before the first grid cell. [SOURCE] (osint/collect/cloak.py:99-142, the write at :142) A failed precondition writes a cloak-precondition error envelope and sends nothing to the operators. [SOURCE] (osint/collect/cloak.py:130-141) No such envelope exists, so both runs passed. [OBSERVED] (evidence/raw/ contains no cloak-precondition directory)

Both controls succeeded from the exit address that produced the 56 refusals: at 2026-09-18T16:07:37Z and 16:07:50Z, exit 185.220.101.150, status 200, 559 bytes, body sha256 ff67a9d764d6... (the control body is not stored as an artifact and its hash is therefore not a line of evidence/MANIFEST.sha256, so only the prefix is cited), Server: cloudflare. [OBSERVED] (evidence/raw/cloak-control/20260918T160737Z-https___example.com_.json and evidence/raw/cloak-control/20260918T160750Z-https___example.com_.json, payload.summary) The exit address that an unrelated site served a normal page was given nine bytes by the campaign seconds later, so the refusal is the operators’ and not the circuit’s. [INFERRED]

5.3 The two gates, isolated

Both gates sit on the landing host; the redirector in front applies no check of its own (section 2.3). [OBSERVED] (the 28 se-45564 envelopes in evidence/raw/cloak/, each a 3-hop chain ending in 404)

The two handset rows isolate the client check. Same device, same cellular connection, both chains minting their own fresh token, 18 seconds apart by the response Date headers (Fri, 18 Sep 2026 16:10:52 GMT to 16:10:54 GMT against 16:11:10 GMT to 16:11:12 GMT): only the User-Agent differed, and the result flipped from the 140535-byte kit to nine bytes. [OBSERVED] (evidence/raw/cloak-phone/20260918T161229Z-http___easypank.se-45564.xyz_se.json and its .1.json counterpart, payload.headers_text and payload.user_agent)

The Tor cells isolate the source-network check. All 28 lure-URL cells were issued a distinct fresh token by the redirector, each expiring eight hours after the second the cell was collected, and all 28 were still refused at the landing page. [OBSERVED] (the 28 se-45564 envelopes in evidence/raw/cloak/: 28 distinct _v= values in payload.summary.final_url, expiry minus eight hours falling 0 to 2 seconds from each collected_at, and payload.summary.status_code 404 in every one) Three of those seven client profiles are mobile, so a mobile client holding a valid token was refused for its network alone. [OBSERVED] (the iphone_safari, android_chrome and ipad_safari cells, 12 of those 28 envelopes) Both checks are therefore real and independent, and neither a spent token nor the client string accounts for the Tor result. [INFERRED]

5.4 What is and is not established

The conclusion those observations support, quoted as docs/site-access.md states it; this report does not go beyond it.

What is established: a Swedish mobile carrier connection is accepted; Tor is
refused. What is NOT established, because we did not run the clean test:
whether a Swedish home broadband connection with a mobile User-Agent would be
accepted. The operators most likely allowlist mobile carrier address space,
since the campaign is delivered by SMS to phones, but treat "Swedish broadband
will work" as unverified rather than fact.

The block above is [INFERRED] (docs/site-access.md, “Check 1: source network”, reasoning over the matrix in 5.1).

Two further limits apply. The refusal of the recipient’s own desktop on home wifi, which is what first made the campaign look inconsistent, rests on the recipient’s account alone: no envelope exists for that request. [REPORTED] And nothing in this evidence locates any Tor exit geographically, so what is refused is the recorded exit addresses, not a named country. [OBSERVED] (the envelopes record exit_ip and no geolocation field; sections 4.8 and 11)

5.5 Provenance of the handset requests

The four non-Tor rows were made from the handset that received the SMS, over adb, with the reporter’s authorisation; all four envelopes carry the same provenance block. [OBSERVED] (payload.provenance of the four envelopes in evidence/raw/cloak-phone/)

Field Value
device a Swedish mobile handset
method adb shell curl on a connected Android device
network a Swedish mobile carrier, on cellular data with wifi disabled
via_tor false

The handset’s device and subscriber identifiers are withheld from this published copy and are recorded in the copy held for the authorities.

The note recorded with them, verbatim:

These four requests did not go through Tor. They were made with the reporter's
explicit authorisation from the handset that received the SMS. The operators'
logs already held this address from the reporter's own click. The Tor path
could not distinguish a spent token from source-network filtering, and this
comparison does.

[OBSERVED] (same four envelopes, payload.provenance.note) Each envelope carries its exact command, of the form adb shell curl -sL -A '<user agent>' '<url>': a plain GET following redirects, with one User-Agent override and no data of any kind sent. [OBSERVED] (the four envelopes, command)

5.6 Why the finding is hard to reproduce

Three conditions must hold at once for the landing host to serve the page: the request must leave from an accepted network, the only one confirmed accepted being a Swedish mobile carrier on mobile data; it must present a mobile browser User-Agent; and it must carry a fresh, unspent token, which only the lure host mints. [INFERRED] (docs/site-access.md, “What a request must look like to be served the kit”, over the matrix in 5.1)

An Android emulator does not by itself satisfy the first. A Waydroid container sends a mobile Android User-Agent and so passes the client check, but it has no modem of its own and egresses on the host machine’s default route; where that host’s own egress is broadband, VPN or a datacentre, the case docs/site-access.md describes, the operators see that network, the source check fails, and changing the browser or its User-Agent inside the container cannot move it, because the failing check is on the network the traffic leaves from. [INFERRED] (docs/site-access.md, “Why Waydroid gets ‘Not found’”; 5.1)

The session captured under evidence/raw/har/ is the other case. A browser presenting a WayDroid User-Agent

Mozilla/5.0 (Linux; Android 13; WayDroid x86_64 Device Build/TQ3A.230901.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/146.0.7680.153 Mobile Safari/537.36

was served 200 with the 140535-byte kit body, sha256 a98ddbfa1083.... [OBSERVED] (evidence/raw/har/20260919T105202Z-https___easypank.se-9626654.pics_ESZNhaXCmd__v_valid_20260919031957_33bccaec191c.json, payload.summary.status, payload.summary.body_length, payload.summary.body_sha256 and payload.summary.request_headers) That session must therefore have left from a network the landing host accepts. [INFERRED] Which network that was is not recorded, and docs/site-access.md states only that a Swedish mobile carrier is the one egress confirmed accepted (5.4), so the path is left unstated here and in 7.2. [SOURCE] (docs/site-access.md, “What a request must look like to be served the kit”)

Section 3 sets out what a reviewer at a registrar, host or brand-protection desk sees on opening a reported URL. The refusal is not specific to these two hosts either: of the 62 EasyPark-impersonation candidate names checked from a Tor exit on 2026-09-19, none returned a phishing page, and four of the six that answered at all returned a 9-byte 404 from addresses unrelated to this campaign’s origin. [OBSERVED] (the 62 envelopes in evidence/raw/tier3-verify/, payload.verdict, payload.body_length and payload.resolves_to; section 8) The ungated static assets (section 4.5) are therefore the one part of this finding a third party can check for itself. [INFERRED]

6. The phishing kit

This section is static analysis of the preserved bundle plus one static capture of a real operator session. It describes what the code does and what an investigator or defender can key on; it is not a guide to running the kit.

6.1 Provenance and integrity

The landing host served three files: index.html (140535 bytes), assets/index-d25ac0d4.js (444050 bytes) and assets/index-742a24eb.css (34797 bytes), with sha256 hashes a98ddbfa1083... for the HTML, c8ccfd832d7f9b2e6ed47bbf455395776aec71aa22cdde790a05a1f17dd66821 for the JS and 742a24ebaf60812317b40901165eba84d506c54938607911173959dbc4c3f045 for the CSS. [OBSERVED] (evidence/raw/cloak-phone/20260918T161229Z-http___easypank.se-45564.xyz_se.json and evidence/raw/kit-asset/20260918T180946Z-https___easypank.se-9626654.pics_assets_index-d25ac0d4.js.json and evidence/raw/kit-asset/20260918T180946Z-https___easypank.se-9626654.pics_assets_index-742a24eb.css.json, payload.body_length and payload.body_sha256) The same three files preserved in this repository and in the kit repository’s own kit_original/ copy hash identically, confirming the preserved bundle matches what the host served. [SOURCE] (sha256sum against kit_original/index.html, kit_original/assets/index-d25ac0d4.js and kit_original/assets/index-742a24eb.css, both repositories)

The three files’ Last-Modified headers fall within eleven seconds of each other: 08:00:40Z for the HTML and CSS and 08:00:51Z for the JS, all on 2026-08-26, which is the kit build date. [OBSERVED] (evidence/raw/cloak-phone/20260918T161229Z-http___easypank.se-45564.xyz_se.json, payload.headers_text; evidence/raw/kit-asset/20260918T180946Z-https___easypank.se-9626654.pics_assets_index-d25ac0d4.js.json and evidence/raw/kit-asset/20260918T180946Z-https___easypank.se-9626654.pics_assets_index-742a24eb.css.json, payload.headers) The operators gate the page HTML but not these two assets, so both were retrievable over Tor; the retrieval and the gating comparison are section 4.5. [OBSERVED] (same two kit-asset envelopes, status_code: 200)

6.2 Technology and libraries

The bundle is a Vue single-page application compiled with Vite, carrying vendored banner or version-constant strings for Vue 3.5.3, vue-router v4.4.3, pinia 2.2.2, vue-i18n 10.0.4, axios 1.7.7, lodash 4.17.21 and vue-scrollto 2.20.0 (axios and lodash carry theirs as a bare code constant, not a license banner), plus a socket.io/engine.io client and a second, hand-written native WebSocket wrapper (section 6.5). [SOURCE] (grep -o -F in kit_original/assets/index-d25ac0d4.js returns at least one match for each of 3.5.3, vue-router v4.4.3, 2.2.2, 10.0.4, 1.7.7, 4.17.21 and 2.20.0; docs/kit-analysis.md sections 2 and 6) The app mounts into <div id="app"> and declares the base path /we194_cz_etc_easypark/ in its HTML <base href> tag, with the same string twice more in the JS; the runtime-fetched header.html and footer.html resolve under that path, while the two bundled asset files are referenced at the site root as /assets/index-d25ac0d4.js and /assets/index-742a24eb.css. [SOURCE] (grep -o -F 'we194_cz_etc_easypark' returns 2 in the JS; <base href="/we194_cz_etc_easypark/"> at kit_original/index.html:5, the two /assets/ references at :6023-6024 and id="app" at :6029; docs/kit-analysis.md:404-407) The captured session bears that out: five of its requests are /assets/ paths at the site root, both bundle files among them, and four are under the base path, the two runtime fragments and two favicons. [OBSERVED] (the five /assets/ and four we194_cz_etc_easypark envelopes in evidence/raw/har/, payload.summary.url)

6.3 A shared, multi-tenant template

Several details are inconsistent with a page built for this campaign alone. The HTML root element declares <html lang="da", Danish, while the visible title is Swedish (Parkeringsappen som ger dig mer tid till annat | EasyPark). [SOURCE] (kit_original/index.html:2 and :9) The JS carries a Czech confirmation string, Platba dokončena, that never renders in this campaign’s flow, and toll-payment strings (PATENTE CONSULTADA and Peaje base in Spanish, Total Amount Due in English) belonging to an unreachable /pay to /address sub-flow compiled into the same bundle. [SOURCE] (grep -o -F returns 1 for each of Platba dokončena, PATENTE CONSULTADA, Peaje base and Total Amount Due in kit_original/assets/index-d25ac0d4.js; docs/kit-analysis.md sections 1 and 6) The base-path convention itself, <random-token>_<country>_etc_<brand>, reads as a per-deployment slug generator, not a hand-built value; this deployment’s brand suffix is easypark. [SOURCE] (docs/kit-analysis.md section 6) This is one shared kit template serving several brands and countries from a single build, of which only a subset of screens is live in any one deployment. [INFERRED]

6.4 The victim-facing screens

The router table wires nine paths; the observed flow and the operator-only screens are distinguished by whether a victim-facing button pushes to them, or only an operator’s command over the socket does. [SOURCE] (docs/kit-analysis.md section 1, router table at lines 20-32)

Route Reached by Asks the victim for
/home page load vehicle registration plate number
/card submit on /home card number, cardholder name, expiry, CVV, phone
/otpValid operator command only a single one-time code (verifyCode)
/customOtpValid operator command only every custom-input field present in the operator-supplied HTML, keyed by its data-verify-key attribute (can imitate a QR code or a call-to-confirm screen)
/appValid operator command only a fallback manual code (appVerifyCode), while showing a “waiting for app approval” status
/success operator command (success) nothing; a fake confirmation, then a 3-second redirect
/pay, /address unreachable from this deployment’s /home payment amount display; full billing address (Spanish/Chilean sub-flow)
/temp operator command, transiently nothing; a bare route used to force Vue Router to re-mount a screen the victim may already be on

Seven of the eight rows cover eight of the router table’s nine paths (/pay and /address share a row). The ninth, root /, carries the same route name as /home but mounts a different component, a placeholder view that shows a spinner for two seconds and asks for nothing. The eighth row, /temp, is not a router path at all; it is a componentless remount-only path. [SOURCE] (docs/kit-analysis.md section 1, router table at lines 20-32, /temp at line 32; the two components are Bw, wrapping IndexView, and jT, wrapping HomeView, in kit_original/assets/index-d25ac0d4.js) A card rejection returns the victim to /card with an operator-written message rather than to any dead end, and kickOut or block end the session by redirecting to the real easypark.com. [SOURCE] (docs/kit-analysis.md sections 1 and 2)

6.5 Transport and the operator’s control channel

A session opens with an empty POST to /JisiRmktje/api. [SOURCE] (docs/kit-analysis.md section 3, lines 236-239; grep -o -F '/JisiRmktje/api' returns 2 in kit_original/assets/index-d25ac0d4.js, the standalone bootstrap path and the /input variant counted together) The response carries a server-issued relay token, a transport-mode flag, and a per-campaign text block (pay_amount, error_card_msg, deny_c_msg, deny_d_msg among its keys). [SOURCE] (docs/kit-analysis.md section 3, lines 242-255) The relay token opens wss://<host>/ws?token=<token>, present twice in the JS; depending on the mode flag this is wrapped either by the bundled socket.io client (mode 2) or by the kit’s own native WebSocket class (any other mode). [SOURCE] (grep -o -F '/ws?token=' returns 2 in the JS; docs/kit-analysis.md section 3, line 254 and section 2, lines 125-136) The two do not converge as cleanly as that shared URL suggests: in socket.io mode the library treats /ws as a namespace, while the engine.io handshake itself runs over the library’s default /socket.io path on the same host, so a network rule keyed only on /ws would miss that mode. [SOURCE] (docs/kit-analysis.md:135) The captured session used only the native-WebSocket path: all 930 frames carry host: easypank.se-9626654.pics and path: /ws?token=755a9f6f-b4bc-4ef8-9118-171fec4947f7, none /engine.io, and the HAR capture of the same session shows a single direct /ws upgrade with no /socket.io handshake request. [OBSERVED] (kit repository tools/ws_evidence.jsonl, all 930 records; evidence/raw/har/20260919T105202Z-https___easypank.se-9626654.pics_ws_token_755a9f6f-b4bc-4ef8-9118-171fec4947f7.json)

The envelope shape varies by direction and message type: of the 930 frames, 538 (all operator-side) carry {event, content, messageId}, e.g. {"event":"login","content":"success","messageId":"ederjq01000dliooq67h2ldmjq3cuvce"}; 349 (all victim-side heartbeat frames) carry only {event, content}; and 43 (the remaining victim-side frames) carry all four fields, {event, content, messageId, timestamp}. [OBSERVED] (kit repository tools/ws_evidence.jsonl, all 930 records, raw field parsed as JSON; counts by field set and dir) The victim side sends five distinct wire events: login, heartbeat, page_type (a beacon fired on every screen mount), input_text (see 6.6) and submit_card. [SOURCE] (docs/kit-analysis.md section 2, lines 173-181) The frames the capture actually contains match this, from the victim side: login 1, page_type 2, input_text 38, submit_card 2, heartbeat 349. [OBSERVED] (tools/ws_evidence.jsonl, event counts by dir: victim->c2)

The operator’s control verbs arrive on one event, result_type, whose content.type field carries the verb: the source lists otpValid, appValid, customOtpValid, success, kickOut, block, otpFail, appFail, customOtpFail, back, reject and refresh. [SOURCE] (docs/kit-analysis.md section 2, lines 183-213) The kit repository’s own correction names one further wire event alongside it, reload. [SOURCE] (kit repository KIT_ANALYSIS.md:199-204) No reload frame appears in this capture. [OBSERVED] (tools/ws_evidence.jsonl, zero occurrences of reload in any of the 930 records) The capture holds exactly three result_type frames, at records 275, 509 and 513, every one carrying type: reject. [OBSERVED] (tools/ws_evidence.jsonl, records 275, 509, 513) A companion internal, in-browser event bus (mitt-style, named Qn in the source) relays some of those verbs to the mounted Vue component under separate names, my-event, otp-valid, app-valid and custom-otp-valid; it never touches the network. [SOURCE] (docs/kit-analysis.md section 2, lines 214-223) An earlier draft of the kit repository’s own analysis listed those internal names as wire events; its correction states that “Detection/monitoring should key on WS result_type, not on otp-valid as a frame name.” [SOURCE] (kit repository KIT_ANALYSIS.md:199-204) None of the four internal names appears in any of the 930 captured frames, consistent with that correction. [OBSERVED] (tools/ws_evidence.jsonl, zero matches for my-event, otp-valid, app-valid or custom-otp-valid as an event value)

6.6 The two exfiltration paths

Everything the victim types is sent twice, on two independent channels, before any submit button is pressed, except in socket.io mode: the shared debounce helper ends o(e,t,n),_m.value!==2&&a(e,t,n), so the HTTP send (a) fires only when _m.value!==2 and is skipped when the backend’s mode flag sets it to 2. [SOURCE] (kit_original/assets/index-d25ac0d4.js, matching o(e,t,n),_m.value!==2&&a(e,t,n); docs/kit-analysis.md section 3, line 254 and section 5, lines 367-373) The captured session ran in the native-WebSocket mode that performs both sends (6.5). Over the socket, each field fires an input_text event, debounced 300 ms per field. [SOURCE] (docs/kit-analysis.md section 5, lines 367-370) In parallel, the same field fires an HTTP POST to /JisiRmktje/api/input, debounced 1000 ms per field; that path also carries the final submit_card record as a fallback whenever the socket is unreachable. [SOURCE] (docs/kit-analysis.md section 3, lines 271-283; grep -o -F '/JisiRmktje/api/input' returns 1 in kit_original/assets/index-d25ac0d4.js) The completed card record itself (cardNumber, cardName, expires, cvv, phone) is otherwise sent only once, as a single submit_card socket event, once the form is submitted. [SOURCE] (docs/kit-analysis.md section 3, lines 284-293)

The kit repository’s own takedown report states the opposite: “All stolen data leaves over WebSocket… HTTP POSTs in the bundle are only the engine.io polling fallback to /engine.io.” [SOURCE] (kit repository TAKEDOWN_REPORT.md:225-231) That is contradicted by direct observation: the captured session’s HAR log holds 17 POST envelopes to /JisiRmktje/api/input on the landing host, plus one POST to the bootstrap endpoint /JisiRmktje/api, and no /engine.io request anywhere in the capture. [OBSERVED] (evidence/raw/har/20260919T105202Z-https___easypank.se-9626654.pics_JisiRmktje_api_input_token_755a9f6f-b4bc-4ef8-9.json, one of 17 matching envelopes in evidence/raw/har/) The session’s WebSocket capture shows the same absence (6.5): none of its 930 frames carry /engine.io. [OBSERVED] (kit repository tools/ws_evidence.jsonl, all 930 records) A monitoring rule that treats /JisiRmktje/api/input as mere polling overhead would miss a genuine, continuous exfiltration channel. [INFERRED]

6.7 Session token persistence

A client-generated UUIDv4 device token is stamped as Token and X-Token request headers and a token query parameter on every HTTP request through the app’s shared axios instance, and is synced to a cookie named token (max-age=34560000, 400 days, SameSite=Lax), to localStorage, to sessionStorage, and to an IndexedDB database (TokenDB, store tokens, key userToken). [SOURCE] (docs/kit-analysis.md section 3, lines 258-268 and section 6; grep -o -F each returning 1 in kit_original/assets/index-d25ac0d4.js for headers.Token, X-Token, TokenDB, userToken and max-age=34560000) The cookie’s use is directly observed: all 17 captured field-exfiltration POSTs carry Cookie: token=755a9f6f-b4bc-4ef8-9118-171fec4947f7. [OBSERVED] (evidence/raw/har/20260919T105202Z-https___easypank.se-9626654.pics_JisiRmktje_api_input_token_755a9f6f-b4bc-4ef8-9.json, payload.summary.request_headers.cookie) This identifies the victim’s browser across reloads and across clearing that removes only one of the four storage locations; per source it is generated independently of the relay token /JisiRmktje/api issues to open the socket, though in this captured session the cookie value and the relay token are identical, an unresolved discrepancy. [INFERRED]

6.8 Cross-domain fingerprints and detection

None of the following depends on this campaign’s hostnames: a search of the bundle for easypank, se-9626654, se-45564 and .pics returns zero matches each, confirming the kit ships with no hardcoded backend host or IP. [SOURCE] (grep -o -F counts of 0 for each string in kit_original/assets/index-d25ac0d4.js; docs/kit-analysis.md section 6)

Fingerprint Where Specificity
/JisiRmktje/api and /JisiRmktje/api/input HTTP paths almost certainly kit-generated, not a framework default
<random>_<cc>_etc_<brand> base-path pattern <base href> and asset URLs naming convention; brand and country vary per deployment
wss://<host>/ws?token= combined with Token/X-Token headers live-relay transport distinctive as a combination; /ws alone is too generic
{event, content} socket envelope (operator frames add messageId; non-heartbeat victim frames add timestamp too) with inner events page_type, submit_card, input_text wire protocol shape useful only if a sibling’s socket traffic is captured
index-d25ac0d4.js / index-742a24eb.css content hashes exact asset filenames strongest but narrowest: identical only for this exact build

[SOURCE] (docs/kit-analysis.md section 7, lines 419-427; the parenthetical in the socket-envelope row is the field-set count of the captured frames, 6.5) These are kit-code fingerprints, independent of the Server: GoFrame HTTP Server / Via: 1.1 Caddy hosting-platform signature discussed in section 4, which identifies the phishing platform rather than the kit or this campaign. [INFERRED] The two most durable of them for live monitoring are the result_type wire event and the JisiRmktje path segment, since neither is generated from the hostname and both would survive a domain and IP rotation this kit’s operators have not yet been observed to make. [INFERRED] (6.5, 6.6, this section)

7. The captured live session

One full session against the operators’ live backend is preserved, on both of its channels: 930 WebSocket frames in the kit repository’s tools/ws_evidence.jsonl, and the 40 HTTP requests of the same browser session as envelopes under evidence/raw/har/. [OBSERVED] (930 records in tools/ws_evidence.jsonl, all carrying host easypank.se-9626654.pics and path /ws?token=755a9f6f-b4bc-4ef8-9118-171fec4947f7; 40 envelopes in evidence/raw/har/, all status: ok and all payload.capture kit-2026-09-18) This section reports what those two records contain.

7.1 What the session was

The session was a controlled test, run with junk data to record the backend’s behaviour: “This is a controlled test session using junk data, but it exercises the real C2 end to end.” [REPORTED] (kit repository TAKEDOWN_REPORT.md:189-190) The values typed were the registration plate boy635, card number 1111111111111111 and then 5204480010000005, cardholder name Bosse Bildoktor, expiry 01/01 corrected to 01/30, CVV 123 and phone 07129284829. [OBSERVED] (the 38 input_text frames and the two submit_card frames, tools/ws_evidence.jsonl; frames 273 and 463 carry the full submitCard form) The card numbers are junk by construction: 1111111111111111 fails a Luhn check, and both were rejected by the operators’ own validation (7.5). [INFERRED]

What the session exercised was real: every request in the record went to, and every response came from, the campaign’s own hosts. [OBSERVED] (host and path of all 930 frames in tools/ws_evidence.jsonl; payload.summary.url of all 40 envelopes in evidence/raw/har/, every one under easypank.se-9626654.pics or easypank.se-45564.xyz)

No verification-code or app-approval step was ever reached: both cards were rejected, and none of the 930 frames carries a code submission, a code-entry page transition or any of the kit’s second-factor verbs. [OBSERVED] (event counts over tools/ws_evidence.jsonl: heartbeat 838, ack 43, input_text 38, login 3, result_type 3, page_type 2, submit_card 2, connect 1, and zero occurrences of verifyCode, submitValidCode, otpValid, appValid, otp-valid, app-valid or my-event in the file) The second-factor screens and the operator-driven navigation described in section 6 are therefore kit capability read from the bundle, not behaviour observed of these operators. [INFERRED]

7.2 Capture method and network path

The traffic was recorded by a proxy sitting in front of an Android browser: all 40 envelopes present an Android User-Agent, and 39 also carry x-requested-with naming the handset’s browser package, withheld here with the other device identifiers; the exception is the WebSocket upgrade request, which lacks it. [OBSERVED] (the 40 envelopes in evidence/raw/har/, payload.summary.request_headers) The envelopes’ recorded command reads the capture back with mitmdump -r <capture> --set hardump=kit-2026-09-18.har, which is where the 40 envelopes come from, written on 2026-09-19. [OBSERVED] (the 40 envelopes in evidence/raw/har/, command and collected_at 2026-09-19T10:52:02Z) The kit repository states the method as the page opened in Waydroid with traffic through mitmproxy, decoded with tools/ws_capture.py; no artifact of the capture host exists in either repository. [REPORTED] (kit repository TAKEDOWN_REPORT.md:104-105 and README.md:51)

The capture’s network path is not recorded in either repository: the kit repository gives the method but no egress, and the envelopes carry no provenance block of the kind the handset requests carry (5.5). [SOURCE] (kit repository TAKEDOWN_REPORT.md:104-105 and README.md:51; the 40 envelopes in evidence/raw/har/, whose payload keys are capture, har_file and summary only) docs/site-access.md states only that a Swedish mobile carrier is the one egress confirmed accepted, so no network follows from the fact that the kit was served. [SOURCE] (docs/site-access.md, “What a request must look like to be served the kit”; 5.4) Section 5.6 records the same gap for the 200 that served the kit to this session’s WayDroid User-Agent.

7.3 Reading the timestamps

The per-record time field is not the capture time. It is identical in all 930 records, 2026-09-18T22:13:19. [OBSERVED] (one distinct time value across all 930 records of tools/ws_evidence.jsonl) That is the wall clock of the offline decode run, since the decoder stamps each line as it writes it. [INFERRED] (kit repository tools/ws_capture.py:54) The real times are inside the frames. Every victim-to-server frame other than a heartbeat carries an epoch-ms timestamp, 43 of them, spanning 1789759200876 to 1789759512954, that is 2026-09-18T19:20:00.876Z to 19:25:12.954Z, 21:20:00.876 to 21:25:12.954 CEST. [OBSERVED] (parse of the raw field of all 930 records: the 43 frames carrying a timestamp are exactly the 43 non-heartbeat victim-to-server frames) Server-to-victim frames carry no timestamp, which is why the operator rows below have no time of their own. [OBSERVED] (same parse) The server’s own heartbeats carry content.time in epoch seconds, 349 of them from 1789759202 to 1789759899, that is 19:20:02Z to 19:31:39Z, 21:20:02 to 21:31:39 CEST, so the socket stayed open for six minutes and twenty-six seconds after the last victim frame carrying a timestamp, frame 463 at 19:25:12.954Z. [OBSERVED] (the 349 server-to-victim heartbeat records of tools/ws_evidence.jsonl that carry a content.time field, against frame 463)

7.4 The session timeline

Frame numbers are 1-based lines of the kit repository’s tools/ws_evidence.jsonl; times are each frame’s own embedded timestamp. [OBSERVED] (the parse above; the same rows appear in the kit repository’s tools/APPENDIX_session.txt:1-18)

Frames CEST UTC Direction Event
1 – – server to victim login ack success
3 21:20:00.876 19:20:00.876Z victim to server login, tag user, token 755a9f6f-b4bc-4ef8-9118-171fec4947f7, isFirst false
6 – – server to victim login ack success
7 21:20:01.705 19:20:01.705Z victim to server page_type home
42-49 21:20:29.517 19:20:29.517Z victim to server input_text plate, 3 frames, final boy635
56 21:20:36.624 19:20:36.624Z victim to server page_type card
72-183 21:20:47.896 19:20:47.896Z victim to server input_text cardNumber, 11 frames, final 1111111111111111
187-192 21:22:05.729 19:22:05.729Z victim to server input_text expires, 3 frames, final 01/01
196 21:22:07.958 19:22:07.958Z victim to server input_text cvv, 1 frame, 123
205-218 21:22:14.137 19:22:14.137Z victim to server input_text cardName, 5 frames, final Bosse Bildoktor
220-246 21:22:17.920 19:22:17.920Z victim to server input_text phone, 9 frames, final 07129284829
259-267 21:22:35.230 19:22:35.230Z victim to server input_text expires, 3 frames, final 01/30
273 21:22:42.099 19:22:42.099Z victim to server submit_card, first card
275 – – server to victim result_type reject, errorCard
449-455 21:25:06.283 19:25:06.283Z victim to server input_text cardNumber, 3 frames, final 5204480010000005
463 21:25:12.954 19:25:12.954Z victim to server submit_card, second card
509 – – server to victim result_type reject
513 – – server to victim result_type reject

[OBSERVED] (frame indices, events, directions, embedded timestamps and content of every row above, read from tools/ws_evidence.jsonl)

The burst end times are absent from the appendix and they matter. [OBSERVED] (kit repository tools/APPENDIX_session.txt:1-18, which gives each burst’s start time and frame count but not its last frame’s time) The card-number burst began at 21:20:47.896 CEST, and its last frame, frame 183, at 21:22:03.665 CEST (19:22:03.665Z), already carried the complete sixteen digits. [OBSERVED] (frames 72 to 183, tools/ws_evidence.jsonl) That is 38.4 seconds before the submit at frame 273: the full number was on the server well before anything was submitted, so closing the page then would have withdrawn nothing. [INFERRED]

The plate field is streamed under a different shape from the card fields: the plate frames carry type Registreringsnummer while every card field carries type input_card. [OBSERVED] (frame 42 against frames 72 to 267, tools/ws_evidence.jsonl)

7.5 The operator side

Three frames in the whole session travel from the server as control messages, all of them result_type, the single wire event that carries every operator command (section 6); each carries a verdict and a bank-identification-number lookup of the leading digits. [OBSERVED] (frames 275, 509 and 513, tools/ws_evidence.jsonl) Frame 275, answering 1111111111111111, carries type reject, an inner value.type errorCard, and cardBIN {"bin": 111111, "bank": "CENTRAL BANK OF INDIA", "country": "INDIA", "schema": "LOCAL BRAND", "type": "DEBIT", "level": "CLASSIC"}. [OBSERVED] (frame 275) Frames 509 and 513, answering 5204480010000005, carry type reject with no inner value.type, cardBIN {"bin": 520448, "bank": "", "country": "UNITED STATES", "schema": "MASTERCARD", "type": "DEBIT", "level": ""}, and a Swedish error string for the victim, message2 Betalningen misslyckades. [OBSERVED] (frames 509 and 513)

Frame 275 falls between heartbeats at 19:22:41Z (frame 272) and 19:22:43Z (frame 277), about a second after the submit at frame 273, 19:22:42.099Z: the first verdict came back essentially as the card arrived. [OBSERVED] (frames 272, 275 and 277 against frame 273, tools/ws_evidence.jsonl) That immediacy does not hold for the second card: frames 509 and 513, both answering frame 463 (19:25:12.954Z), fall between heartbeats bracketing them at 19:25:48Z-19:25:50Z and 19:25:50Z-19:25:53Z, roughly 35 and 37 seconds later. [OBSERVED] (frames 508, 509, 512, 513 and 515 against frame 463, tools/ws_evidence.jsonl) A delay that long fits a human operator choosing the next step, as section 6.5 describes, better than grading on arrival. [INFERRED] (section 6.5)

Frames 509 and 513 also return a server-built cardHistory array with a submitTime per card, 2026-09-19 03:25:13 for frame 463’s card and 03:22:42 for frame 273’s, each eight hours ahead of that frame’s own UTC timestamp to the nearest second (19:25:12.954Z and 19:22:42.099Z, the first rounded up by 46 ms and the second truncated). [OBSERVED] (frames 509 and 513, value.data.cardHistory, against frames 273 and 463) The backend’s application clock is therefore set to UTC+8, six hours ahead of the victim’s own CEST display, which says nothing about where the operator sits. [INFERRED]

Nothing else was sent from the operator side: the remaining server-to-victim frames are 489 heartbeats, 43 acks, two login acknowledgements and one connect carrying {"ping_interval": 5, "ping_timeout": 30}. [OBSERVED] (event and direction counts over tools/ws_evidence.jsonl; frame 2 for the connect content)

7.6 The session token

One token identifies the victim throughout: 755a9f6f-b4bc-4ef8-9118-171fec4947f7. It is the path query parameter of all 930 WebSocket frames, the login payload of frame 3, the cookie and the token and x-token request headers of the session-bootstrap POST, the Token in that POST’s response, and the query string of all 17 field-exfiltration POSTs. [OBSERVED] (tools/ws_evidence.jsonl path field and frame 3; evidence/raw/har/20260919T105202Z-https___easypank.se-9626654.pics_JisiRmktje_api_token_755a9f6f-b4bc-4ef8-9118-17.json, payload.summary.request_headers and the stored response body evidence/artifacts/e3eaf9aa94f833e92c3e09df408c03dd98ba0675f7f6a878bbe1692b566d1e66.bin) The cookie already carries the token on that first bootstrap request, and no Set-Cookie for it appears anywhere in the 40 envelopes; the only Set-Cookie in the capture is the gfsessionid on the second redirect hop. [OBSERVED] (the bootstrap envelope above, payload.summary.request_headers; evidence/raw/har/20260919T105202Z-https___easypank.se-45564.xyz_se.json, the only envelope with a set-cookie response header) That is what a first load looks like, not evidence of an earlier visit: the token is generated client-side, stamped into the cookie (and localStorage, sessionStorage and IndexedDB), and attached to every outgoing request by an interceptor, bootstrap included. [INFERRED] (section 6.7)

That bootstrap response is also where the backend configures the page for the victim: it returns "country":"SE", "mode":1, "isFirst":true and a custom block of operator-editable message strings, one of them the Swedish Det här kortet stöds inte. Var god byt ut det. [OBSERVED] (evidence/artifacts/e3eaf9aa94f833e92c3e09df408c03dd98ba0675f7f6a878bbe1692b566d1e66.bin, 418 bytes) That isFirst disagrees with the relay login frame, which carries isFirst false (7.4, frame 3); section 11 covers the discrepancy. [OBSERVED] (frame 3, tools/ws_evidence.jsonl, against the bootstrap response above)

7.7 The HTTP requests of the same session

The 40 har envelopes cover the same browser session, 2026-09-18T19:14:36Z to 19:25:08Z, and store response bodies only: the envelope schema has no request-body field, so what the browser POSTed is recoverable only from the WebSocket frames. [OBSERVED] (payload.summary.started_at of the 40 envelopes; payload.summary keys are body_length, body_sha256, host, method, mime_type, request_headers, response_headers, started_at, status, url)

Time (UTC) Request Status Bytes Body sha256
19:14:36.256 GET landing /ESZNhaXCmd?_v=valid_20260918232359_861d698a2bab... 404 9 0019dfc4b32d...
19:14:36.577 GET landing /favicon.ico 404 9 0019dfc4b32d...
19:19:54.024 GET http://easypank.se-45564.xyz/se no response recorded 0 –
19:19:54.222 GET http://easypank.se-45564.xyz/se 302 5 b0ee315f4ac6...
19:19:55.283 GET https://easypank.se-45564.xyz/se 302 5 b0ee315f4ac6...
19:19:55.572 GET landing /ESZNhaXCmd?_v=valid_20260919031955_b48ac3f511fe2... over HTTP 302 5 b0ee315f4ac6...
19:19:56.136 GET the same landing URL over HTTPS no response recorded 0 –
19:19:56.214 GET http://easypank.se-45564.xyz/se no response recorded 0 –
19:19:56.398 GET http://easypank.se-45564.xyz/se 302 5 b0ee315f4ac6...
19:19:56.945 GET https://easypank.se-45564.xyz/se 302 5 b0ee315f4ac6...
19:19:57.197 GET landing /ESZNhaXCmd?_v=valid_20260919031957_33bccaec191cb... over HTTP 302 5 b0ee315f4ac6...
19:19:57.453 GET the same landing URL over HTTPS 200 140535 a98ddbfa1083...
19:19:58.602 GET /assets/index-742a24eb.css 200 34797 742a24ebaf60...
19:19:58.605 GET /assets/index-d25ac0d4.js 200 444050 c8ccfd832d7f...
19:19:59.436 GET /we194_cz_etc_easypark/favicon-16x16.png 200 493 0a33c850d00d...
19:19:59.439 GET /we194_cz_etc_easypark/favicon-32x32.png 200 906 4182ef039afa...
19:19:59.803 POST /JisiRmktje/api?token=755a9f6f-... 200 418 e3eaf9aa94f8...
19:20:00.631 GET /ws?token=755a9f6f-..., WebSocket upgrade 101 0 e3b0c44298fc...
19:20:00.883 GET /we194_cz_etc_easypark/header.html 200 383237 60ef3826e47c...
19:20:01.416 GET /we194_cz_etc_easypark/footer.html 200 53375 03049f61761e...
19:20:36.626 GET /assets/default-d2edf42c.svg 200 630 d2edf42ccc57...
19:22:42.111 GET /assets/80066acd3fcfa-80066acd.svg 200 1312 80066acd2096...
19:25:07.692 GET /assets/d9f501073fcfa-d9f50107.svg 200 9499 d9f50107aa84...
19:20:30 to 19:25:08, 17 requests POST /JisiRmktje/api/input?token=755a9f6f-... 200 each 33 each 973a77295b63... each

[OBSERVED] (the 40 envelopes in evidence/raw/har/, payload.summary.method, url, status, body_length, body_sha256 and started_at; “landing” is easypank.se-9626654.pics) Full hashes: 0019dfc4b32d63c1392aa264aed2253c1e0c2fb09216f8e2cc269bbfb8bb49b5, b0ee315f4ac6af09d05f9e6f23ffb606f3b4fec1ba897bd4315592d2a2979876 (the body Found), 973a77295b63aeb2bc2d960f68ff5698bf5d09746aa8f3f2418e4144c133715f (the body {"code":0,"message":"","data":{}}), e3eaf9aa94f833e92c3e09df408c03dd98ba0675f7f6a878bbe1692b566d1e66, e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855, 60ef3826e47cb004d36b418c4f9a372dc719077aa96130a4f43091c1db3db8b2, 03049f61761eca5519531b5069b52775a55b06a1a02b445bbd0dea3c0667d6c7, 0a33c850d00dc1f91d4634eaf02dd2d020d6a86731f67daed548fb3c9c50ad42, 4182ef039afa0be9d9a6e3537921f8ed913b0768e76a1233395c800536ba4161, d2edf42ccc57441bebe758887091cef7b5c94ada72b2f9b2b991a25a5755ec42, 80066acd2096893762dab64b37b03c9de576e948372ac516f05d25f2b1cc988f, d9f50107aa842d19b7f4bac799d3e6199c2fdbc8c3197f4305b292bb0db143b6; the page body is a98ddbfa1083b0c6893b60c6bc019b9ffef3dbc36528e0820dc332e8d78691d8 and the two assets are as in section 6.1. [OBSERVED] (the same envelopes; every one of these hashes is listed in evidence/MANIFEST.sha256)

Four things in that list are worth naming. The capture opens at 19:14:36Z with a request carrying the recipient’s own, already spent SMS token, answered with the same nine bytes of Not Found as every other refused request, five minutes before the working chain. [OBSERVED] (evidence/raw/har/20260919T105202Z-https___easypank.se-9626654.pics_ESZNhaXCmd__v_valid_20260918232359_861d698a2bab.json; section 2.4) The working chain, the three 302 hops of section 2.3, runs twice: the first attempt’s landing request has no response recorded, and the second, with a freshly minted _v=valid_20260919031957_33bccaec191cb..., is answered 200 with the 140535-byte kit page. [OBSERVED] (the ten envelopes between 19:19:54 and 19:19:57 listed above, payload.summary.status) The WebSocket upgrade at 19:20:00.631Z is answered 101 with Server: Caddy, and the first relay frame carries a timestamp 245 milliseconds after it, tying the two records to one session. [OBSERVED] (evidence/raw/har/20260919T105202Z-https___easypank.se-9626654.pics_ws_token_755a9f6f-b4bc-4ef8-9118-171fec4947f7.json against frame 3 of tools/ws_evidence.jsonl) And the 17 POSTs to /JisiRmktje/api/input fall between 19:20:30 and 19:25:08, interleaved with the input_text typing bursts of that window (7.4), each answered with the same 33-byte acknowledgement. [OBSERVED] (the 17 envelopes) The bundle identifies that path as a per-field HTTP exfiltration channel alongside the socket. [SOURCE] (docs/kit-analysis.md:271, “/JisiRmktje/api/input - HTTP exfiltration channel”) Against this capture, the kit repository’s statement that the bundle’s only HTTP POSTs are an engine.io polling fallback does not hold; section 6.6 covers that contradiction. [INFERRED] (section 6.6)

7.8 What the capture proves, and what it does not

Proved by the frames and envelopes above: card number, expiry, CVV, cardholder name and phone are streamed to the operators’ server as typed, before and independently of any submit [OBSERVED] (the 38 input_text frames of tools/ws_evidence.jsonl, with the 17 field POSTs of evidence/raw/har/ running in parallel); the full card record is sent again on submit [OBSERVED] (frames 273 and 463); the server runs a bank-identification-number lookup and returns an enriched verdict, promptly for the first card and after a longer delay for the second (7.5) [OBSERVED] (frames 275, 509 and 513); and one per-victim token binds the whole session together, giving the operator a single live row to work [OBSERVED] (section 7.6).

Not proved by it: anything about second-factor relay in practice, since no verification screen was reached and no code or approval was ever submitted, so section 6’s account of those screens rests on the bundle alone [OBSERVED] (the event counts over tools/ws_evidence.jsonl in 7.1); nor what the operators do with a card they accept, or where they are, since the only location-shaped datum in the session is a backend clock set to UTC+8. [INFERRED] (7.5)

8. The wider platform cluster

Sections 4 and 5 establish the four confirmed hosts and the two gates that protect them. This section looks outward, at other domains served by the same phishing platform and impersonating the same brand. None of it is offered as this campaign’s infrastructure. [INFERRED] It is preserved because it shows the scale and disposability of the platform the campaign runs on, and because a future capture from a live cluster member, made the same way section 5’s handset capture was made, is the only thing that could turn a member of this set into a confirmed sibling.

8.1 The query is never the fingerprint alone

The backend fingerprint common to every campaign host, Server: GoFrame HTTP Server behind Via: 1.1 Caddy (4.5), also answers on a very large number of unrelated domains, so a search on that header by itself is not a lead: it returns the platform, not an operator. [SOURCE] (osint/discover.py:8-10: “The fingerprint alone is useless as a lead … It is only ever combined with another term.”) The codebase’s own infrastructure-pivot queries enforce that rule by construction, always pairing the header with an AS term (osint/discover.py:28-32). The two urlscan queries behind this section were run by hand, not by that function, but follow the same rule: each pairs the platform header with a brand or AS term, never the header alone. [INFERRED] (evidence/raw/urlscan/20260919T100041Z-page.server__GoFrame_HTTP_Server__AND_page.domain__easypark_.json and 20260919T100044Z-page.server__GoFrame_HTTP_Server__AND_page.asn__AS132203__AND_page.domain__park_.json, target; the envelopes record the query string, not who issued it)

8.2 The 62-domain result and its hosting

On 2026-09-19T10:00:41Z a query for page.server:"GoFrame HTTP Server" AND page.domain:*easypark* returned 65 results. Counted directly from the envelope, those 65 results name 62 distinct domains, scanned between 2026-07-06T09:34:14Z and 2026-09-18T14:43:21Z. [OBSERVED] (evidence/raw/urlscan/20260919T100041Z-page.server__GoFrame_HTTP_Server__AND_page.domain__easypark_.json, payload.total, payload.results) The commit that captured this envelope describes “63 distinct EasyPark-impersonation domains”; the envelope itself has 62, and this report uses the verified figure. [SOURCE] (commit 1019840)

The scan-time ASN field on each result gives the hosting spread: AS132203 for 60 of the 65 results, AS38623 for 4, and AS45102 for 1. [OBSERVED] (same envelope, payload.results[*].asn) The four AS38623 results are the campaign’s own se- names: easypark.se-36586.online twice, both on the campaign’s origin address (9.3), and easypark.se-toyota.homes and easypark.se-toyota.lol once each, on the adjacent address (9.4). [OBSERVED] (same envelope, payload.results[*].domain, payload.results[*].ip) As with the origin address in section 4, this report states the AS number as recorded by urlscan at scan time and does not assert an AS owner name, since no RDAP record for any of these addresses was collected. [INFERRED]

8.3 Verifying each name

Each of the 62 domains was checked over Tor on 2026-09-19: resolved over DNS over HTTPS, then its root fetched with a mobile User-Agent, exit 192.42.116.60, collected between 2026-09-19T10:03:05Z and 10:06:14Z. [OBSERVED] (62 envelopes in evidence/raw/tier3-verify/; docs/tier3-verification.md) Three verdicts were possible: dead (no DNS answer, or no reachable server), platform (live, the GoFrame header present, no kit markers at the root), and kit (the phishing template itself served at the root). Counted directly from the 62 envelopes: [OBSERVED]

Verdict Count
dead 56
platform 6
kit 0

The six live names, with the address and root response each returned: [OBSERVED] (evidence/raw/tier3-verify/, one envelope per domain, payload.resolves_to, payload.status_code, payload.body_length)

Domain Address Root response
aseeasypark.cfd 43.162.111.113 404, 9 bytes
easypark.work 43.165.1.140 404, 9 bytes
easypark88.com 43.129.85.86 200, 8988 bytes
easypark9.com 43.129.85.86 200, 6650 bytes
easyparkss.cfd 43.157.24.72 404, 9 bytes
easyparkss.sbs 43.157.24.72 404, 9 bytes

No kit verdict occurred anywhere in the set. [OBSERVED]

8.4 Reading the result

None of the 62 could be positively confirmed as serving the EasyPark kit from a Tor vantage, for the same two structural reasons documented for the primary campaign in section 5: the kit is served only at a tokened path, never at the root, and the source-network gate that refuses Tor for the confirmed campaign hosts applies here as well, so a Tor request cannot see the kit even on a live cluster domain. [SOURCE] (docs/tier3-verification.md:17-21) The verdict counts read as the same phishing platform impersonating the same brand, with most of that platform already rotated out of use, consistent with the confirmed campaign’s own pattern of short-lived domains (section 4). [INFERRED] The finding stays classified as context: the commit that captured it states “These are the same platform impersonating the same brand as the Swedish campaign; the link to this specific campaign is weaker than the AS38623 origin-IP hosts, so they normalise to unconfirmed leads, not confirmed infrastructure.” [SOURCE] (commit 1019840)

8.5 A broader, unverified parking-brand set

A second query, page.server:"GoFrame HTTP Server" AND page.asn:"AS132203" AND page.domain:*park*, reports a total of 1312 matches but returns only the first 100 (the search API’s page size), spanning 93 distinct domains, all on AS132203, scanned between 2026-08-08 and 2026-09-18. [OBSERVED] (evidence/raw/urlscan/20260919T100044Z-page.server__GoFrame_HTTP_Server__AND_page.asn__AS132203__AND_page.domain__park_.json, payload.total, payload.results) It surfaces the platform’s use against other parking-brand names on the same infrastructure. None of these 93 has a tier3 envelope: they exist in the evidence store only as urlscan search results and the facts derived from them, not as anything independently verified, and this report does not list them individually or treat any one of them as a lead. [INFERRED]

8.6 Naming-scheme generations

The naming pattern behind the confirmed hosts is a brand misspelling followed by a se- prefix and a digit or word segment (section 4). The wider cluster also shows other naming generations built on the same brand: single-letter host prefixes, a run of suffix letters appended directly to the brand string, and two-letter country tags. [OBSERVED] (the 62-name list in evidence/raw/urlscan/20260919T100041Z-page.server__GoFrame_HTTP_Server__AND_page.domain__easypark_.json, payload.related_domains) Three of the 62, not the rest, carry the campaign’s se- marker: easypark.se-36586.online, easypark.se-toyota.homes and easypark.se-toyota.lol (9.3, 9.4). [OBSERVED] (same envelope) None of the generations was checked against a Swedish source network, and nothing in the evidence dates one generation relative to another, so this report treats the remaining naming similarity as platform-level context, not as a link to the confirmed campaign beyond the three names already addressed in 9.3 and 9.4. [INFERRED]

8.7 What confirming a cluster domain would require

The Tor vantage used for this section cannot distinguish a live cluster domain that would serve the kit from one that would not, because both present the same nine-byte refusal to a source network the gate does not accept. Confirming any individual domain in this cluster needs the same method used for the confirmed campaign: a capture from a Swedish mobile network, with a mobile User-Agent, against a freshly minted token. [SOURCE] (docs/tier3-verification.md:26-28: “Confirming any individual domain would need a capture from a Swedish mobile network with a fresh token, the same method used for the primary campaign.”) No such capture exists for any cluster member, and this report makes no claim beyond what is written here. [INFERRED]

9. Unconfirmed leads and claims not made

Section 4 lists the four hostnames and the origin address confirmed as this campaign’s infrastructure. Everything below shares some attribute with that set (a brand misspelling, the origin address, the phishing platform) but falls short of confirmation, for a reason stated in each subsection. None of it is repeated as fact elsewhere in this report. [INFERRED]

9.1 Two certificate-transparency hostnames

A crt.sh query for the pattern easypank% returned exactly two hostnames, one beginning with the label easypank. and the other with the label easypanknofakturen., each under a different long-established corporate parent domain that this report does not name; the full hostnames are recorded in the cited certificate-transparency envelope, not withheld from the evidence store. [OBSERVED] (evidence/raw/ct/20260918T164240Z-easypank_.json, payload.names, row_count 6) Neither resolves: every DNS record type queried for either hostname, on both 2026-09-18 and again on 2026-09-19, returns an empty value. [OBSERVED] (DNS envelopes for both hostnames, timestamped 20260918T160851Z-53Z and 20260918T160853Z-55Z and, for the full seven-record-type re-run, 20260919T105557Z-08Z and 20260919T105616Z-30Z, all in evidence/raw/dns/, payload.values []) RDAP for both resolves to the same kind of corporate registrant, with registration events dated 2007-01-03T17:23:31Z and 2007-01-03T17:20:11Z respectively, on nameservers belonging to a major cloud platform, provisioned two decades before this campaign existed. [OBSERVED] (RDAP envelopes for both hostnames, timestamped 20260918T162831Z and 20260918T162834Z, in evidence/raw/rdap/, payload.raw.events, payload.facts.nameservers)

A brand-typo match in certificate transparency, on names that do not resolve, under a registration unconnected to anything else here, is not evidence of a shared operator. An earlier draft treated these hostnames as a second infrastructure track before withdrawing that claim once RDAP returned this registration data. [SOURCE] (commit 32a8cbf) CLAUDE.md states the resulting rule: “Never describe them as campaign infrastructure, and never name the parent domains in a report.” [SOURCE] (CLAUDE.md, “Domain context”) This report follows that rule: the parent domains are not named here, and the full hostnames are not spelled out either, since that would reveal the parent domain too.

9.2 liuguan168.lol, a suspected co-tenant

liuguan168.lol resolves to the confirmed campaign’s own origin address, 220.158.232.231, and was seen on that address by urlscan on 2026-09-07T06:22:10Z. [OBSERVED] (evidence/raw/dns/20260918T181422Z-liuguan168.lol.json, payload.values; evidence/raw/urlscan/20260918T175939Z-page.ip__220.158.232.231_.json, results[0].scanned_at) It was auto-promoted to the confirmed set purely on that shared address, then reclassified once reviewed. The reclassifying commit states the reasoning: “It was auto-promoted purely by resolving to the shared origin 220.158.232.231, a multi-tenant malicious host. It has no brand typosquat, no current kit (the origin serves it no valid certificate), and a name unlike the Swedish campaign, so it is a suspected co-tenant, not confirmed campaign infrastructure.” [SOURCE] (commit 62199d7) The same commit adds that naming it to police would risk the same kind of false accusation that 9.1 already guards against. [SOURCE] (commit 62199d7) This report treats liuguan168.lol as a suspected co-tenant only, not confirmed campaign infrastructure.

9.3 easypark.se-36586.online

urlscan recorded this hostname on the campaign’s origin address on 2026-09-02T08:18:38Z and 2026-09-03T11:54:20Z. [OBSERVED] (evidence/raw/urlscan/20260919T100041Z-page.server__GoFrame_HTTP_Server__AND_page.domain__easypark_.json) A discovery run attempted to confirm it and could not: “easypark.se-36586.online was a candidate but did not confirm: it no longer resolves (empty A/AAAA/CNAME), consistent with the campaign abandoning domains within days.” [SOURCE] (commit 20ffaf6) Re-checked on 2026-09-19, it still returns no address and no reachable server. [OBSERVED] (evidence/raw/tier3-verify/20260919T100351Z-easypark.se-36586.online.json, payload.resolves_to [], payload.verdict “dead”) A name that matches the naming scheme but cannot be reached by any means available to this investigation is recorded as a lead, not a finding.

9.4 easypark.se-toyota.homes and easypark.se-toyota.lol

These two are recorded in sections 4.4 and 4.7 as scanned at 220.158.233.4 on 2026-08-24, adjacent to the campaign’s origin. [OBSERVED] (evidence/raw/urlscan/20260919T100041Z-page.server__GoFrame_HTTP_Server__AND_page.domain__easypark_.json) CLAUDE.md’s “Domain context” section describes them, with se-36586.online, as “Confirmed variants include se-36586.online, se-toyota.homes and se-toyota.lol.” [SOURCE] (CLAUDE.md, “Domain context”) That sentence confirms only that the names fit the naming scheme; both verified dead on 2026-09-19, with no address and no reachable server. [OBSERVED] (evidence/raw/tier3-verify/20260919T100351Z-easypark.se-toyota.homes.json and evidence/raw/tier3-verify/20260919T100351Z-easypark.se-toyota.lol.json, payload.resolves_to [], payload.verdict “dead”) This report treats the naming-scheme match as a lead only: neither name is stated as confirmed campaign infrastructure.

9.5 Two four-year-old tenants of the origin address

matrix-client.dev-ctalk.us and packages.glivedev.xyz also appear in the urlscan history of the origin address, scanned on 2022-12-19T02:59:37Z and 2022-12-14T14:01:01Z. [OBSERVED] (evidence/raw/urlscan/20260918T175939Z-page.ip__220.158.232.231_.json) Both sightings predate the kit build recorded in this evidence, 2026-08-26 (4.7), by roughly four years, and neither name carries any brand relation to EasyPark or to parking. [INFERRED] A shared address four years apart, with no other shared attribute, does not connect these names to the campaign; this report treats them only as other tenants of the origin address.

9.6 A claim with no evidence behind it at all

The design document that preceded this evidence store names two further hostnames on a netblock adjacent to the origin address, said to have impersonated government sites in two other countries since 2025. [SOURCE] (design spec lines 170-171, 177) No envelope in this evidence store records either name or that address: a search of evidence/ for both returns no match. [OBSERVED] This report does not name them or restate the claim as a finding, and records only that it appears in an earlier planning document and could not be verified.

9.7 Claims this report deliberately does not make

10. Methodology, chain of custody, and deviations

10.1 Transport: one path for every request

osint/transport.py is the only module in this codebase that opens a network connection (module docstring, transport.py:1-9). [SOURCE] session() refuses to build a requests.Session unless a SOCKS proxy is reachable at an explicit host and port: check_proxy_reachable() parses OSINT_SOCKS (default socks5h://127.0.0.1:9050), rejects a value with no explicit host or port, and attempts a raw TCP connect first (transport.py:39-56); session() then sets proxies and trust_env = False so an ambient HTTP_PROXY cannot bypass Tor (transport.py:59-65). [SOURCE] grep -rn "import requests" osint/ returns exactly one line, osint/transport.py:17: no collector opens its own connection. [SOURCE]

A narrower check exists only for the cloaking probe: exit_identity() GETs https://check.torproject.org/api/ip over the session and raises TorUnavailable unless the response’s IsTor field is true (transport.py:68-79). [SOURCE] grep -rn "exit_identity" osint/ returns three lines: the definition (transport.py:68), the call gating probe_url() before the control request and any grid cell (cloak.py:132), and a string literal, "exit_identity(sess)", used as the error envelope’s command value when that call fails (cloak.py:138) - only the second line is a real call site. [SOURCE] DNS, RDAP, certificate and urlscan never call it: they don’t touch an operator host and rely on the proxy-reachability check above. [SOURCE]

DNS is resolved over HTTPS through the same session: resolve() calls https://cloudflare-dns.com/dns-query with accept: application/dns-json (transport.py:23, 91-98), and osint/collect/dns.py calls only transport.resolve. [SOURCE] grep -rn "getaddrinfo(\|subprocess\." osint/ returns no hits, so no collector can fall back to the system resolver (a looser pattern without the parenthesis matches only that same docstring line, osint/collect/dns.py:3). [SOURCE]

Registration data comes from RDAP, not whois: the module docstring states whois is TCP/43 and cannot traverse the SOCKS proxy (rdap.py:4-6), and _fetch(), built on transport.session().get(), is the only path to a registry (rdap.py:61-66), with no subprocess call or whois parser anywhere in osint/. [SOURCE] This was not always true: commit 76de89d (“fix: remove the whois Tor-bypass from rdap.py”, 2026-09-18T20:48:07+02:00) deleted an OSINT_ALLOW_WHOIS-gated subprocess.run(["whois", target]) path that had opened TCP/43 directly, outside Tor, whenever set. [SOURCE] An RDAP envelope from before that commit still carries the old wording: evidence/raw/rdap/20260918T162138Z-easypank.se-9626654.pics.json records "command": "GET https://rdap.org/domain/easypank.se-9626654.pics (Tor); whois fallback enabled=False", and a whois_skipped field repeating the same TCP/43 reasoning. [OBSERVED] That lookup failed with a 404, superseded by a later run against the registrable parent the same evening (evidence/raw/rdap/20260918T162807Z-se-9626654.pics.json, status ok); the wording is a fossil of a removed code path, not evidence that whois ran. [OBSERVED]

10.2 Request discipline: GET only, budgeted where it touches the operators

grep -rn "\.post(" osint/ returns no matches; every collector calls sess.get or transport.session().get(). [SOURCE] The per-domain request budget (CLAUDE.md rule 3) is config.REQUEST_BUDGET = 40 (config.py:15), and only the cloaking probe enforces it: probe_url() raises BudgetExceeded before sending anything if the grid (7 user agents by 2 languages by 2 referers, 28 cells) plus one control request, 29 of 40, exceeds it (cloak.py:29-78, 99-128, 119-128). [SOURCE] grep -rln "REQUEST_BUDGET" osint/ returns only config.py and cloak.py: the DNS, RDAP, certificate and urlscan collectors issue a handful of requests per domain and never check the budget, never expected to approach it. [SOURCE]

10.3 The envelope, quoted from the store

Every collector call produces one envelope through evidence.envelope(): collected_at (UTC, %Y-%m-%dT%H:%M:%SZ), source, target, command, status, payload_sha256 (the sha256 of the payload’s canonical JSON, sorted keys, compact separators, ensure_ascii=False), and payload (evidence.py:42-51). [SOURCE] The stored file is compact JSON with sorted keys and no line breaks, not the pretty-printed form below (evidence.py:76). [SOURCE] One, reformatted for readability:

{
  "collected_at": "2026-09-18T16:08:45Z",
  "source": "dns",
  "target": "easypank.se-45564.xyz",
  "command": "DoH A easypank.se-45564.xyz via https://cloudflare-dns.com/dns-query?name={name}&type={rtype}",
  "status": "ok",
  "payload_sha256": "a6f0ec975caa...",
  "payload": {"record": "A", "values": ["220.158.232.231"]}
}

(evidence/raw/dns/20260918T160845Z-easypank.se-45564.xyz.json) [OBSERVED]

payload_sha256 is what facts.jsonl cites as evidence (facts.py:34, 43), but it hashes only the payload, so identical payloads collide. [SOURCE] This hash is shared by 8 envelopes under evidence/raw/dns/, five hostnames with the same A answer across two collection runs, so the hash alone does not identify an envelope - the file path does (grep -rl a6f0ec975caa evidence/raw/ | wc -l -> 8). [OBSERVED] The manifest instead records the hash of the whole envelope blob, 0bb5626b9333291ecca90138de7ef5ba8b8a4e369c41d4b819f47e04b46b9665, so a tampered file or forged payload hash is caught by two independent checks. [OBSERVED] (evidence/MANIFEST.sha256)

10.4 Artifacts, the manifest, and append-only

Page bodies and other blobs are stored once, by content: store_artifact() writes to evidence/artifacts/<sha256>.<ext> only if that path does not already exist (evidence.py:82-91). [SOURCE] write_envelope() never overwrites either: it appends a .1, .2 collision suffix rather than replace a file at the same timestamp and slug (evidence.py:63-79). [SOURCE] Both call append_manifest(), which appends a <sha256> <relpath> line and skips it if already present (evidence.py:54-60) - a mechanism, not an enforced lock: nothing stops a later manual edit, so the manifest is an independent check. [SOURCE]

Verified now:

$ (cd evidence && sha256sum -c MANIFEST.sha256 | grep -vc OK)
0
$ wc -l evidence/MANIFEST.sha256
433 evidence/MANIFEST.sha256

433 files, all checksums current, zero mismatches. [OBSERVED]

10.5 Failures are recorded, never dropped

Collectors do not raise into the pipeline: probe_url() catches a failed exit_identity() before any campaign request and writes a cloak-precondition error envelope instead of sending anything (cloak.py:130-141); a failed grid cell is caught individually and written with status: "error" and no body_artifact (cloak.py:163-171). [SOURCE] The same pattern - status: "error" on the exception branch, envelope written regardless - is standard across the other collectors, e.g. rdap.py:94-104. [SOURCE] facts.rebuild() applies the same discipline to the read side: a raw file that fails to parse is recorded in evidence/facts-skipped.jsonl rather than silently dropped (facts.py:159-191). [SOURCE] That file is currently 0 lines, so no envelope has failed to parse (wc -l evidence/facts-skipped.jsonl -> 0). [OBSERVED]

10.6 Facts and the promotion gate

osint/facts.py normalizes only status: "ok" envelopes into {subject, predicate, object, observed_at, evidence} facts (facts.py:39-40); every fact carries a payload_sha256 from its envelope. [SOURCE] evidence/facts.jsonl holds 1563 lines, each with a non-empty evidence field (verified by loading every record; wc -l evidence/facts.jsonl -> 1563). [OBSERVED] Analysis and reports read only this file (osint/analyze/pivot.py, osint/report/render.py), never the network. [SOURCE]

A candidate domain is promoted from pivot.score_candidates() only if its score against confirmed infrastructure is at least CONFIDENCE_THRESHOLD = 2 (pivot.py:42) and one shared relationship is in INFRASTRUCTURE_FAMILIES = {"resolves_to", "hosting"} (pivot.py:45, 129, 135). [SOURCE] A shared kit body (served_body) or registrar/DNS zone (registrar, nameserver_zone) never promotes alone, since those families are excluded from INFRASTRUCTURE_FAMILIES (pivot.py:46-51). [SOURCE] osint/discover.py’s confirm() adds a second gate: a candidate must resolve onto a known IP before being confirmed (discover.py:61-72). [SOURCE] osint/seeds.py keeps the two parent domains behind section 9’s unconfirmed certificate-transparency hostnames out of known, the set anchoring the pivot: discover.run() builds it by filtering the seed list through is_excluded() (EXCLUDED_PARENT_DOMAINS, seeds.py:13-30; discover.py:94). [SOURCE] seen, used only to suppress already-known candidates, deliberately re-includes both parent domains (discover.py:100), so a match against either is never returned as a new candidate. [SOURCE]

10.7 Deviations from the rules

Not every request behind this report followed the rules above, listed in full, in the order they happened:

Pre-pipeline lookups, outside Tor. The “Confirmed facts as of 2026-09-18T15:35Z” table in the design document was “collected with dig, whois and crt.sh before this design was written” (design spec, line 34). dig and whois go directly over UDP/53 and TCP/43, not through Tor, disclosing the reporter’s real address to the campaign’s nameservers and the queried registries - exactly what CLAUDE.md rules 4 and 5 forbid. git log --diff-filter=A -- CLAUDE.md shows those rules were added in commit f3688ef at 2026-09-18T17:36:30+02:00, one minute after that collection (17:35 CEST for the 15:35Z table). The lookups predate the rules, were never repeated, and every value was independently re-collected over Tor afterward (section 4).

Four handset requests, outside Tor, with the reporter’s authorisation. The cloak-phone source holds exactly four envelopes. [OBSERVED] (ls evidence/raw/cloak-phone/ | wc -l -> 4) Each carries a payload.provenance block: device “a Swedish mobile handset”, method “adb shell curl on a connected Android device”, network “a Swedish mobile carrier, on cellular data with wifi disabled”, via_tor: false, and the note: “These four requests did not go through Tor. They were made with the reporter’s explicit authorisation from the handset that received the SMS. The operators’ logs already held this address from the reporter’s own click. The Tor path could not distinguish a spent token from source-network filtering, and this comparison does.” (evidence/raw/cloak-phone/20260918T161229Z-http___easypank.se-45564.xyz_se.json, payload.provenance) [OBSERVED] These isolate the client-type gate from the source-network gate in section 5, a comparison Tor exits cannot make: they fail the source-network check regardless of User-Agent.

Kit assets and cluster verification, outside the CLI. grep -rln "kit-asset\|tier3-verify" osint/ finds no matching source file: neither collector exists here. The static-asset fetch holds 2 envelopes, both via_tor: true, exit 171.25.193.131 (evidence/raw/kit-asset/); the wider-cluster root checks are a separate source of 62 envelopes (ls evidence/raw/tier3-verify/ | wc -l -> 62). [OBSERVED] Neither was populated by python -m osint probe, the only command CLAUDE.md names as touching operator hosts: both used ad hoc scripts, through Tor and GET only, but outside the CLI path enforcing REQUEST_BUDGET and cloak.py’s envelope format.

Page-initiated POSTs during the Waydroid session. The har source holds 40 envelopes from the captured browser session, ingested with osint ingest-har, a legitimate CLI command (cli.py:67-72) (ls evidence/raw/har/*.json | wc -l -> 40); 18 of them are POST requests - 17 to /JisiRmktje/api/input?token=... and 1 to /JisiRmktje/api?token=..., all status: 200, issued automatically by the kit’s own JavaScript as the session progressed (evidence/raw/har/20260919T105202Z-https___easypank.se-9626654.pics_JisiRmktje_api_input_token_755a9f6f-b4bc-4ef8-9.json and 17 siblings, payload.summary.method: "POST"). [OBSERVED] Not issued by any collector here; the ingest step only imported an existing mitmproxy capture, filtered to the campaign host (har.py:61-75).

Junk form data, against rule 1, entered anyway. CLAUDE.md rule 1 is explicit: “never enter credentials or card data, not even fabricated data.” The captured session did exactly that: a fabricated plate, two fabricated card numbers (one deliberately Luhn-invalid), an expiry, CVV, name and phone number - why the POSTs above and the session’s WebSocket frames exist (section 7 has the full record). Done in the kit repository, not through any collector here, and its own account states why: “This is a controlled test session using junk data, but it exercises the real C2 end to end.” [REPORTED] (kit repository TAKEDOWN_REPORT.md:189-190) That let the operators’ live relay - server-side BIN check and card verdict - be documented from a genuine round trip, not asserted from static analysis alone. No real payment or identity data was entered at any point.

A stale method statement. All four reports carry the same METHOD_STATEMENT (render.py:17-24), stating observations used “HTTP GET requests, DNS lookups, WHOIS/RDAP queries, and queries to public certificate transparency and URL scanning services.” grep -l "WHOIS/RDAP" reports/{police-dossier,abuse-reports,brand-brief,press-narrative}.md matches all four. [OBSERVED] Per section 10.1, the code has had no whois path since commit 76de89d; the “WHOIS/RDAP” wording predates that removal and was never updated.

11. Evidence gaps and inconsistencies

What an investigation declines to claim matters as much as what it claims. This section lists what the evidence store does not contain, and every place where a document of this investigation, in either repository, says something the evidence does not bear out. Every row was re-verified against its anchor. Gaps the 2026-09-19 collection run or the browser-session ingest have closed are not listed as open.

11.1 Gaps

Gap Why it is open What would close it
No artifact of the SMS. Delivery time 2026-09-18 16:46:15 CEST and sender ID InfoSMS are [REPORTED] only (kit repo TAKEDOWN_REPORT.md:107-116) No screenshot or export was captured; evidence/ has no match for InfoSMS [OBSERVED] A handset export, or the carrier’s delivery record
The route the SMS took The ROM does not retain the SMSC address (kit repo TAKEDOWN_REPORT.md:238-239); the grey-route account at :246-259 is analysis, not observation [SOURCE] A carrier or PTS ingress trace
Whether Swedish fixed broadband passes the source-network gate The clean test was never run; docs/site-access.md:54-59 calls the allowlist hypothesis unverified [SOURCE] One GET from such an address, mobile User-Agent, fresh token
The reporter’s desktop-on-wifi refusal that started the investigation [REPORTED], never reproduced: the four non-Tor handset envelopes are the only ones from the reporter’s own connections [OBSERVED] (evidence/raw/cloak-phone/) One authorised captured request from that address, fresh token
Certificate transparency is only partly covered 14 of 51 crt.sh envelopes are status: error (timeouts, 502, 404), and eight Cert Spotter envelopes, four each for the two parents of 9.1, are 403 [OBSERVED] (evidence/raw/ct/, evidence/raw/certspotter/) A retry from another vantage, or an API key
Reverse DNS and routing origin for 220.158.232.231 PTR is empty in both runs; the IP’s RDAP object carries no AS number [OBSERVED] (evidence/raw/dns/20260918T160855Z-220.158.232.231.json; evidence/raw/rdap/20260918T162147Z-220.158.232.231.json, zero matches for 38623) A routing-registry or BGP lookup, stored as an envelope
Embedded signed certificate timestamps Cert Spotter records issuer, dates, dns_names and id only; no SCT field exists [OBSERVED] (evidence/raw/certspotter/20260918T164231Z-se-45564.xyz.json) Fetching and parsing the certificates
The bodies of the two substantive live platform hosts Their envelopes record 200 at 8988 and 6650 bytes, but carry no body_sha256 field and no artifact was stored [OBSERVED] (evidence/raw/tier3-verify/) Re-fetching both roots over Tor, storing the bodies
The parking-brand platform set is truncated The broader urlscan query reports total 1312 and returned 100 rows [OBSERVED] (evidence/raw/urlscan/20260919T100044Z-page.server__GoFrame_HTTP_Server__AND_page.asn__AS132203__AND_page.domain__park_.json) Paginating it, which needs a higher urlscan quota
Second-factor relay in practice No verification screen was reached: the 930 frames hold zero OTP, app-approval or custom-OTP submissions [OBSERVED] (kit repo tools/ws_evidence.jsonl) Nothing this investigation may safely do; 6.4 rests on the bundle alone
Whether the origin serves directly or sits behind a proxy Responses carry Via: 1.1 Caddy ahead of Server: GoFrame HTTP Server; no envelope separates proxy from origin [OBSERVED] (evidence/raw/cloak/) Host records, held only by the abuse desks
The certificate state of liuguan168.lol seeds.yaml:23 calls it uncertificated; no TLS or Cert Spotter envelope exists [OBSERVED] (evidence/raw/certspotter/) A Cert Spotter query for it. See 9.2
The host count behind the GoFrame platform header The design document’s “more than 10000” figure has no envelope: the store holds no bare page.server query, only two that AND it with a brand term [OBSERVED] (evidence/raw/urlscan/) A bare page.server query, which 8.1 declines to run
No independent replay of the kit The kit repo’s mock harness was never exercised: its output tools/evidence.jsonl is 0 bytes in that repository’s working tree. Unlike every other kit-repository citation here it is untracked, so it cannot be read back with git show phishing-investigation:<path> [SOURCE] (git -C <kit repo> status --short tools/evidence.jsonl returns ?? tools/evidence.jsonl) Running it offline against the preserved bundle, and committing the output

Five gaps the source material lists are closed, and so are absent above. avcoa.click and btalning.click lacked RDAP, Cert Spotter and per-domain urlscan collection and now have all three [OBSERVED] (evidence/raw/rdap/20260919T105655Z-avcoa.click.json and siblings, 2026-09-19T10:56Z). The kit’s bootstrap response, never observed before, is preserved whole and carries "mode":1, "country":"SE" and the operator text block [OBSERVED] (evidence/artifacts/e3eaf9aa94f833e92c3e09df408c03dd98ba0675f7f6a878bbe1692b566d1e66.bin). No HAR had been ingested; 40 now exist [OBSERVED] (evidence/raw/har/). The dossier’s manifest count was stale; all four generated reports were regenerated 2026-09-19T11:18:04Z against 433 verifying manifest lines [OBSERVED] (reports/police-dossier.md:3-4). And no abuse report covered the two .click domains, which now have their own registrar section [OBSERVED] (reports/abuse-reports.md:39-47).

11.2 Inconsistencies

Where a document and the evidence disagree, this report follows the evidence. Where two documents disagree, it follows the capture file and the preserved bundle.

Document statement What the evidence shows This report
Certificates were “issued minutes after each domain was registered” (design spec, line 183) Both precede registration: not_before 07:27:20Z against 07:50:58.0Z, and 05:55:00Z against 06:43:13.0Z [OBSERVED] (evidence/raw/certspotter/20260918T164231Z-se-45564.xyz.json; evidence/raw/rdap/20260918T162140Z-se-45564.xyz.json) The envelopes; the ordering is left unexplained (4.3)
se-45564.xyz was registered “~9 hours before the lure” (kit repo SCAMMER_WORKFLOW.md:47-48, TAKEDOWN_REPORT.md:137) 07:50:58Z to the reported delivery at 14:46:15Z is 6 h 55 min 17 s; the nine-hour figure reads 16:46 CEST as if it were UTC [OBSERVED] (evidence/raw/rdap/20260918T162140Z-se-45564.xyz.json) 6 h 55 min 17 s
The grid’s uniform “Not found” follows from the SMS token “having already been used” (reports/police-dossier.md:29) 28 of the 56 cells requested the lure URL, and the redirector minted each a fresh token; all still returned the same nine bytes [OBSERVED] (evidence/raw/cloak/, final_url carrying _v=valid_20260919000752_...) A spent token explains the landing-URL cells only; the source-network gate the rest (5.2, 5.3)
The operators serve the page “only to mobile User-Agent strings” (reports/abuse-reports.md:17-18; reports/police-dossier.md:13 makes the same claim in different words, “only to mobile browsers”) Two gates must both pass; no generated report mentions the source-network one [OBSERVED] (evidence/raw/cloak-phone/20260918T161229Z-http___easypank.se-45564.xyz_se.json and .1.json, and the 56 envelopes under evidence/raw/cloak/; see 5.3. No generated report names the source-network gate: grep -il "source network" reports/{police-dossier,abuse-reports,brand-brief,press-narrative}.md returns nothing) Both gates (5.3)
Observations used “WHOIS/RDAP queries” (all four generated reports) No whois path exists in the codebase after commit 76de89d [SOURCE] (osint/collect/rdap.py:4-5, “There is no whois fallback: whois is TCP/43 and cannot traverse the SOCKS proxy”) RDAP only
The origin belongs to a named Cambodian operator (design spec, line 41), against “BUCT-BD, Bangladesh, via Viettel” (kit repo README.md:41) RDAP gives netname BUCT-BD, country BD, abuse yennp@viettel.com.vn, no AS number; AS38623 appears only as urlscan scan-time data [OBSERVED] (evidence/raw/rdap/20260918T162147Z-220.158.232.231.json) The RDAP wording plus “AS38623 per urlscan scan-time data”; no owner asserted (4.4)
The origin address “came back 404 from the relevant RDAP registries” (commit 50a87b7) The RDAP envelope for 220.158.232.231 is a successful lookup carrying netname BUCT-BD, country BD and abuse contact yennp@viettel.com.vn [OBSERVED] (evidence/raw/rdap/20260918T162147Z-220.158.232.231.json) The commit message was wrong when written: the successful lookup it calls a 404 was collected at 16:21:47Z, 91 seconds before the commit at 16:23:18Z, by the same run. Section 4.4 cites the later 2026-09-19 envelope
A Tor exit was in a named country (docs/site-access.md:32-33) No envelope carries a country or geolocation field for any exit address [OBSERVED] (evidence/raw/cloak/, evidence/raw/cloak-control/) The country is omitted; closing this needs each recorded exit resolved against a consensus source
The AS-constrained urlscan search “returned 11 hosts” (design spec, line 160), above a table of 8 rows That envelope has 8 results over 6 domains, and no page.asn:"AS38623" envelope exists [OBSERVED] (evidence/raw/urlscan/20260918T175939Z-page.ip__220.158.232.231_.json) The 6 domains it names (4.1, 9.2, 9.5)
“63 distinct EasyPark-impersonation domains” (commit 1019840), the 62 checked “excluding” one name belonging to the corporate registrar behind the 9.1 parents (docs/tier3-verification.md:3-4) The envelope holds 62 related domains, none of them such a name [OBSERVED] (evidence/raw/urlscan/20260919T100041Z-page.server__GoFrame_HTTP_Server__AND_page.domain__easypark_.json) 62, no exclusion (8.2)
easypark.se-36586.online first seen 2026-09-03 (design spec, line 164) Scans at 2026-09-02T08:18:38.730Z and 2026-09-03T11:54:20.273Z [OBSERVED] (evidence/raw/urlscan/20260918T175939Z-page.ip__220.158.232.231_.json) 2026-09-02 (9.3)
The scheme is se-<6-8 digits> (design spec, line 52) Observed: 45564, 36586, 9626654, that is five, five and seven digits [OBSERVED] (evidence/raw/rdap/20260919T105537Z-se-45564.xyz.json, evidence/raw/rdap/20260919T105554Z-se-9626654.pics.json, evidence/raw/urlscan/20260918T175939Z-page.ip__220.158.232.231_.json for easypark.se-36586.online) se-<digits or word>, lengths given
The capture used “wss:///engine.io” (kit repo TAKEDOWN_REPORT.md:98, 228, SCAMMER_WORKFLOW.md:69), the flag “_m defaults to 1 => wss:///engine.io” (KIT_ANALYSIS.md:33) All 930 frames carry path: /ws?token=755a9f6f-..., none /engine.io; the bootstrap returned "mode":1, and the bundle routes both modes to that same /ws URL [OBSERVED] (kit repo tools/ws_evidence.jsonl; evidence/artifacts/e3eaf9aa94f833e92c3e09df408c03dd98ba0675f7f6a878bbe1692b566d1e66.bin; docs/kit-analysis.md section 2) /ws?token=, both modes (6.5)
“HTTP POSTs in the bundle are only the engine.io polling fallback” (kit repo TAKEDOWN_REPORT.md:230) The session made 17 POSTs to /JisiRmktje/api/input, each answered 200 with 33 bytes, plus the bootstrap POST [OBSERVED] (18 POST envelopes, evidence/raw/har/) A second, parallel exfiltration channel (6.6, 7.7)
index.html hashes to c8ccfd83... and its title is Danish (kit repo SCAMMER_WORKFLOW.md:211, TAKEDOWN_REPORT.md:10) c8ccfd832d7f... is the JS bundle; index.html is a98ddbfa1083.... Only lang="da" at line 2 is Danish; the title at line 9 is Swedish [SOURCE] (sha256sum, sed, against kit_original/) The computed hashes, and the attribute-versus-title split as a multi-tenant tell (6.1, 6.3)
The plate streams as input_text { type:"input_card", key:"plate" } (kit repo KIT_ANALYSIS.md:130) Record 42 carries {"type":"Registreringsnummer","key":"plate","text":"boy"} [OBSERVED] (kit repo tools/ws_evidence.jsonl) The captured value (6.6)
The operator table lists my-event, otp-valid, app-valid, custom-otp-valid, success as wire events (kit repo TAKEDOWN_REPORT.md:54-65, SCAMMER_WORKFLOW.md:96-110) That repo’s own correction calls them internal bus signals and names result_type (KIT_ANALYSIS.md:199-204); none of the five appears in the 930 frames [OBSERVED] (kit repo tools/ws_evidence.jsonl) result_type (6.5)
The frame file is “timestamped” (kit repo README.md:28) The time field is 2026-09-18T22:13:19 on all 930 lines: the wall clock of the offline decode run [OBSERVED] (kit repo tools/ws_capture.py:54) Only the frames’ embedded timestamp values (7.3)
The kit writes 13 localStorage keys (kit repo TAKEDOWN_REPORT.md:14-15), against 16 in the same repo’s KIT_ANALYSIS.md:55-58 The lists differ by price, countdownDuration and countdownStartTime [SOURCE] Neither list is cited as complete; 6.7 anchors to the bundle
Phase 0 setup, Phase 1 delivery and the hosting jurisdiction are labelled [OBSERVED] in the kit repo (SCAMMER_WORKFLOW.md:114-119, 178) That repo defines [OBSERVED] as “confirmed from capture” (README.md:17) and holds no RDAP, DNS or registration artifact [SOURCE] Labels registration and hosting [OBSERVED] only because this repository holds the envelopes; delivery stays [REPORTED]
The kit “also ships toll-road and generic bank skins” (kit repo TAKEDOWN_REPORT.md:5), against “also toll” (README.md:38) The bundle carries toll strings; nothing in either repository substantiates a bank skin [SOURCE] (6.3) Toll and multi-language only
Six routes “were seen live in the collector’s crawl” (docs/kit-analysis.md:32) No crawl exists, and rule 2 forbids path enumeration: none of the 412 envelope targets ends in /home, /card, /address, /pay, /success or /temp [OBSERVED] (evidence/raw/) The route table as [SOURCE], read from the router (6.4)
The page is “a copy of EasyPark’s Next.js site with the framework’s attributes intact” (design spec, lines 146-149), against a Vite-built Vue 3 app (docs/kit-analysis.md:10) Both hold in part: index.html carries data-next-head twice and __next once; the application is Vue [SOURCE] (grep -o -F, kit_original/) Copied markup inside a Vue kit (6.2, 6.3)
“56 grid cells plus 2 control requests” (design spec, lines 72-73) against “29 envelopes, being 28 grid cells plus one control request” (docs/vps-runbook.md:139) Both are right at different scopes: 56 cloak envelopes, 28 per URL over two URLs, and 2 cloak-control envelopes [OBSERVED] (evidence/raw/cloak/, evidence/raw/cloak-control/) Totals, with the per-URL split stated (5.1)
The submitted phone number passes without comment (kit repo TAKEDOWN_REPORT.md:213-220) 07129284829 is eleven digits, one more than a Swedish mobile number, in both submissions [OBSERVED] (kit repo tools/ws_evidence.jsonl, records 273 and 463) States plainly that the session used fabricated data throughout (7.1)
facts-scam.md carries file:line anchors into this repository’s code (facts-kit.md carries none) Several are stale: config.py:203-206 is cited for REQUEST_BUDGET in a 54-line file, and evidence.py:118-149 for envelope(), which starts at line 42 [OBSERVED] (grep -n, wc -l) Every anchor was re-opened; the lines cited here are the lines actually read

None of the above changes a finding in sections 2 through 8. Each changes how a finding may be worded, which is why they are listed rather than reconciled in silence.

12. Indicators of compromise

This section is the blocklist and hunting-query extract of the report. Every row was re-read from the envelope or artifact named beside it. The confidence column uses the report’s four labels. Only infrastructure confirmed as this campaign’s appears in 12.1 to 12.9; section 9’s unconfirmed leads appear nowhere here, and 12.10 is a separate table that is not this campaign’s infrastructure. [INFERRED] Status values are those of the 2026-09-19 collection run. [OBSERVED]

12.1 Hostnames

Indicator Role A record 2026-09-18 Status 2026-09-19 Confidence Anchor
easypank.se-45564.xyz lure host named in the SMS; HTTP redirector 220.158.232.231 resolving at 10:54:51Z [OBSERVED] evidence/raw/dns/20260918T160845Z-easypank.se-45564.xyz.json, evidence/raw/dns/20260919T105451Z-easypank.se-45564.xyz.json
easypank.se-9626654.pics landing host; served the kit and the live relay 220.158.232.231 no A record at 10:55:12Z [OBSERVED] evidence/raw/dns/20260918T160846Z-easypank.se-9626654.pics.json, evidence/raw/dns/20260919T105512Z-easypank.se-9626654.pics.json
avcoa.click sibling name on the origin address; APCOA typosquat 220.158.232.231 resolving at 10:56:36Z [OBSERVED] evidence/raw/dns/20260918T181409Z-avcoa.click.json, evidence/raw/dns/20260919T105636Z-avcoa.click.json
btalning.click sibling name on the origin address; betalning typosquat, seen serving the campaign’s own path 220.158.232.231 resolving at 10:56:59Z [OBSERVED] evidence/raw/dns/20260918T181415Z-btalning.click.json, evidence/raw/dns/20260919T105659Z-btalning.click.json

12.2 Registrable domains and registration data

All four are NameSilo, LLC registrations, IANA registrar id 1479, all delegated to ns1.dnsowl.com, ns2.dnsowl.com and ns3.dnsowl.com. [OBSERVED] (the four envelopes below, payload.facts.registrar, payload.facts.nameservers and the registrar entity’s publicIds)

Domain Handle Registered (UTC) Last changed RDAP status 2026-09-19 Abuse contact Confidence Anchor
se-45564.xyz D644515746-CNIC 2026-09-18T07:50:58.0Z 2026-09-18T07:51:03.0Z server transfer prohibited, client transfer prohibited, add period abuse@namesilo.com, tel +1.4805240066 [OBSERVED] evidence/raw/rdap/20260919T105537Z-se-45564.xyz.json
se-9626654.pics D639688650-CNIC 2026-09-09T06:43:13.0Z 2026-09-18T23:47:11.0Z server hold, server transfer prohibited, client hold, client transfer prohibited abuse@namesilo.com, tel +1.4805240066 [OBSERVED] evidence/raw/rdap/20260919T105554Z-se-9626654.pics.json
avcoa.click DO_1dcdb4021fe3d6faa62b10e826192166-INAMING 2026-09-05T15:55:26.273Z 2026-09-10T15:55:52.041Z client transfer prohibited support@namesilo.com, tel +1.6024928198 [OBSERVED] evidence/raw/rdap/20260919T105655Z-avcoa.click.json
btalning.click DO_b07f16df9e824d61205c08078811f578-INAMING 2026-09-02T08:23:58.644Z 2026-09-07T08:24:52.299Z client transfer prohibited support@namesilo.com, tel +1.6024928198 [OBSERVED] evidence/raw/rdap/20260919T105717Z-btalning.click.json

se-9626654.pics is the one domain carrying both a registry hold and a registrar hold; the other three carry no hold and remain live registrations. [OBSERVED] (the same four envelopes, payload.raw.status) One registrar publishes two different abuse addresses across these four domains, so a report covering all four has to be sent to both. [INFERRED] (4.2)

12.3 Origin address

Field Value as the registration data has it Confidence
Address 220.158.232.231 [OBSERVED]
Netblock handle 220.158.232.0 - 220.158.232.255 [OBSERVED]
name BUCT-BD [OBSERVED]
type ASSIGNED NON-PORTABLE [OBSERVED]
country BD [OBSERVED]
remarks description BUCT COMMUNICATION [OBSERVED]
Abuse entity IRT-VIETTEL-CAMBODIA-KH, email yennp@viettel.com.vn [OBSERVED]
Technical and administrative entity BCA3-AP, BUCT Communication administrator, tel +880-2-8153246, email admin@buctbd.com [OBSERVED]
PTR empty [OBSERVED]
Autonomous system AS38623, per urlscan scan-time data only [OBSERVED]

[OBSERVED] (evidence/raw/rdap/20260919T105723Z-220.158.232.231.json for every field but the last two; evidence/raw/dns/20260918T160855Z-220.158.232.231.json for the PTR; evidence/raw/urlscan/20260918T175939Z-page.ip__220.158.232.231_.json, the asn field of each result, for AS38623) The RDAP object holds no autonomous system number and no owner name for AS38623 exists in any envelope collected here, so none is asserted. [OBSERVED] (the same RDAP envelope contains no autnum field and no occurrence of 38623)

12.4 Certificates

Covers Issuer not_before not_after Cert Spotter id Confidence Anchor
easypank.se-45564.xyz C=US, O=Let's Encrypt, CN=YE1 2026-09-18T07:27:20Z 2026-12-17T07:27:19Z 17251662632 [OBSERVED] evidence/raw/certspotter/20260919T105728Z-se-45564.xyz.json
easypank.se-9626654.pics C=US, O=Let's Encrypt, CN=YE2 2026-09-09T05:55:00Z 2026-12-08T05:54:59Z 17072948686 [OBSERVED] evidence/raw/certspotter/20260919T105729Z-se-9626654.pics.json
avcoa.click C=US, O=Let's Encrypt, CN=YE1 2026-09-05T15:05:21Z 2026-12-04T15:05:20Z 17004487410 [OBSERVED] evidence/raw/certspotter/20260919T105724Z-avcoa.click.json
btalning.click C=US, O=Let's Encrypt, CN=YE1 2026-09-02T07:30:50Z 2026-12-01T07:30:49Z 16939788574 [OBSERVED] evidence/raw/certspotter/20260919T105725Z-btalning.click.json

Each issuance carries exactly one name and no wildcard. [OBSERVED] (the four envelopes, payload.issuances[*].dns_names)

12.5 URL and path patterns

Pattern Where observed Confidence Anchor
easypank.se-45564.xyz/se the lure URL as given in the SMS. The two preserved renderings differ on the scheme, https:// in one and none in the other (2.1); the hostname and path are common to both [REPORTED] kit repo TAKEDOWN_REPORT.md:107-116; design spec lines 14-16
http://easypank.se-45564.xyz/se the probe target; answers with three 302 hops. Requested from the handset over a Swedish mobile carrier, not over Tor (5.5), and also from 28 Tor cells [OBSERVED] evidence/raw/cloak-phone/20260918T161229Z-http___easypank.se-45564.xyz_se.json and the 28 lure-URL envelopes under evidence/raw/cloak/
_v=valid_<14-digit UTC timestamp>_<32 hex> every landing URL; the timestamp is mint time plus eight hours, and the token is single use (2.4) [OBSERVED] 31 distinct values across the 60 envelopes in evidence/raw/cloak/ and evidence/raw/cloak-phone/, none deviating from the grammar: the 30 mints of 2.4 plus the spent token that arrived in the SMS
bls=<6 chars> one additional query parameter, seen once, on the 2026-09-03 btalning.click scan [OBSERVED] evidence/raw/urlscan/20260919T105718Z-page.domain__btalning.click_.json
path segment /ESZNhaXCmd every landing URL on easypank.se-9626654.pics, and on btalning.click fifteen days earlier [OBSERVED] all 60 envelopes of evidence/raw/cloak/ and evidence/raw/cloak-phone/ carry it; evidence/raw/urlscan/20260919T105718Z-page.domain__btalning.click_.json
base path /we194_cz_etc_easypark/, pattern <random>_<cc>_etc_<brand> <base href> in the kit HTML, twice more in the JS [SOURCE] kit_original/index.html:5, <base href="/we194_cz_etc_easypark/">, and grep -o -F returning 2 in kit_original/assets/index-d25ac0d4.js
base path /we194_cz_etc_easypark/ on four requests of the captured session [OBSERVED] the four we194_cz_etc_easypark envelopes in evidence/raw/har/
POST /JisiRmktje/api session bootstrap; returns the relay token and the operator’s message strings [OBSERVED] evidence/raw/har/20260919T105202Z-https___easypank.se-9626654.pics_JisiRmktje_api_token_755a9f6f-b4bc-4ef8-9118-17.json
POST /JisiRmktje/api/input per-field HTTP exfiltration, parallel to the socket; 17 requests in the captured session [OBSERVED] the 17 JisiRmktje_api_input envelopes in evidence/raw/har/
/assets/index-d25ac0d4.js, /assets/index-742a24eb.css ungated static assets of this exact build [OBSERVED] evidence/raw/kit-asset/20260918T180946Z-https___easypank.se-9626654.pics_assets_index-d25ac0d4.js.json, evidence/raw/kit-asset/20260918T180946Z-https___easypank.se-9626654.pics_assets_index-742a24eb.css.json

12.6 Response fingerprints

Indicator Value Confidence Anchor
Refusal body 9 bytes, the ASCII string Not Found, sha256 0019dfc4b32d63c1392aa264aed2253c1e0c2fb09216f8e2cc269bbfb8bb49b5 [OBSERVED] evidence/artifacts/0019dfc4b32d63c1392aa264aed2253c1e0c2fb09216f8e2cc269bbfb8bb49b5.html; all 56 envelopes in evidence/raw/cloak/
404 header set exactly these ten: Access-Control-Allow-Headers, Access-Control-Allow-Methods, Access-Control-Allow-Origin, Alt-Svc, Content-Type, Date, Server, Trace-Id, Transfer-Encoding, Via [OBSERVED] the same 56 envelopes, payload.summary.headers, one identical header set
Session cookie gfsessionid=<32 lowercase alphanumeric>; Path=/; Expires=<Date plus 24 h>, set on the second redirect hop only [OBSERVED] evidence/raw/cloak-phone/20260918T161229Z-http___easypank.se-45564.xyz_se.json, payload.headers_text
Device token UUIDv4 sent as cookie token and as the token and x-token request headers on every application request [OBSERVED] the bootstrap envelope in 12.5 and all 17 JisiRmktje_api_input envelopes, payload.summary.request_headers
Kit page response 200, 140535 bytes, Etag: "12d5585e1626af891dc3c1cca51d90c6", Last-Modified: Wed, 26 Aug 2026 08:00:40 GMT, no Server header [OBSERVED] evidence/raw/cloak-phone/20260918T161229Z-http___easypank.se-45564.xyz_se.json, fourth header block
Platform banner Server: GoFrame HTTP Server behind Via: 1.1 Caddy, with a per-response Trace-Id of 32 hex [OBSERVED] the same 56 envelopes

The platform banner identifies the hosting platform, not these operators, and is never a lead on its own: it is used here only paired with another indicator from this section. [SOURCE] (osint/discover.py:8-10)

12.7 Kit files

File Bytes sha256 Confidence
index.html 140535 a98ddbfa1083b0c6893b60c6bc019b9ffef3dbc36528e0820dc332e8d78691d8 [OBSERVED]
assets/index-d25ac0d4.js 444050 c8ccfd832d7f9b2e6ed47bbf455395776aec71aa22cdde790a05a1f17dd66821 [OBSERVED]
assets/index-742a24eb.css 34797 742a24ebaf60812317b40901165eba84d506c54938607911173959dbc4c3f045 [OBSERVED]

[OBSERVED] (sha256sum and stat -c '%s' against kit_original/ in this repository; the HTML hash matches the captured payload.body_sha256 of evidence/raw/cloak-phone/20260918T161229Z-http___easypank.se-45564.xyz_se.json, and the JS and CSS hashes match the bodies retrieved live in the two evidence/raw/kit-asset/ envelopes) These three hashes are the narrowest indicator here: they match this build only, and a rebuild defeats them. [INFERRED] (6.8)

12.8 Live relay channel

Indicator Value Confidence Anchor
Relay path pattern wss://<host>/ws?token=<UUIDv4>, same origin as the page, answered 101 [OBSERVED] evidence/raw/har/20260919T105202Z-https___easypank.se-9626654.pics_ws_token_755a9f6f-b4bc-4ef8-9118-171fec4947f7.json
Captured instance /ws?token=755a9f6f-b4bc-4ef8-9118-171fec4947f7 on easypank.se-9626654.pics [OBSERVED] all 930 records of the kit repository’s tools/ws_evidence.jsonl
Operator wire event result_type, the single inbound event carrying every operator command in its content.type [OBSERVED] the 3 result_type records at frames 275, 509 and 513, tools/ws_evidence.jsonl
Victim wire events login, heartbeat, page_type, input_text, submit_card [OBSERVED] event counts over the same 930 records
Frame envelope one JSON object per frame, event and content in all 930, messageId in 581 and timestamp in 43 [OBSERVED] key counts over the same 930 records

A detection rule keys on result_type, not on the in-browser names my-event, otp-valid, app-valid or custom-otp-valid: none of those four appears in any of the 930 captured frames. [OBSERVED] (the same file; 6.5)

12.9 SMS delivery

Indicator Value Confidence
Alphanumeric sender ID InfoSMS [REPORTED]
Delivery time 2026-09-18 16:46:15 CEST, 2026-09-18T14:46:15Z [REPORTED]

[REPORTED] (kit repository TAKEDOWN_REPORT.md:107-116) Both rest on the recipient’s statement, with no message artifact or carrier record behind them, so these two rows are leads for a carrier or police query rather than values a defender can match on. [INFERRED] (2.2)

12.10 Live platform hosts, platform and not campaign

The six names below are live hosts of the same phishing platform impersonating the same brand, verified over Tor on 2026-09-19 (section 8). [OBSERVED] None is confirmed as this campaign’s infrastructure: no capture from an accepted network exists for any of them, and none served the kit. [OBSERVED] (the 62 envelopes in evidence/raw/tier3-verify/, verdict kit zero times) They are listed as platform context and must not be reported as this campaign’s hosts. [INFERRED]

Host Address Root response over Tor AS at scan time Confidence
aseeasypark.cfd 43.162.111.113 404, 9 bytes AS132203 [OBSERVED]
easypark.work 43.165.1.140 404, 9 bytes AS132203 [OBSERVED]
easypark88.com 43.129.85.86 200, 8988 bytes AS132203 [OBSERVED]
easypark9.com 43.129.85.86 200, 6650 bytes AS132203 [OBSERVED]
easyparkss.cfd 43.157.24.72 404, 9 bytes AS132203 [OBSERVED]
easyparkss.sbs 43.157.24.72 404, 9 bytes AS132203 [OBSERVED]

[OBSERVED] (one envelope per domain in evidence/raw/tier3-verify/, payload.resolves_to, payload.status_code, payload.body_length and payload.server; evidence/raw/urlscan/20260919T100041Z-page.server__GoFrame_HTTP_Server__AND_page.domain__easypark_.json, payload.results[*].asn, for the AS number) The four 404 rows return a 9-byte body, the same length as the campaign hosts’ refusal, but the tier3 envelopes record no body hash, so byte equality is not established and none of these refusals is evidence that these hosts are gated as the campaign’s are. [OBSERVED] (the same envelopes have no body_sha256 field; 8.4) No owner name is asserted for AS132203, since no registration record for it was collected. [INFERRED] (section 9.7)

13. Recommendations and requested actions

Every action below traces to a fact established earlier in this report; none of it introduces a new claim. Each subsection states what the report can support asking for, and what would need cooperation the reporter does not have. The four generated reports (reports/police-dossier.md, reports/abuse-reports.md, reports/brand-brief.md, reports/press-narrative.md) and the kit repository’s own TAKEDOWN_REPORT.md and README.md are the baseline this section preserves and re-checks against the current evidence.

13.1 Swedish police

The evidence supports a report of attempted card fraud: a live, human-operated backend that streams typed card data before submission, validates it with a bank-identification-number lookup and returns a verdict, reject in each of the three observed cases (section 7.5, 7.8), served from infrastructure that gates on network and client type specifically to delay detection (section 5). [INFERRED] The captured session used fabricated data by deliberate design, so it demonstrates the mechanism without exposing any real victim’s card (section 7.1, section 10.7). [INFERRED] What the evidence cannot support is anything about the SMS itself: the sender ID InfoSMS and the delivery time rest on the recipient’s own account, with no PDU, screenshot or carrier record in either repository (section 2.2). [REPORTED] A filing in the bedrägeri / dataintrång track, as the kit repository frames it (kit repository TAKEDOWN_REPORT.md:275, README.md:59), can attach the infrastructure and session evidence directly. [SOURCE] Establishing who sent the message or by what route requires the carrier and network records addressed in 13.6. [INFERRED]

13.2 CERT-SE

CERT-SE takedown and abuse notification is a preserved ask from both source documents (kit repository README.md:56, SCAMMER_WORKFLOW.md:219). [SOURCE] What this report supports handing over is the confirmed infrastructure of section 4 (four hostnames, one origin address, two registrar abuse contacts), the gating behaviour of section 5, and the detection material of 13.7, so CERT-SE can coordinate with the registrar and host abuse desks below and circulate the indicators nationally. [INFERRED] What needs cooperation this investigation does not have: visibility into whether other Swedish recipients report the same sender ID or campaign, which only a national coordination point can aggregate. [INFERRED]

13.3 The registrar, NameSilo

The registrar publishes two different abuse addresses across the four registrations: abuse@namesilo.com for se-45564.xyz and se-9626654.pics, and support@namesilo.com for avcoa.click and btalning.click (section 4.2). [OBSERVED] (section 4.2) Both are needed for a report covering all four. [INFERRED]

The ask has changed for one of them since the abuse reports were drafted. [INFERRED] (section 4.2) se-9626654.pics, and the hostname easypank.se-9626654.pics under it, moved from two transfer-prohibited statuses to server hold and client hold between 2026-09-18T16:21:41Z and 2026-09-19T10:55Z, and the landing host no longer resolves (section 4.2). [OBSERVED] That domain is already off the air by registry or registrar action. [OBSERVED] (section 4.2) What is still worth asking for is confirmation that the hold is a deliberate abuse action and not a transient state, since nothing in this evidence records who requested it (section 4.2). [INFERRED] The other three registrations, se-45564.xyz, avcoa.click and btalning.click, carry only transfer-prohibited statuses and still resolve to the origin address as of the same collection (section 4.1, 4.2). [OBSERVED] The suspension request already drafted for all four (reports/abuse-reports.md) remains the live ask for these three specifically: no record in this evidence shows that request was actually sent to the registrar, only that the four reports were generated (2026-09-19T11:18:04Z, section 11.1). [INFERRED]

13.4 The hosting network’s abuse contact

The origin address 220.158.232.231 is where the takedown lever with the widest reach sits: the kit repository’s own reasoning is that the phishing page and the live operator console are the same host, so a host-level action stops both at once (kit repository TAKEDOWN_REPORT.md:75-76). [SOURCE] Section 7.5 shows a response delay consistent with a human operator choosing the next step rather than with automatic grading; 7.8 states what the capture does not prove. [INFERRED] The RDAP object for the containing netblock names an abuse-role contact, yennp@viettel.com.vn, and a separate technical/administrative contact, admin@buctbd.com (section 4.4). [OBSERVED] A report can be addressed to both roles recorded on the block, as reports/abuse-reports.md already does for the first. [INFERRED] This report does not assert an autonomous-system owner name for that address: the RDAP object carries no AS number, and AS38623 appears here only as urlscan scan-time data (section 4.4). [OBSERVED] A report should therefore cite the RDAP netblock and its named contacts rather than an AS owner. [INFERRED] Confirming the abuse desk’s actual response track record needs cooperation this investigation does not have. [INFERRED]

13.5 EasyPark

EasyPark has brand-holder standing for a takedown request that an individual reporter does not (reports/brand-brief.md:46-48). [SOURCE] The kit presents itself under EasyPark’s own Swedish payment-page branding, down to the visible title Parkeringsappen som ger dig mer tid till annat | EasyPark (section 6.3), and harvests vehicle registration plate, full card number, cardholder name, expiry, CVV and phone number, streamed as typed and again on submit (section 6.4, 7.8). [SOURCE] The current live set, as of the 2026-09-19 collection, is easypank.se-45564.xyz (redirector) still resolving, easypank.se-9626654.pics (landing host) no longer resolving following the holds of 13.3, and avcoa.click and btalning.click still resolving on the same address (section 4.1). [OBSERVED] What EasyPark’s own security team can add that this investigation cannot: confirmation of exactly where the kit’s copy diverges from the real payment flow, which would sharpen the brand brief beyond what external observation alone established. [INFERRED]

13.6 The recipient’s mobile operator and PTS

This report can support forwarding the lure text and its known indicators (the redirector hostname, the origin address) to the recipient’s mobile operator’s messaging-fraud channel and to PTS (Post- och telestyrelsen) for sender-ID abuse. [INFERRED] Both asks are already present in the kit repository (TAKEDOWN_REPORT.md:272-274, README.md:57). [SOURCE] What it cannot support is any claim about how the message reached the handset. [INFERRED] The sender ID InfoSMS carries no originating number at the recipient’s end (section 2.2). [REPORTED] The interconnect partner or paying SMPP account behind it lives only in carrier signalling records, CDRs and SS7 data that this investigation never had access to and that only the operator or a law-enforcement request can read (kit repository TAKEDOWN_REPORT.md, “Attribution limits”). [SOURCE] Reported carrier-level countermeasures against this kind of delivery, SMS firewalls, SMS Home Routing and sender-ID registries (kit repository TAKEDOWN_REPORT.md:268-271), are policy context this report repeats but did not test. [SOURCE]

13.7 Defenders, generally

The kit-level and platform-level fingerprints established in sections 6 and 8 are durable across a domain and IP rotation this kit’s operators have not yet been observed to make (section 6.8). [INFERRED]

Signal Where established Note Confidence
result_type WebSocket event, content.type verb section 6.5 the operator’s only control channel [SOURCE]; internal names such as my-event appear in none of the 930 captured frames [OBSERVED] [SOURCE] and [OBSERVED] as marked
/JisiRmktje/api and /JisiRmktje/api/input HTTP paths section 6.5, 6.6 a second, parallel exfiltration channel, not polling overhead [OBSERVED]
<random>_<cc>_etc_<brand> base-path convention section 6.3 per-deployment slug; this build’s suffix is easypark [SOURCE]
Asset hash c8ccfd832d7f9b2e6ed47bbf455395776aec71aa22cdde790a05a1f17dd66821 section 6.1 strongest signal, narrowest scope: this exact build only [OBSERVED]
page.server:"GoFrame HTTP Server" combined with a brand or AS term section 8.1, 8.2 never the header alone [SOURCE]

A hunting query on the platform header by itself is not a lead: it answers on a very large number of unrelated hosts and identifies the phishing platform, not this campaign’s operators (osint/discover.py:8-10; sections 4.5, 6.8, 8.1). [SOURCE] The kit repository’s own ask to pivot on the naming pattern by passive DNS or certificate transparency (kit repository README.md:58) does not hold for this campaign: crt.sh does not hold this campaign’s certificates, although the pattern does return other hostnames that have to be excluded on other grounds (4.3, 9.1), and Cert Spotter cannot take a pattern at all. Nothing in this evidence tests the passive-DNS half of that ask, so this repository’s own discovery code instead pivots outward from confirmed infrastructure, the origin address, the hosting AS and the kit’s own server fingerprint (osint/discover.py:3-6). [SOURCE] Confirming any candidate this pivots to as a sibling, rather than as unrelated platform noise, needs the same method used for the confirmed campaign: a capture from a Swedish mobile network, with a mobile User-Agent, against a freshly minted token, since a Tor vantage cannot distinguish a live cluster member that would serve the kit from one that would not (section 8.7). [INFERRED] The carrier-level countermeasures of 13.6 apply here too, as the durable defence against this delivery mechanism rather than against any one domain. [INFERRED]

Appendix A. Evidence index

A table row in this appendix is its own citation: the path is the anchor and the sha256 beside it is the value being verified, so rows carry no separate evidence label. Prose sentences outside the tables carry a label as elsewhere in this report.

A.1 Verifying the store

evidence/MANIFEST.sha256 has 433 lines, one per envelope or artifact file under evidence/; (cd evidence && sha256sum -c MANIFEST.sha256 | grep -vc OK) returns 0, so all 433 are present with a matching hash. [OBSERVED] (wc -l evidence/MANIFEST.sha256; same sha256sum -c command, run 2026-09-19)

grep -oE 'evidence/(raw|artifacts)/[A-Za-z0-9._/-]+' reports/easypark-smishing-investigation.md | sort -u returns 84 matches; 11 end in a slash, citing a directory as a set rather than a single file (for example “the 56 envelopes in evidence/raw/cloak/”), leaving 73 distinct cited files. All 73 exist on disk and each sha256 matches a manifest line; none is missing and none is an unlisted hash. [OBSERVED] (that command against this report; ls of each path; cross-reference against evidence/MANIFEST.sha256, 2026-09-19)

Three of those directory-set citations check out exactly against the manifest: evidence/raw/cloak/ holds 56 files, all cited as a set (5.3, 12.6); evidence/raw/cloak/ and evidence/raw/cloak-phone/ together hold 60 files, cited as a set (12.5); of the 40 files in evidence/raw/har/, 17 match JisiRmktje_api_input, cited as that set (6.6). [OBSERVED] (grep -c of the manifest against each of raw/cloak/, raw/cloak(-phone)?/ and raw/har/.*JisiRmktje_api_input, 2026-09-19) These sets are covered by the whole-store verification above, not listed file by file below.

A.2 Envelopes and artifacts cited by name

Grouped by the directory under evidence/ that holds them. The path shown is relative to that directory; the full path is evidence/<directory>/<path shown>.

evidence/raw/certspotter/ (6 of 18 files in this directory cited by name)

file sha256
20260918T164231Z-se-45564.xyz.json 013b6e520e6c385067cf19bd06ba028cc018a187ca3fef7ff0e1ff132ac9dde8
20260918T164232Z-se-9626654.pics.json 9b50854cce23a1d8b979f4180b5d8f7c01cb50acc4acdbdc039bd8db27b9f572
20260919T105724Z-avcoa.click.json 1f4446d9291797e7089eb092cf0fd862f5bc85803b6bddb85f9d5587e87462b7
20260919T105725Z-btalning.click.json 33c9779803e9056b59295e6d2965476e90bf11263122ec3785bafbeb7ab6b872
20260919T105728Z-se-45564.xyz.json b6be22df03d10cb8333b33ca472ba146994ce183638f17366cf909afd9897c63
20260919T105729Z-se-9626654.pics.json ca9044a83eae928e08e592c0c2597922724693515d952182061a077f017811cf

evidence/raw/cloak/ (1 of 56 files cited by name; the remaining 55 are covered by the set citations in A.1)

file sha256
20260918T160754Z-http___easypank.se-45564.xyz_se.json 597c66efc17d1bb18aa64dec8ed51605c443181fd18bc6fa257364049e2567e7

evidence/raw/cloak-control/ (2 of 2 files in this directory)

file sha256
20260918T160737Z-https___example.com_.json 57599e78d8b2d726f811fb1d946bb32e8cd7e8dd8fe3207f1cec88eac758b491
20260918T160750Z-https___example.com_.json 64371bda05a8e0192c8cb11e90ae8c611e8bd26b9ae7fbcf29f32ba5ea220ceb

evidence/raw/cloak-phone/ (4 of 4 files in this directory)

file sha256
20260918T161229Z-http___easypank.se-45564.xyz_se.1.json 3fd51a30591763b87fc9129e934ea49d589e4b7e054dd822183a90f8ceda3d7e
20260918T161229Z-http___easypank.se-45564.xyz_se.json f5a19e578e5a7a5308bab75a1bae01f4efbfa8b955ccff1d6d0f19b3d528bb2c
20260918T161229Z-https___easypank.se-9626654.pics_ESZNhaXCmd__v_valid_20260918232359_861d698a2bab.1.json d1882f881dae67cd1151d83934f4088f5381b51b12192aa367983912fd8b955f
20260918T161229Z-https___easypank.se-9626654.pics_ESZNhaXCmd__v_valid_20260918232359_861d698a2bab.json 48c10b2efeb76aed6dd611b364e14154b371c6d16830c41ea89e88426f8902e1

evidence/raw/ct/ (3 of 51 files in this directory cited by name)

file sha256
20260918T164240Z-easypank_.json ae6092531a88f20231dad877a4c647c888113b88d35c68850cde0c04d05fb258
20260919T105739Z-easypank_.json 0853d869c292f507fc849c268cd0137ea7d31428621829252f721b1de48fc1ee
20260919T111715Z-_.se-_.click.json 4e2897cd0a76653dbd3b7b45468f0862145ae8220fc508c60534606c40d38d01

evidence/raw/dns/ (29 of 121 files in this directory cited by name)

file sha256
20260918T160845Z-easypank.se-45564.xyz.1.json 8a69e1267f79b89a8b69988aca579e4760076f5bb6e24e5ccb64189f75dcd985
20260918T160845Z-easypank.se-45564.xyz.json 0bb5626b9333291ecca90138de7ef5ba8b8a4e369c41d4b819f47e04b46b9665
20260918T160846Z-easypank.se-45564.xyz.json c54e6ae160f51c4254b5d26f3e2f6294bc16cf1a39ec5d12ecadd0cec97b1e45
20260918T160846Z-easypank.se-9626654.pics.json 4f94b863f818c9f2262217ad3e20f7b9ebbe322780af8639f457ed41d0f4c19a
20260918T160847Z-easypank.se-9626654.pics.json 33eed65dc92121bc19447f5038a4cd93dbf5f5b670dabba0ba83cfaaa9091503
20260918T160848Z-easypank.se-9626654.pics.json dd81a443f3fa09d2dc391c48824bd334960e91307e0f1a4665c91ad4e0d2f58b
20260918T160848Z-se-45564.xyz.json 0754c1b0ef80e09cd386a5fa5882ba96337187c11947442ef02792746950a7d3
20260918T160849Z-se-45564.xyz.4.json eedd493a9ff3c0aecb94bf2c12ff8f033de94ebec66349d93ed1bcd845f0bd79
20260918T160849Z-se-45564.xyz.json c581353f6632dd23d83d3f0c997bf36e809e0d094119e10084035cf22f790628
20260918T160849Z-se-9626654.pics.json 684337140053f10e20851cf93242a364ec54d608c1ca4fb5f4ce6376a462f637
20260918T160850Z-se-9626654.pics.1.json 11389cdef56b013d85a1ac43915639fc7653656c80ba0fad098772e9577d8da2
20260918T160851Z-se-9626654.pics.1.json 9bb365de80654d794386dc9c71c0264c0615f101ccd7f73a2850bbeaddcddd72
20260918T160855Z-220.158.232.231.json 40f47d9958a0d23bf8560f477e7be8d396943c07df6f16e28280934211e1106f
20260918T181409Z-avcoa.click.json 2ed297fa5e645ea34330176d9b6c067403c4470302ceef54f4359808601e7b88
20260918T181414Z-avcoa.click.1.json 708f78e00d2e07c1d32ce39955fc091aaea57981cdb429f1007dc02e403abb31
20260918T181415Z-btalning.click.json da733f524003095bb10b46c1c31560fac064bb5d68e90d0707f449aedbbdcdc7
20260918T181421Z-btalning.click.json 085e429edb98ca269f265822325a4aafdbf7541f01b940e10d20ac2f89af5001
20260918T181422Z-liuguan168.lol.json d70a79c111be619c295db2f8de14b9e885ba3b114dc9da37f85f96203aedd022
20260919T105451Z-easypank.se-45564.xyz.json 46d41b603d8e4d041e1d1660e5c0f5e7461aafe81862c5bbe2ae6964b4670cf7
20260919T105512Z-easypank.se-9626654.pics.json 4494a01157e5ade72641bb775d46368b77bba25e0ff67f28e39929071c1ff7fc
20260919T105539Z-se-9626654.pics.json 337d4660d8c53e997f283013296f229baba20129398eb8c70f7411b2afd2908d
20260919T105541Z-se-9626654.pics.json 650bf12c6c995ecbb15ea15349f18fbcbc70e9c119485d7608c23026fdf62783
20260919T105543Z-se-9626654.pics.json ab436b4dcc99069a42a4b6b50b986ce7e442480ac5304dbe7f027fdd1ecddb0f
20260919T105545Z-se-9626654.pics.json 368b9d9c7b1da4150002448e35c0880ab1e141cab68e09ed7818f986a7086947
20260919T105547Z-se-9626654.pics.json 8c030b0c3cd42bd7dac49d4dd56f260fbe9ebea83042c39eb19c96803007ed65
20260919T105550Z-se-9626654.pics.json b910ccc5469d4c5b3c68c3d0d2bd26ae47bb34a398ca46b3befd6712a7d13d58
20260919T105552Z-se-9626654.pics.json 5ea71ccd915f616ec563086dae3551cdccb408441b71fa59ee227368d8ed31a6
20260919T105636Z-avcoa.click.json d859c50355e1a8ad110a2a41252fbf0ce7fafbc497a2ee1c25d4331d49928fb0
20260919T105659Z-btalning.click.json 4c2d0e768d14a867e214af47536212c12587f7bc91bb242055e8fe1f030b3f0e

evidence/raw/har/ (6 of 40 files in this directory cited by name; 17 of the 40 are also cited as the JisiRmktje_api_input matching set, A.1)

file sha256
20260919T105202Z-https___easypank.se-45564.xyz_se.json e1a75ac6266e4b6dcb57335a9c35cbfcdd62b04adaf622ea879d3c607775bff6
20260919T105202Z-https___easypank.se-9626654.pics_ESZNhaXCmd__v_valid_20260918232359_861d698a2bab.json cc4df2ee6ac7a007e1fa8386d69cddb92a7d5f668e92f492ada01f96d2505364
20260919T105202Z-https___easypank.se-9626654.pics_ESZNhaXCmd__v_valid_20260919031957_33bccaec191c.json 17ccbf3ad92486ffd15ecea49811bf905c59e2da7b49772e9b562e885ce37baa
20260919T105202Z-https___easypank.se-9626654.pics_JisiRmktje_api_input_token_755a9f6f-b4bc-4ef8-9.json d29b6943da6582255b2684326533239663db41b094d9911f0520c7c6c0e4a40f
20260919T105202Z-https___easypank.se-9626654.pics_JisiRmktje_api_token_755a9f6f-b4bc-4ef8-9118-17.json 7e8e0a838ffd586d2c3c99b31b99b650788f94a84ef6fc1171f906d6bb63b108
20260919T105202Z-https___easypank.se-9626654.pics_ws_token_755a9f6f-b4bc-4ef8-9118-171fec4947f7.json ff4646883cfd2ee2125265528d8aa768b8322668acf2dfed3a717d13e77c75b4

evidence/raw/kit-asset/ (2 of 2 files in this directory)

file sha256
20260918T180946Z-https___easypank.se-9626654.pics_assets_index-742a24eb.css.json 0ca3005fa582326412490cc6890319610ba58ba76975bb5625ad514c43af57f5
20260918T180946Z-https___easypank.se-9626654.pics_assets_index-d25ac0d4.js.json 3d88055da9da2258c8a63fbb53c33d809d52485b64016313994d9dda6bbe3bd3

evidence/raw/rdap/ (10 of 23 files in this directory cited by name)

file sha256
20260918T162138Z-easypank.se-9626654.pics.json 4d13601b4c460ef2ab4f9d8a300f004877ff97f9f27e9d6d993c100abd8a5ceb
20260918T162140Z-se-45564.xyz.json cf8b05b6c4a8e3ae51488a957b30d37ee0c76a6da4e78c3827dfe0477a7db5d9
20260918T162141Z-se-9626654.pics.json 7c85602d60e656fe0d57b484f98fd732b8f2013f261e31fed6c25467d63e48b1
20260918T162147Z-220.158.232.231.json 6900fa75ea004e8ef788bc0a3179110f9924ddb356b6c5faaaddd75ebb09a3d3
20260918T162807Z-se-9626654.pics.json 5e335891ca57f5170081d61afbfa764904ea204b0c43b767cbbe3d12bd074922
20260919T105537Z-se-45564.xyz.json 5c64a05afbd59b24736eac8a0b870735ed43bd3d29126a6298f5975b815cb606
20260919T105554Z-se-9626654.pics.json 9cba0f0d5bc9caa17abe1a4e3cfebe1384c844ba73e7cdb3c403b45caf4dfa67
20260919T105655Z-avcoa.click.json cf0f3f0b629474c7c17d480d963914c6f6f647907c7816b396b8c56ed90ea7f6
20260919T105717Z-btalning.click.json 97bd545edcd47c631935a25247010a358d89dd383dd3124eb17c934982bbb2cf
20260919T105723Z-220.158.232.231.json d1b81979138d7b893c79f07b8505ecd3459c3d6e8e9ba96d6ea5515bf79518da

evidence/raw/tier3-verify/ (3 of 62 files in this directory cited by name)

file sha256
20260919T100351Z-easypark.se-36586.online.json 3156ddcd298a89d02ec560460f80cf460602c773db74a8b243547b75b8490678
20260919T100351Z-easypark.se-toyota.homes.json 5876d3dc42d6f2fdc8a505624789b2f1e4e984a5fa0b208a540d60b43233aa79
20260919T100351Z-easypark.se-toyota.lol.json 0fdcc0f2eba000bb4802522779244567a1aac0ec058f8603249872314887ec4b

evidence/raw/urlscan/ (5 of 33 files in this directory cited by name)

file sha256
20260918T175939Z-page.ip__220.158.232.231_.json 75984a12303cfd7c2ba17b9e3d276b204bc66ff55bfa0acf9f963742856c1aaa
20260919T100041Z-page.server__GoFrame_HTTP_Server__AND_page.domain__easypark_.json c42d1cf9be6738d53ffa0ca30104fbd61e14a05de7bfa6b829def34296f4530f
20260919T100044Z-page.server__GoFrame_HTTP_Server__AND_page.asn__AS132203__AND_page.domain__park_.json 9209e4839565714a8d6d042a75329524fe359956329f2c6c40e80d32817f361f
20260919T105656Z-page.domain__avcoa.click_.json 769949429c48a978e90ef49244dc8ec956ff36502f2cecb860e751f7b71bb4cc
20260919T105718Z-page.domain__btalning.click_.json fe7a7de639c52e1d72d34222aeed2da0950e3dc1ed1bc78636b0d8868387d6c4

evidence/artifacts/ (2 of 21 files in this directory cited by name; all are content-addressed, so the filename stem is the hash)

file sha256
0019dfc4b32d63c1392aa264aed2253c1e0c2fb09216f8e2cc269bbfb8bb49b5.html 0019dfc4b32d63c1392aa264aed2253c1e0c2fb09216f8e2cc269bbfb8bb49b5
e3eaf9aa94f833e92c3e09df408c03dd98ba0675f7f6a878bbe1692b566d1e66.bin e3eaf9aa94f833e92c3e09df408c03dd98ba0675f7f6a878bbe1692b566d1e66

A.3 Kit repository files cited

The kit repository (/home/tugg/misc/dev/projects/kit, branch phishing-investigation) is a separate working tree from this repository and its files carry no line in evidence/MANIFEST.sha256; the hashes below were computed directly from the files as read from that repository, not from this repository’s evidence store. [OBSERVED] (git -C /home/tugg/misc/dev/projects/kit show phishing-investigation:<path> | sha256sum, run against each of the four files below, 2026-09-19)

file size (bytes) sha256
kit_original/index.html 140535 a98ddbfa1083b0c6893b60c6bc019b9ffef3dbc36528e0820dc332e8d78691d8
kit_original/assets/index-d25ac0d4.js 444050 c8ccfd832d7f9b2e6ed47bbf455395776aec71aa22cdde790a05a1f17dd66821
kit_original/assets/index-742a24eb.css 34797 742a24ebaf60812317b40901165eba84d506c54938607911173959dbc4c3f045

These three sha256 values match the ones the landing host served, which is what establishes that the preserved kit source and the captured live build are the same code (section 6.1). The HTML was served to the authorised handset request over a Swedish mobile carrier, outside Tor (5.5, 10.7); the JS and the CSS were served to two Tor requests from exit 171.25.193.131. [OBSERVED] (evidence/raw/cloak-phone/20260918T161229Z-http___easypank.se-45564.xyz_se.json and evidence/raw/kit-asset/20260918T180946Z-https___easypank.se-9626654.pics_assets_index-d25ac0d4.js.json and evidence/raw/kit-asset/20260918T180946Z-https___easypank.se-9626654.pics_assets_index-742a24eb.css.json)

The captured frame file, tools/ws_evidence.jsonl, has 930 lines (one JSON record per WebSocket frame) and sha256 f65a299f6969907be98c00a6cb5d0160e10f65b2501f0ba81ad7c5ed891664a9 as read from the kit repository. [OBSERVED] (git -C /home/tugg/misc/dev/projects/kit show phishing-investigation:tools/ws_evidence.jsonl | wc -l returns 930; piped to sha256sum returns the hash above, 2026-09-19) Like the three files above, it is tracked in the kit repository’s own git history and is not covered by this repository’s manifest; sections 6 and 7 cite it as tools/ws_evidence.jsonl or “the 930 captured frames”, never as an evidence/ path, because it was never collected into this repository’s evidence store. [OBSERVED] (kit repository, git -C /home/tugg/misc/dev/projects/kit log --oneline -- tools/ws_evidence.jsonl)

Appendix B. Glossary

Plain-language definitions for the terms this report relies on, written for a reader who is a police officer or a journalist rather than a network engineer. A definition below is background, not a factual claim about this campaign, so it carries no evidence label; where the report demonstrates the term, the relevant section is named.

Smishing. SMS phishing: a text impersonating a trusted sender to lure the recipient into opening a link and entering personal or payment details on a fake page, as in the EasyPark-impersonating message this report examines (section 2).

User-Agent. A short string a phone or browser sends with every web request, naming the browser and device. This campaign’s landing page reads it and serves the phishing page only to a mobile-looking User-Agent, refusing a desktop one making the same request (section 5).

Cloaking. Serving different content to different visitors depending on who, or what, appears to be asking, so an investigator sees something harmless while the intended victim sees the attack. Section 5 sets out this campaign’s two independent checks, source network and User-Agent.

Certificate transparency. Public, append-only logs recording every HTTPS certificate a certificate authority issues, searchable by hostname, letting a new domain be found within minutes of going live. Section 4.3 reads this campaign’s certificates from it; section 9.1 explains why the same brand-typo search also surfaces two hostnames this report treats as unconfirmed.

RDAP (Registration Data Access Protocol). The structured, machine-readable successor to WHOIS, returning who registered a domain, when, through which registrar, and its current status. Section 4.2 reads this campaign’s registration data from it; RDAP is used instead of WHOIS because it runs over the same Tor circuit as every other lookup (CLAUDE.md).

Registrar. The company a domain owner pays to hold a registration, and that can suspend or lock it on an abuse report. All four of this campaign’s registrable domains share one registrar, NameSilo, LLC (section 4.2), addressed directly in section 13.3.

Nameserver. The server that answers, for a given domain, which address it resolves to. A shared, unusual nameserver set across otherwise unrelated-looking names is itself a clustering signal (sections 4.1, 4.6).

Tor exit. The last computer in a Tor circuit, the one that contacts the destination and whose address the server sees instead of the real requester’s. Every request to the operators’ own hosts left from a Tor exit; section 5.2 notes that phishing kits, including this one, sometimes block Tor exits outright, which is why every probe also sends a control request over the same circuit to a non-campaign site.

DNS over HTTPS (DoH). Resolving a hostname to an address inside an ordinary encrypted HTTPS request rather than the plaintext lookup an operating system normally sends, so resolution travels over the same Tor circuit as everything else instead of leaking the investigator’s real path to the campaign’s own nameservers (section 4, section 10.1).

Bank identification number (BIN). The first several digits of a payment card number, identifying the issuing bank and scheme without identifying the cardholder. The captured session’s live relay looks this number up against a card the operator is shown in real time, before accepting or rejecting it (section 7.5).

One-time code relay. A phishing technique that takes whatever the victim enters, including a one-time code from the victim’s own bank, and relays it live into the real bank’s login flow to complete a fraudulent transaction. The kit’s /otpValid and /customOtpValid operator commands describe this capability (section 6.4), though this captured session never reached that stage (section 7.8).

WebSocket. A persistent, two-way connection that, unlike an ordinary web request, stays open so either side can send messages at any moment. This kit uses one to give the operator a live view of the victim’s session and a channel to send commands back (section 6.5), identified by a per-session token (section 7.6).

Alphanumeric sender identifier. An SMS sender name made of letters rather than a phone number, such as InfoSMS in this report’s subject message (section 2.2). A handset cannot originate one itself; it is a feature of the bulk-messaging product used to send it, so the identifier alone does not reveal who paid to send the message (section 3, 12.9).

Grey route. An SMS delivery path reaching a handset through an interconnect or reseller outside the sending brand’s own direct agreement with the recipient’s mobile operator, often chosen for lower cost or weaker sender-identity checks. Whether such a route carried this report’s subject message is not established: that needs carrier interconnect records, CDRs or SS7 data this investigation never had access to (section 13.6).

SMPP (Short Message Peer-to-Peer protocol). The protocol bulk SMS senders and aggregators use to submit messages into the mobile network for delivery. Which SMPP account or interconnect partner submitted this campaign’s message is a question only the recipient’s mobile operator or a law-enforcement request can answer (section 13.6).