#!/usr/bin/env python3 """Ransomware payment wallet blockchain analysis agent. Traces cryptocurrency payment flows from ransomware wallets using public blockchain APIs. Identifies transaction patterns, cluster relationships, and fund movement to exchanges or mixers. """ import json import re import sys try: import requests except ImportError: print("[!] 'requests' library required: pip install requests") sys.exit(1) BLOCKCHAIN_API = "https://blockchain.info" BLOCKSTREAM_API = "https://blockstream.info/api" BTC_ADDRESS_REGEX = re.compile( r"^(1[a-km-zA-HJ-NP-Z1-9]{25,34}|3[a-km-zA-HJ-NP-Z1-9]{25,34}|bc1[a-z0-9]{39,59})$" ) KNOWN_RANSOMWARE_WALLETS = { "12t9YDPgwueZ9NyMgw519p7AA8isjr6SMw": "WannaCry", "13AM4VW2dhxYgXeQepoHkHSQuy6NgaEb94": "WannaCry", "115p7UMMngoj1pMvkpHijcRdfJNXj6LrLn": "WannaCry", "1Mz7153HMuxXTuR2R1t78mGSdzaAtNbBWX": "DarkSide (Colonial Pipeline)", "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh": "DarkSide", } def validate_btc_address(address): """Validate Bitcoin address format.""" if BTC_ADDRESS_REGEX.match(address): return True return False def query_address_info(address): """Query blockchain.info for address details.""" url = f"{BLOCKCHAIN_API}/rawaddr/{address}?limit=50" resp = requests.get(url, timeout=30) resp.raise_for_status() data = resp.json() return { "address": address, "total_received_btc": data.get("total_received", 0) / 1e8, "total_sent_btc": data.get("total_sent", 0) / 1e8, "final_balance_btc": data.get("final_balance", 0) / 1e8, "n_tx": data.get("n_tx", 0), "transactions": data.get("txs", []), } def query_blockstream_address(address): """Query Blockstream API for address stats (fallback).""" url = f"{BLOCKSTREAM_API}/address/{address}" resp = requests.get(url, timeout=30) resp.raise_for_status() data = resp.json() chain = data.get("chain_stats", {}) return { "address": address, "funded_txo_count": chain.get("funded_txo_count", 0), "spent_txo_count": chain.get("spent_txo_count", 0), "funded_txo_sum_btc": chain.get("funded_txo_sum", 0) / 1e8, "spent_txo_sum_btc": chain.get("spent_txo_sum", 0) / 1e8, } def extract_output_addresses(transactions, source_address): """Extract downstream addresses from transaction outputs.""" downstream = {} for tx in transactions: tx_hash = tx.get("hash", "unknown") is_outgoing = any( inp.get("prev_out", {}).get("addr") == source_address for inp in tx.get("inputs", []) ) if not is_outgoing: continue for out in tx.get("out", []): addr = out.get("addr") value = out.get("value", 0) / 1e8 if addr and addr != source_address: if addr not in downstream: downstream[addr] = {"total_btc": 0, "tx_count": 0, "tx_hashes": []} downstream[addr]["total_btc"] += value downstream[addr]["tx_count"] += 1 downstream[addr]["tx_hashes"].append(tx_hash[:16]) return downstream def check_known_wallets(address): """Check if address matches known ransomware wallets.""" if address in KNOWN_RANSOMWARE_WALLETS: return {"known": True, "family": KNOWN_RANSOMWARE_WALLETS[address]} return {"known": False, "family": None} def detect_peel_chain(transactions, address): """Detect peel chain pattern in outgoing transactions.""" outgoing_values = [] for tx in transactions: is_outgoing = any( inp.get("prev_out", {}).get("addr") == address for inp in tx.get("inputs", []) ) if is_outgoing: outputs = [o.get("value", 0) / 1e8 for o in tx.get("out", []) if o.get("addr") != address] outgoing_values.extend(outputs) if len(outgoing_values) < 3: return {"peel_chain_detected": False, "reason": "Insufficient transactions"} decreasing = sum(1 for i in range(1, len(outgoing_values)) if outgoing_values[i] < outgoing_values[i - 1]) ratio = decreasing / (len(outgoing_values) - 1) if len(outgoing_values) > 1 else 0 return { "peel_chain_detected": ratio > 0.6, "decreasing_ratio": round(ratio, 3), "num_outputs": len(outgoing_values), } def analyze_wallet(address): """Full analysis of a ransomware payment wallet.""" report = {"analysis_type": "Ransomware Payment Wallet Analysis", "address": address} if not validate_btc_address(address): report["error"] = f"Invalid Bitcoin address format: {address}" return report report["known_wallet_check"] = check_known_wallets(address) try: info = query_address_info(address) report["wallet_info"] = { "total_received_btc": info["total_received_btc"], "total_sent_btc": info["total_sent_btc"], "final_balance_btc": info["final_balance_btc"], "transaction_count": info["n_tx"], } downstream = extract_output_addresses(info["transactions"], address) report["downstream_addresses"] = { "count": len(downstream), "top_recipients": sorted( [{"address": a, **d} for a, d in downstream.items()], key=lambda x: x["total_btc"], reverse=True, )[:10], } for recipient in report["downstream_addresses"]["top_recipients"]: match = check_known_wallets(recipient["address"]) recipient["known_entity"] = match["family"] if match["known"] else "Unknown" report["peel_chain_analysis"] = detect_peel_chain(info["transactions"], address) except requests.RequestException as e: report["error"] = f"API query failed: {e}" try: fallback = query_blockstream_address(address) report["wallet_info_blockstream"] = fallback except requests.RequestException as e2: report["fallback_error"] = f"Blockstream fallback also failed: {e2}" return report if __name__ == "__main__": print("=" * 60) print("Ransomware Payment Wallet Analysis Agent") print("Blockchain tracing, cluster analysis, fund flow mapping") print("=" * 60) if len(sys.argv) < 2: print("\nUsage:") print(" python agent.py ") print(" python agent.py --deep") print("\nExample:") print(" python agent.py 12t9YDPgwueZ9NyMgw519p7AA8isjr6SMw") sys.exit(0) address = sys.argv[1] print(f"\n[*] Analyzing wallet: {address}") report = analyze_wallet(address) known = report.get("known_wallet_check", {}) if known.get("known"): print(f"[!] KNOWN RANSOMWARE WALLET: {known['family']}") info = report.get("wallet_info", {}) if info: print(f"\n--- Wallet Summary ---") print(f" Total received: {info.get('total_received_btc', 0):.8f} BTC") print(f" Total sent: {info.get('total_sent_btc', 0):.8f} BTC") print(f" Balance: {info.get('final_balance_btc', 0):.8f} BTC") print(f" Transactions: {info.get('transaction_count', 0)}") ds = report.get("downstream_addresses", {}) if ds.get("count", 0) > 0: print(f"\n--- Top Downstream Recipients ({ds['count']} total) ---") for r in ds.get("top_recipients", [])[:5]: entity = r.get("known_entity", "Unknown") print(f" {r['address'][:20]}... {r['total_btc']:.8f} BTC [{entity}]") peel = report.get("peel_chain_analysis", {}) if peel.get("peel_chain_detected"): print(f"\n[!] Peel chain pattern detected (ratio: {peel['decreasing_ratio']})") if report.get("error"): print(f"\n[!] Error: {report['error']}") print(f"\n[*] Full report:\n{json.dumps(report, indent=2, default=str)}")