A forensic teardown and hostile response to the Smishing Triad's Lighthouse phishing kit.
The Hustle
It started, as these things always do, with a text message.
California DMV Final Notice: Enforcement will begin on March 21.
Our system indicates you have an unresolved traffic violation.
Per relevant regulations, if payment is not completed by March 20, 2026, the following will apply:
- Update your record in the DMV system
- Suspend your vehicle registration starting March 21
- Temporarily restrict driving privileges for 30 days
- Refer your account for further processing with an additional administrative fee
- Possible legal follow-up and impact to your credit record
Please settle this promptly to avoid service restrictions and additional procedures.
Link:https://ca.gov-axb.cfd/dmv
Classic. Urgency. Authority. Escalating consequences. A $6.99 "traffic violation" — just low enough that a panicked person might pay it without thinking. The link even starts with ca.gov- to give it that government feel, like the digital equivalent of a trench coat and a fake badge.
They sent this to the wrong phone.
The Forensics
Twenty-two hours. That's the entire lifespan of this operation from domain registration to active phishing campaign. Let's appreciate the speedrun:
| Timestamp | Event |
|---|---|
| 2026-03-19 14:10 | Domain gov-axb.cfd registered via Gname.com (Singapore) |
| 2026-03-20 ~12:17 | Let's Encrypt SSL certificate issued for ca.gov-axb.cfd
|
| 2026-03-20 ~13:00 | Smishing messages begin arriving |
The domain was registered on a .cfd TLD — that's "Clothing Fashion Design," in case you were wondering what haute couture has to do with the California DMV. It costs about $0.98 to register. The attackers configured wildcard DNS pointing everything at 47.89.135.90 — an Alibaba Cloud server — so ca.gov-axb.cfd, tx.gov-axb.cfd, fl.gov-axb.cfd, and literally any subdomain you can dream up all resolve to the same phishing kit. Seven confirmed state-targeted subdomains on a single domain. Assembly line phishing.
The nameservers (share-dns.com, share-dns.net) are a Chinese DNS provider. The registrar abuse contact is in Singapore. The hosting is Alibaba Cloud's US allocation. It's a jurisdictional lasagna designed to make takedowns as painful as possible.
Meet the Kit: Lighthouse
The phishing page itself is a slick California DMV impersonation — official logo, official color scheme, footer links to real .ca.gov pages. It's built on Vue.js 3, bundled with Vite, communicating over Socket.IO with AES-128-CBC encrypted WebSocket messages. This isn't some amateur HTML form. This is a commercial product.
It's called Lighthouse — a phishing-as-a-service (PhaaS) platform operated by the Smishing Triad, a Chinese cybercrime operation that Google literally filed a federal lawsuit against in November 2025. The operator, attributed to someone going by Wang Duo Yu, runs a platform serving ~300 "front desk staff" worldwide, targeting 316+ brands across 74 countries through an estimated 194,000+ malicious domains.
The kit has a real-time operator panel. When a victim lands on the page, the operator sees their session appear in real time. As the victim fills in their name, address, credit card — the data streams live to the operator's dashboard. They can push the victim through verification steps in real time: "Enter the code we just sent to your phone." "Now enter your card PIN." It's live, interactive social engineering at industrial scale.
The victim flow:
Landing Page → Contact Info Form → Credit Card Form → Verification Codes → 💀
Every field submission, every page navigation, every keystroke-level interaction — all wrapped in AES encryption and shuttled over WebSocket. The kit even has anti-debugging protections in its JavaScript, string obfuscation tables, and mobile User-Agent gating (it won't even load if you're not on a phone browser).
They thought of everything.
Almost.
The Reverse Engineering
The kit's JavaScript is two files totaling ~570KB of heavily obfuscated code. Here's what that looks like:
function xe(){const t=["YWdl","message","Y2hhbm","Zmllb","c3VibW","bm90a..."];
// ... 260,000 more characters of this
Every meaningful string — event names, API paths, encryption keys — is routed through a deobfuscation function (be()) that indexes into a shuffled, Base64-encoded string table. The Socket.IO connection path isn't /socket.io/ like normal. It's been moved. The encryption key and IV aren't in plaintext. Nothing is where it should be.
Step 1: Find the Socket.IO Path
After failing to statically decode the obfuscation (the string table uses a self-modifying shuffle — it rearranges itself during initialization), I pivoted to empirical observation. Loaded the page in a headless browser with a mobile User-Agent, captured the WebSocket traffic:
wss://ca.gov-axb.cfd:443/console/?uuid=<uuid>&EIO=4&transport=websocket
The Socket.IO path is /console/. Not /socket.io/. Not /ws/. Not anything in the standard playbook.
Step 2: Crack the Encryption
All WebSocket messages are encrypted. Client sends 42["message","<base64>"], server responds the same way. The actual event data is AES-128-CBC encrypted inside that base64 blob.
From the obfuscated source, I could see the key and IV were assembled from string fragments:
const We = Be(226) + ye(250) + ze(254) + "LDND"; // AES key
const Se = "OJGJHHFMJEJB" + we(259); // AES IV
Ne = CryptoJS.enc.Utf8.parse(We); // → WordArray
Te = CryptoJS.enc.Utf8.parse(Se); // → WordArray
The Be(), ye(), ze(), we() functions are all aliases for the same deobfuscator, returning short string fragments. I couldn't decode them statically — the shuffle function defeats that approach.
So I intercepted the JavaScript in flight. Using Playwright's route API, I caught the JS file as it loaded, injected a single line that exposed the computed key values to the global scope, and read them out:
await context.route('**/CPD9iRZf.js', async (route) => {
const response = await route.fetch();
let body = await response.text();
body = body.replace(
/Se="OJGJHHFMJEJB"\+\w+\(\d+\)/,
(match) => match + ';window.__AES_KEY=We;window.__AES_IV=Se'
);
await route.fulfill({ response, body });
});
Key: KIKOCCJCFILDLDND
IV: OJGJHHFMJEJBDFAI
Verified by decrypting a captured server message:
{"data":{"money":"","successUrl":"","currencySymbol":"","products":[]},"event":"userSiteConfig"}
And a captured client message:
{"event":"changleField","data":{"router":"首页"}}
That typo — changleField instead of changeField — is a known Lighthouse kit fingerprint. It's in every deployment. Somewhere, a developer fat-fingered it once, and now it's a forensic signature stamped across 194,000 domains.
Also: 首页 is Mandarin for "home page." The Chinese-language strings are everywhere in the source: 手机验证页 (phone verification page), 运通CVV验证页 (Amex CVV verification page), 加密异常! (encryption exception!). For a kit that goes to great lengths to look like the California DMV, it sure does think in Mandarin.
The Weapon
With the encryption cracked and the protocol reverse-engineered, it was time to build.
Not a Python script. Not a Node.js hack. Rust. Specifically: an async, multi-session, zero-copy WebSocket flood engine using Tokio, with native AES-128-CBC encryption, realistic fake data generation, and the exact Socket.IO protocol the kit expects.
Each session:
- Opens a WebSocket to
/console/with a mobile User-Agent - Completes the Engine.IO handshake
- Sends the Socket.IO connect packet
- Responds to server heartbeats (ping
2→ pong3) - Encrypts and sends 12 events mimicking a complete victim session:
- Router navigation (
changleField— yes, with the typo) - Full personal info (name, address, city, state, zip, phone, email)
- Full credit card data (Luhn-valid card number, holder name, expiry, CVV)
- Phone verification code
- Email verification code
- PIN code
- Express CVV re-verification
- Custom verification code
- Router navigation (
- Closes gracefully
Every piece of fake data is realistic:
- Names drawn from US census frequency tables
- Addresses with real California street patterns and cities
- ZIP codes matching California postal zones
- Phone numbers with correct California area codes
- Credit cards that pass Luhn validation (Visa, Mastercard, Amex, Discover prefixes)
- Email addresses with realistic username patterns at common providers
From the server's perspective, each session is indistinguishable from a real victim clicking through the phishing flow.
The Flood
╔══════════════════════════════════════════════════════════╗
║ LIGHTHOUSE FLOOD — Pure Rust WebSocket Engine ║
║ AES-128-CBC | Direct Socket.IO | Max Throughput ║
╚══════════════════════════════════════════════════════════╝
Target: https://ca.gov-axb.cfd
WS Path: /console/
Concurrency: 100
Count: ∞
First test: 5 sessions, 3 concurrent. 60 events, 0 errors. Proof of concept.
Second test: 200 sessions, 30 concurrent. 2,400 events, 0 errors, 28 seconds. Warming up.
Third test: 1,000 sessions, 100 concurrent. 12,000 events, 0 errors, 42 seconds. Now we're talking. ~24 complete fake victims per second.
Then we let it rip.
╔══════════════════════════════════════════════════════════╗
║ FLOOD COMPLETE ║
╠══════════════════════════════════════════════════════════╣
║ Submitted: 100700 | Events: 1208984 | Errors: 0 ║
╚══════════════════════════════════════════════════════════╝
One hundred thousand fake victim sessions. 1.2 million encrypted events. Zero errors.
One hour. One machine. One Rust binary. Their operator's dashboard — the same one they use to monitor real victims in real time — is now a firehose of:
- Jennifer Wilson from San Jose, CA 95132, card ending in 8388
- Kevin Sanchez from Chula Vista, CA 92101, card ending in 6501
- Laura Martin from Santa Ana, CA 92701, card ending in 4787
- ... times one hundred thousand.
Every single entry looks real. Luhn-valid card numbers that'll fail at the processor. California addresses that go to actual streets. Phone numbers that ring actual area codes. The operators can't tell which data is real and which is garbage. Their entire database is poisoned.
For every real victim they managed to phish today, there are now thousands of fake records burying them. Good luck finding the needle in that haystack.
The Takeaway
This particular phishing operation is part of a massive, well-funded, commercially operated cybercrime ecosystem. The Smishing Triad runs Lighthouse as a business — subscription model, customer support, Telegram channels, the works. Google sued them. The FBI has received thousands of complaints. They're still operating.
Individual takedowns are whack-a-mole. The domain gov-axb.cfd will die, and tomorrow there'll be gov-xyz.cfd and gov-abc.win and a hundred more. The kit itself rotates, the infrastructure shifts, the TLDs change.
But today? Today, one specific operator's database is garbage. One specific campaign's ROI just cratered. One specific Lighthouse instance's real-time dashboard is scrolling fake Californians faster than any human could possibly triage.
They set up an encrypted, obfuscated, anti-debugging, mobile-gated phishing operation.
We reverse-engineered the encryption in an afternoon and flooded them with a million fake victims before dinner.
Fuck around. Find out.
Technical Summary
| Component | Detail |
|---|---|
| Target |
ca.gov-axb.cfd (California DMV phishing) |
| Threat Actor | Smishing Triad / Lighthouse PhaaS |
| Kit Stack | Vue.js 3 + Vite + Socket.IO + AES-128-CBC |
| Socket.IO Path |
/console/ (non-standard) |
| Encryption Key |
KIKOCCJCFILDLDND (UTF-8) |
| Encryption IV |
OJGJHHFMJEJBDFAI (UTF-8) |
| Kit Fingerprint |
changleField typo in all event names |
| Flood Tool | Rust + Tokio + tungstenite (async WebSocket) |
| Sessions Completed | 100,700+ |
| Events Sent | 1,208,984+ |
| Error Rate | 0.000% |
| Throughput | ~24 complete victim sessions/second |
| Duration | ~63 minutes |
Filed under: threat intelligence, active defense, phishing disruption, and not taking shit from scammers.

Top comments (0)