import uuid import base64 from curl_cffi import requests # 用于模拟指纹 from config import CLAUDE_URL, get_proxy from models import ClaudeAccount from identity import random_ua def attack_claude(target_email): """伪装成浏览器发起攻击""" device_id = str(uuid.uuid4()) ua = random_ua() headers = { "Host": "claude.ai", "Anthropic-Anonymous-Id": f"claudeai.v1.{uuid.uuid4()}", "Sec-Ch-Ua-Full-Version-List": '"Google Chrome";v="143.0.7499.105", "Chromium";v="143.0.7499.105", "Not A(Brand";v="24.0.0.0"', "Sec-Ch-Ua-Platform": '"Linux"', "Sec-Ch-Ua": '"Google Chrome";v="143", "Chromium";v="143", "Not A(Brand";v="24"', "Baggage": "sentry-environment=production,sentry-release=ce5600af514463a166f4cd356a6afbc46ee5cd3d,sentry-public_key=58e9b9d0fc244061a1b54fe288b0e483,sentry-trace_id=7bdc872994f347d6b5a610a520f40401,sentry-org_id=1158394", "Anthropic-Client-Sha": "ce5600af514463a166f4cd356a6afbc46ee5cd3d", "Content-Type": "application/json", "Anthropic-Client-Platform": "web_claude_ai", "Anthropic-Device-Id": device_id, "Anthropic-Client-Version": "1.0.0", "User-Agent": ua, "Origin": "https://claude.ai", "Referer": "https://claude.ai/login?returnTo=%2Fonboarding", "Accept-Encoding": "gzip, deflate, br", "Accept-Language": "zh-CN,zh;q=0.9", "Priority": "u=1, i" } payload = { "utc_offset": -480, "email_address": target_email, "login_intent": None, "locale": "en-US", "oauth_client_id": None, "source": "claude" } try: print(f"[*] 正在向 Claude 发送 Magic Link 请求: {target_email}") session = requests.Session() response = session.post( CLAUDE_URL, json=payload, headers=headers, impersonate="chrome124", proxies=get_proxy(), ) if response.status_code == 200: print("[+] 请求成功,Claude 已发信。") return True elif response.status_code == 429: print("[-] 被限流了 (Rate Limited)。") else: print(f"[-] 请求失败 Code: {response.status_code}, Body: {response.text}") except Exception as e: print(f"[-] 发生异常: {e}") return False def finalize_login(magic_link_fragment): """ 完成最后一步:无需浏览器,直接交换 sessionKey。 magic_link_fragment 格式: https://claude.ai/magic-link#token:base64_email 返回 ClaudeAccount 对象 """ # 1. 外科手术式拆解 Hash if '#' in magic_link_fragment: fragment = magic_link_fragment.split('#')[1] else: fragment = magic_link_fragment if ':' not in fragment: print("[-] 链接格式错误: 找不到 token 和 email 的分隔符") return None # 分割 nonce 和 base64_email nonce, encoded_email = fragment.split(':', 1) try: decoded_email = base64.b64decode(encoded_email).decode('utf-8') print(f"[*] 解析成功 -> Email: {decoded_email} | Nonce: {nonce[:8]}...") except: print(f"[*] 解析成功 -> Nonce: {nonce[:8]}...") # 2. 构造最终 payload verify_url = "https://claude.ai/api/auth/verify_magic_link" payload = { "credentials": { "method": "nonce", "nonce": nonce, "encoded_email_address": encoded_email }, "locale": "en-US", "oauth_client_id": None, "source": "claude" } # 3. 伪造指纹头 device_id = str(uuid.uuid4()) ua = random_ua() headers = { "Host": "claude.ai", "Content-Type": "application/json", "Origin": "https://claude.ai", "Referer": "https://claude.ai/magic-link", "User-Agent": ua, "Accept": "*/*", "Accept-Language": "zh-CN,zh;q=0.9", "Anthropic-Client-Version": "1.0.0", "Anthropic-Client-Platform": "web_claude_ai", "Anthropic-Device-Id": device_id, "Sec-Fetch-Dest": "empty", "Sec-Fetch-Mode": "cors", "Sec-Fetch-Site": "same-origin", "Priority": "u=1, i" } try: print(f"[*] 正在交换 SessionKey...") session = requests.Session() response = session.post( verify_url, json=payload, headers=headers, impersonate="chrome124", proxies=get_proxy(), ) if response.status_code == 200: data = response.json() # 1. 提取 SessionKey session_key = response.cookies.get("sessionKey") if not session_key: for name, value in response.cookies.items(): if name == "sessionKey": session_key = value break if not session_key: print("[-] 请求成功 (200),但未在 Cookie 中找到 sessionKey。") print(f"Response: {str(data)[:200]}...") return None # 2. 提取 Org UUID try: org_uuid = data['account']['memberships'][0]['organization']['uuid'] email = data['account']['email_address'] print(f"[+] 登录成功。OrgID: {org_uuid}") return ClaudeAccount(email, session_key, org_uuid, ua) except KeyError as e: print(f"[-] 无法提取 Organization UUID,结构可能变了: {e}") print(f"Response keys: {data.keys() if isinstance(data, dict) else type(data)}") return None else: print(f"[-] 交换失败 Code: {response.status_code}") print(f"Body: {response.text}") return None except Exception as e: print(f"[-] 发生异常: {e}") return None