JacobJandon/Sicry

GitHub: JacobJandon/Sicry

Sicry 是一个单文件 Python 库,为 AI Agent 提供 Tor/暗网访问能力,整合了 18 个搜索引擎和 LLM 驱动的 OSINT 分析流水线。

Stars: 0 | Forks: 0

# SICRY™ — 面向 AI Agent 的 Tor/Onion 网络接入层 [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/JacobJandon/Sicry/blob/main/LICENSE) [![CI](https://static.pigsec.cn/wp-content/uploads/repos/2026/03/64cc88e77c021258.svg)](https://github.com/JacobJandon/Sicry/actions/workflows/ci.yml) **作者 JacobJandon**  ·  [github.com/JacobJandon/Sicry](https://github.com/JacobJandon/Sicry) 单个 Python 文件。放入任何项目中,您的 AI agent 即可获得对 Tor/.onion 暗网的完全访问权限——与 agent 访问常规互联网时使用的同样简洁的工具接口,现在专用于隐藏服务。 内置 Robin 的完整搜索引擎目录(18 个引擎)和 OSINT 流水线。无需安装 Robin。无额外进程。除 `.env` 文件外无需其他配置。 ``` pip install requests[socks] beautifulsoup4 python-dotenv stem apt install tor && tor & cp .env.example .env # add one API key (or use Ollama — no key needed) python sicry.py check # → CONNECTED via Tor | exit IP: 185.220.101.5 ``` ## 目录 1. [SICRY™ 的功能](#what-sicry-does) 2. [安装](#installation) 3. [快速入门](#quickstart) 4. [全部九个函数](#all-nine-functions) 5. [工具模式 (Anthropic / OpenAI / Gemini)](#tool-schemas) 6. [框架集成](#framework-integration) 7. [CLI 参考](#cli-reference) 8. [完整 OSINT 流水线](#the-full-osint-pipeline) 9. [分析模式](#analysis-modes) 10. [18 个搜索引擎](#18-search-engines) 11. [环境变量](#environment-variables) 12. [Tor 设置](#tor-setup) 13. [故障排除](#troubleshooting) 14. [致谢](#credits) ## SICRY™ 的功能 SICRY™ 为 AI agent 提供了确切的 6 个工具——与它们在 clearnet(明网)上已经掌握的 6 个工具相同,只是现在通过 Tor 运行: | SICRY™ 工具 | Clearnet 等效工具 | 功能描述 | |---|---|---| | `sicry_check_tor` | 健康检查 | 验证 Tor 是否处于活动状态,获取出口 IP | | `sicry_renew_identity` | 重置会话 | 轮换电路,获取新的出口节点 | | `sicry_fetch` | `fetch_url()` / `browser_read_page()` | 通过 Tor 读取任何 URL 或 `.onion` | | `sicry_search` | `web_search()` / `brave_search()` | 查询 18 个暗网搜索引擎 | | `sicry_ask` | `analyze()` / `summarize()` | 基于原始内容的 LLM OSINT 报告 | | `sicry_check_engines` | ping / 健康检查 | 所有 18 个引擎的延迟 + 状态 | 外加三个质量提升辅助工具(Robin 模式,可直接调用): | 辅助函数 | 功能描述 | |---|---| | `refine_query(query)` | LLM:自然语言 → ≤5 个词的暗网查询 | | `filter_results(query, results)` | LLM:从所有原始结果中筛选出前 20 个最相关的 | | `scrape_all(urls)` | 并发批量抓取 → `{url: "title - text"}` 字典 | ## 安装 ### 系统要求 - Python 3.10+ - 本地运行 Tor daemon - pip 包(见下文) ### 1. 安装 Tor **Linux (Debian/Ubuntu):** ``` apt install tor tor & ``` **macOS:** ``` brew install tor tor & ``` **自定义 DataDirectory(推荐用于 `renew_identity`):** ``` cat > /tmp/sicry_tor.conf << 'EOF' SocksPort 9050 ControlPort 9051 CookieAuthentication 1 DataDirectory /tmp/tor_data EOF tor -f /tmp/sicry_tor.conf & ``` 使用自定义配置时,在 `.env` 中设置 `TOR_DATA_DIR=/tmp/tor_data`。 ### 2. 安装 Python 依赖 ``` pip install -r requirements.txt ``` 或手动安装: ``` pip install requests[socks] beautifulsoup4 python-dotenv stem # 可选 —— 仅在使用 MCP server 时需要 pip install mcp # 可选 —— 仅在使用 OpenAI/Anthropic/Gemini LLM 后端时需要 pip install openai # for OpenAI pip install anthropic # for Anthropic/Claude pip install google-generativeai # for Gemini ``` ### 3. 配置 `.env` ``` cp .env.example .env ``` 最小配置 —— 选择一个 LLM: ``` # 无密钥选项(本地推理): LLM_PROVIDER=ollama OLLAMA_MODEL=llama3.2 # OpenAI: LLM_PROVIDER=openai OPENAI_API_KEY=sk-... # Anthropic: LLM_PROVIDER=anthropic ANTHROPIC_API_KEY=sk-ant-... # Gemini: LLM_PROVIDER=gemini GEMINI_API_KEY=AIza... ``` ## 快速入门 ``` # 验证 Tor 是否正在运行 python sicry.py check # → 已通过 Tor 连接 | 出口 IP: 185.220.101.5 | 错误: None # 搜索暗网 python sicry.py search "ransomware data leak" --max 10 # 获取 .onion 页面 python sicry.py fetch http://juhanurmihxlp77nkq76byazcldy2hlmovfu2epvl5ankdibsot4csyd.onion # 为您的框架打印工具 schemas python sicry.py tools # Anthropic format (default) python sicry.py tools --format openai # OpenAI format python sicry.py tools --format gemini # Gemini format # 轮换 Tor 身份 python sicry.py renew # 启动 MCP server (用于 Claude Desktop / Cursor / Zed) python sicry.py serve ``` 在 Python 中: ``` import sicry # 验证 Tor print(sicry.check_tor()) # → {"tor_active": True, "exit_ip": "185.220.101.5", "error": None} # 搜索 results = sicry.search("credential dump") # → [{"title": "...", "url": "http://...onion/...", "engine": "Ahmia"}, ...] # 获取 page = sicry.fetch("http://juhanurmihxlp77nkq76byazcldy2hlmovfu2epvl5ankdibsot4csyd.onion") # → {"url": "...", "is_onion": True, "status": 200, "title": "Ahmia", "text": "...", "links": [...]} ``` ## 全部九个函数 ### `check_tor() → dict` 验证 Tor 是否正在运行以及机器是否通过 Tor 出口节点进行路由。 ``` r = sicry.check_tor() # {"tor_active": True, "exit_ip": "185.220.101.5", "error": None} # {"tor_active": False, "exit_ip": None, "error": "connection refused"} ``` **首先调用此函数。** 如果 Tor 宕机,所有其他网络函数将静默失败。 ### `renew_identity() → dict` 轮换 Tor 电路 —— 获取新的出口节点和全新的身份。 ``` r = sicry.renew_identity() # {"success": True, "error": None} ``` 按顺序尝试认证: 1. `TOR_CONTROL_PASSWORD` 环境变量(如果您在 torrc 中设置了 `HashedControlPassword`) 2. 来自 `TOR_DATA_DIR` 环境变量的 Cookie 文件 3. 常见系统路径中的 Cookie 文件(`/tmp/tor_data`, `/var/lib/tor`, `~/.tor`, `/run/tor`) 4. 空字符串 / null 认证(完全没有密码的 Tor) 使用 SICRY™ 推荐的 torrc(cookie 认证)可**开箱即用**。请参阅 [Tor 设置](#tor-setup)。 ### `fetch(url) → dict` 通过 Tor 获取任何 URL —— 适用于 clearnet 和 `.onion` 隐藏服务。 ``` r = sicry.fetch("http://somemarket.onion/listings") # { # "url": "http://somemarket.onion/listings", # "is_onion": True, # "status": 200, # "title": "Market Listings", # "text": "Plain text, HTML stripped, up to 8000 chars", # "links": [{"text": "Link label", "href": "http://..."}, ...], # up to 80 links # "error": None # } ``` - 没有 `http://` / `https://` 的 URL 会自动添加 `http://` 前缀。 - `text` 经过 HTML 去除、空白折叠处理,并截断至 `MAX_CONTENT_CHARS`(默认 8000)。 - 始终返回字典 —— 永不抛出异常。 ### `search(query, engines=None, max_results=20, max_workers=8) → list[dict]` 同时搜索 18 个暗网搜索引擎。 ``` # 并行使用所有 18 个引擎 results = sicry.search("leaked database credentials") # [{"title": "...", "url": "http://...onion/...", "engine": "Ahmia"}, ...] # 仅指定引擎 results = sicry.search("ransomware", engines=["Ahmia", "Tor66", "Ahmia-clearnet"]) # 更多结果 results = sicry.search("bitcoin mixer", max_results=50) ``` - 结果在所有引擎之间按 URL 去重。 - `engines` 不区分大小写。未知的引擎名称将被静默跳过。 - 始终返回列表 —— 永不抛出异常。 ### `scrape_all(urls, max_workers=5) → dict` 并发批量抓取多个页面,并返回准备好供 LLM 使用的 `{url: content}`。 ``` pages = sicry.scrape_all(search_results[:10]) # { # "http://site1.onion/page": "Page Title - full page text...(truncated)", # "http://site2.onion/page": "Page Title - full page text", # ... # } combined = "\n\n".join(pages.values()) ``` - 输入是 `search()` 的原始输出 —— `{"title", "url"}` 字典列表。 - 内容限制为每页 2000 个字符,并带有 `...(truncated)` 标记。 - 使用 Robin 的模式:`"title - text"` 格式为 LLM 提供上下文。 - 失败的页面将被静默丢弃(仅返回可访问的页面)。 ### `refine_query(query, provider=None) → str` LLM 将自然语言查询细化为 ≤5 个聚焦的词汇,用于暗网搜索引擎。 ``` q = sicry.refine_query("I want to find ransomware groups that targeted hospitals in 2026") # → "hospital ransomware 2026 leak" q = sicry.refine_query("has acme.com appeared in any data breaches") # → "acme.com breach credentials" ``` - 如果未设置 LLM 密钥,则回退到原始查询。**永不抛出异常**。 - 这是一个 Robin 模式 —— 暗网索引对短关键词的响应远优于自然语言。 - 在 `search()` 之前使用可显著提高结果质量。 ### `filter_results(query, results, provider=None) → list[dict]` LLM 过滤搜索结果列表,仅保留前 20 个最相关的结果。 ``` best = sicry.filter_results("hospital ransomware 2026", raw_results) # 返回最多 20 个结果,由 LLM 根据相关性筛选 ``` - 如果未设置 LLM 密钥,则回退到 `results[:20]`。**永不抛出异常**。 - 如果 LLM 对大型负载进行限流,会自动使用截断的标题重试。 - 在 `search()` 之后使用,以在抓取前减少噪音。 ### `ask(content, query="", mode="threat_intel", custom_instructions="", provider=None) → str` 使用 LLM 分析暗网内容并返回结构化的 OSINT 报告。 ``` report = sicry.ask( content="\n\n".join(pages.values()), query="hospital ransomware groups", mode="ransomware", ) print(report) # Structured report: indicators, TTPs, threat actor profile, next steps ``` **模式:** | 模式 | 别名 | 侧重点 | |---|---|---| | `threat_intel` | *(默认)* | 通用 OSINT —— 工件、洞察、后续步骤 | | `ransomware` | `ransomware_malware` | 恶意软件/C2/MITRE TTPs、受害组织、检测 | | `personal_identity` | | PII/泄露暴露、严重程度、保护措施 | | `corporate` | `corporate_espionage` | 泄露的凭据/代码/文档、IR 步骤 | ``` # 为任何模式添加自定义重点 report = sicry.ask( content, mode="threat_intel", custom_instructions="Focus on cryptocurrency wallets and mixer services", ) ``` - 如果未设置 LLM 密钥,则返回 `[SICRY™: ...]` 错误字符串 —— **永不抛出异常**。 - 内容在发送给 LLM 之前会被截断至 `MAX_CONTENT_CHARS`(默认 8000)。 ### `check_search_engines(max_workers=8) → list[dict]` 通过 Tor ping 所有 18 个引擎,并返回每个引擎的状态和延迟。 ``` results = sicry.check_search_engines() # [ # {"name": "Ahmia", "status": "up", "latency_ms": 1240, "error": None}, # {"name": "Kaizer", "status": "down", "latency_ms": None, "error": "timeout"}, # ... # ] live = [r for r in results if r["status"] == "up"] print(f"{len(live)}/18 engines alive") fastest = min(live, key=lambda x: x["latency_ms"]) print(f"Fastest: {fastest['name']} ({fastest['latency_ms']}ms)") ``` - 结果保持原始引擎顺序。 - 在 `search()` 之前使用,以避免在失效引擎上浪费时间。 ## 工具模式 SICRY™ 以每个主要框架的原生格式公开所有 6 个工具。三种格式始终保持同步。 ``` import sicry sicry.TOOLS # Anthropic / Claude format (input_schema) sicry.TOOLS_OPENAI # OpenAI function-calling format (type: "function") sicry.TOOLS_GEMINI # Google Gemini function declarations ``` 打印其中任何一个: ``` python sicry.py tools # Anthropic (default) python sicry.py tools --format openai python sicry.py tools --format gemini ``` 公开的工具: | 工具名称 | 必需参数 | 可选参数 | |---|---|---| | `sicry_check_tor` | *(无)* | | | `sicry_renew_identity` | *(无)* | | | `sicry_fetch` | `url` | | | `sicry_search` | `query` | `max_results` (int), `engines` (list) | | `sicry_ask` | `content` | `query`, `mode`, `custom_instructions` | | `sicry_check_engines` | *(无)* | `max_workers` (int) | ## 框架集成 ### dispatcher 所有框架共享一个 dispatcher —— 使用工具名称和输入字典调用它: ``` result = sicry.dispatch(tool_name, tool_input) # 返回: dict | list | str (与工具文档中记录的返回类型一致) # 抛出: ValueError if tool_name is unknown ``` ### Anthropic / Claude ``` import anthropic, sicry, json client = anthropic.Anthropic() messages = [{"role": "user", "content": "Search dark web for recent credential leaks from banks"}] while True: resp = client.messages.create( model="claude-opus-4-6", max_tokens=4096, system="You are a dark-web OSINT analyst. Always verify Tor before searching.", tools=sicry.TOOLS, # <- Anthropic format messages=messages, ) if resp.stop_reason != "tool_use": print(next(b.text for b in resp.content if hasattr(b, "text"))) break tool_results = [] for block in resp.content: if block.type == "tool_use": result = sicry.dispatch(block.name, block.input) tool_results.append({ "type": "tool_result", "tool_use_id": block.id, "content": json.dumps(result, default=str), }) messages.append({"role": "assistant", "content": resp.content}) messages.append({"role": "user", "content": tool_results}) ``` ### OpenAI / GPT ``` from openai import OpenAI import sicry, json client = OpenAI() messages = [ {"role": "system", "content": "You are a dark-web OSINT analyst."}, {"role": "user", "content": "Has acme.com appeared in any dark web leaks?"}, ] while True: resp = client.chat.completions.create( model="gpt-4o", tools=sicry.TOOLS_OPENAI, # <- OpenAI format messages=messages, ) msg = resp.choices[0].message messages.append(msg) if not msg.tool_calls: print(msg.content) break for call in msg.tool_calls: result = sicry.dispatch( call.function.name, json.loads(call.function.arguments), ) messages.append({ "role": "tool", "tool_call_id": call.id, "content": json.dumps(result, default=str), }) ``` ### Google Gemini ``` import google.generativeai as genai import sicry, json genai.configure(api_key="YOUR_GEMINI_API_KEY") model = genai.GenerativeModel( "gemini-2.5-flash", tools=[{"function_declarations": sicry.TOOLS_GEMINI}], # <- Gemini format system_instruction="You are a dark-web OSINT analyst.", ) chat = model.start_chat() resp = chat.send_message("Find mentions of acme.com on dark web forums") while True: fn_calls = [p.function_call for p in resp.parts if hasattr(p, "function_call") and p.function_call.name] if not fn_calls: for part in resp.parts: if hasattr(part, "text"): print(part.text) break tool_responses = [] for fn_call in fn_calls: result = sicry.dispatch(fn_call.name, dict(fn_call.args)) tool_responses.append( genai.protos.Part( function_response=genai.protos.FunctionResponse( name=fn_call.name, response={"result": json.dumps(result, default=str)}, ) ) ) resp = chat.send_message(tool_responses) ``` ### LangChain ``` from langchain.tools import StructuredTool from langchain.agents import initialize_agent, AgentType from langchain_openai import ChatOpenAI import sicry tools = [ StructuredTool.from_function(name="sicry_check_tor", func=sicry.check_tor, description="Verify Tor is active. Call before any dark web operation."), StructuredTool.from_function(name="sicry_renew_identity", func=sicry.renew_identity, description="Rotate Tor circuit — new exit node and identity."), StructuredTool.from_function(name="sicry_fetch", func=sicry.fetch, description="Fetch any URL or .onion hidden service via Tor."), StructuredTool.from_function(name="sicry_search", func=lambda query, max_results=20: sicry.search(query, max_results=max_results), description="Search 18 dark web engines. Returns title/url/engine list."), StructuredTool.from_function(name="sicry_ask", func=sicry.ask, description="Analyse dark web content. mode: threat_intel|ransomware|personal_identity|corporate"), StructuredTool.from_function(name="sicry_check_engines", func=sicry.check_search_engines, description="Ping all 18 search engines. Returns status + latency per engine."), ] agent = initialize_agent( tools, ChatOpenAI(model="gpt-4o"), agent=AgentType.OPENAI_FUNCTIONS, verbose=True, ) agent.run("Search the dark web for ransomware activity targeting the healthcare sector") ``` ### CrewAI ``` from crewai import Agent, Task, Crew from langchain.tools import StructuredTool import sicry sicry_tools = [ StructuredTool.from_function(name="sicry_check_tor", func=sicry.check_tor, description="Verify Tor is active."), StructuredTool.from_function(name="sicry_search", func=lambda query: sicry.search(query, max_results=20), description="Search 18 dark web engines."), StructuredTool.from_function(name="sicry_fetch", func=sicry.fetch, description="Fetch any .onion URL via Tor."), StructuredTool.from_function(name="sicry_ask", func=sicry.ask, description="LLM OSINT analysis. mode: threat_intel|ransomware|personal_identity|corporate"), StructuredTool.from_function(name="sicry_check_engines", func=sicry.check_search_engines, description="Ping all 18 search engines. Returns status + latency."), ] analyst = Agent( role="Dark Web OSINT Analyst", goal="Investigate dark web threats and produce structured intelligence reports", backstory="Expert in dark web monitoring and threat intelligence", tools=sicry_tools, verbose=True, ) task = Task( description="Search for ransomware groups targeting hospitals. Fetch top results and produce an intelligence report.", expected_output="Structured OSINT report with threat actors, TTPs, indicators, and next steps.", agent=analyst, ) Crew(agents=[analyst], tasks=[task]).kickoff() ``` ### MCP (Claude Desktop / Cursor / Zed) 启动服务器: ``` python sicry.py serve ``` 添加到 `~/.config/claude/claude_desktop_config.json`: ``` { "mcpServers": { "sicry": { "command": "python", "args": ["/absolute/path/to/sicry.py", "serve"] } } } ``` Cursor (`settings.json`): ``` "mcp.servers": { "sicry": { "command": "python /absolute/path/to/sicry.py serve" } } ``` 这 6 个 SICRY™ 工具通过 FastMCP 自动注册。需要:`pip install mcp` ### OpenClaw ``` mkdir -p ~/.openclaw/workspace/skills/sicry cp sicry.py openclaw_skill/SKILL.md ~/.openclaw/workspace/skills/sicry/ ``` ## CLI 参考 ``` python sicry.py [options] ``` | 命令 | 选项 | 描述 | |---|---|---| | `check` | | 验证 Tor 是否正在运行,显示出口 IP | | `renew` | | 轮换 Tor 电路 | | `search ` | `--max N` (默认 10), `--engine NAME` (可重复) | 搜索暗网 | | `fetch ` | | 通过 Tor 获取 URL,打印文本 | | `tools` | `--format anthropic\|openai\|gemini` | 以 JSON 打印工具模式 | | `serve` | | 启动 MCP 服务器 | **示例:** ``` python sicry.py check python sicry.py renew python sicry.py search "ransomware healthcare" --max 15 python sicry.py search "bitcoin mixer" --engine Ahmia --engine Tor66 python sicry.py fetch http://juhanurmihxlp77nkq76byazcldy2hlmovfu2epvl5ankdibsot4csyd.onion python sicry.py tools --format openai | python -m json.tool python sicry.py serve ``` ## 完整 OSINT 流水线 这是推荐的工作流程。每一步都应用了 Robin 模式,该模式对结果质量有显著的提升作用: ``` import sicry # 步骤 1:验证 Tor status = sicry.check_tor() if not status["tor_active"]: raise RuntimeError(f"Tor not active: {status['error']}") print(f"Tor active. Exit IP: {status['exit_ip']}") # 步骤 2:健康检查引擎(跳过已失效的) engine_status = sicry.check_search_engines() live = [e for e in engine_status if e["status"] == "up"] live_names = [e["name"] for e in live] print(f"{len(live)}/18 engines alive: {', '.join(live_names[:5])}...") # 步骤 3:优化查询(Robin 质量模式) raw_query = "ransomware groups targeting hospital systems 2026" query = sicry.refine_query(raw_query) print(f"Refined: '{raw_query}' -> '{query}'") # 步骤 4:搜索(仅并行查询存活的引擎) raw_results = sicry.search( query, engines=live_names, # skip engines we know are down max_results=50, ) print(f"{len(raw_results)} raw results") # 步骤 5:筛选出最佳的 20 个(Robin 质量模式) best = sicry.filter_results(query, raw_results) print(f"Filtered to {len(best)} most relevant") # 步骤 6:并发批量抓取 pages = sicry.scrape_all(best[:10], max_workers=5) print(f"Scraped {len(pages)} pages") # 步骤 7:OSINT 分析 combined = "\n\n".join(f"[{url}]\n{text}" for url, text in pages.items()) report = sicry.ask( combined, query=query, mode="ransomware", custom_instructions="Focus on victim organisations and ransom demands.", ) print(report) # 步骤 8:完成后轮换身份 sicry.renew_identity() ``` ## 分析模式 所有四种模式都会生成结构化的分节报告。传入原始 `.onion` 文本或 `scrape_all()` 输出。 ### `threat_intel` (默认) 通用暗网 OSINT。最适合初步调查。 输出部分:输入查询 · 来源链接 · 调查工件 · 关键洞察 · 后续步骤 ``` report = sicry.ask(content, query="acme.com breach", mode="threat_intel") ``` ### `ransomware` 别名:`ransomware_malware` 恶意软件情报。提取 C2 域名、文件哈希、MITRE ATT&CK TTPs、受害行业。 输出部分:输入查询 · 来源链接 · 恶意软件/勒索软件指标 · 威胁行为者画像 · 关键洞察 · 后续步骤 ``` report = sicry.ask(content, query="LockBit hospital", mode="ransomware") ``` ### `personal_identity` PII 泄露分析。揭示 SSN、电子邮件、护照数据、泄露来源、风险严重程度。 输出部分:输入查询 · 来源链接 · 泄露的 PII 工件 · 泄露/市场来源 · 泄露风险评估 · 关键洞察 · 后续步骤 ``` report = sicry.ask(content, query="john.doe@email.com", mode="personal_identity") ``` ### `corporate` 别名:`corporate_espionage` 企业威胁情报。检测泄露的凭据、源代码、内部文档。 输出部分:输入查询 · 来源链接 · 泄露的企业工件 · 威胁行为者/经纪人活动 · 业务影响评估 · 关键洞察 · 后续步骤 ``` report = sicry.ask(content, query="acme.com corporate leak", mode="corporate") ``` ## 18 个搜索引擎 Robin 的完整目录加上两个验证过的额外引擎。全部由 `search()` 同时查询。 | 引擎 | 类型 | 备注 | |---|---|---| | **Ahmia** | `.onion` 索引 | 最可靠,最大的索引 | | **OnionLand** | `.onion` 索引 | | | **Torgle** | `.onion` 索引 | | | **Amnesia** | `.onion 索引 | | | **Kaizer** | `.onion` 索引 | | | **Anima** | `.onion` 索引 | | | **Tornado** | `.onion` 索引 | | | **TorNet** | `.onion` 索引 | | | **Torland** | `.onion` 索引 | | | **FindTor** | `.onion` 索引 | | | **Excavator** | `.onion` 索引 | | | **Onionway** | `.onion` 索引 | | | **Tor66** | `.onion` 索引 | 良好的论坛覆盖率 | | **OSS** | `.onion` 索引 | | | **Torgol** | `.onion` 索引 | | | **TheDeepSearches** | `.onion` 索引 | | | **DuckDuckGo-Tor** | `.onion` (DDG) | PGP 验证地址 | | **Ahmia-clearnet** | clearnet HTTPS | Ahmia 的 clearnet 镜像 —— 始终可达 | 在大量运行之前使用 `check_search_engines()` 查看哪些引擎存活。 使用 `engines=["Ahmia", "Ahmia-clearnet"]` 获得快速可靠的结果,或者省略 `engines` 以获得最大覆盖率。 ## 环境变量 将 `.env.example` 复制到 `.env`。所有变量都是可选的 —— 仅配置您需要的内容。 | 变量 | 默认值 | 描述 | |---|---|---| | `TOR_SOCKS_HOST` | `127.0.0.1` | Tor SOCKS5 代理主机 | | `TOR_SOCKS_PORT` | `9050` | Tor SOCKS5 代理端口 | | `TOR_CONTROL_HOST` | `127.0.0.1` | Tor 控制端口主机 | | `TOR_CONTROL_PORT` | `9051` | Tor 控制端口 | | `TOR_CONTROL_PASSWORD` | *(未设置)* | HashedControlPassword 的密码 | | `TOR_DATA_DIR` | *(未设置)* | Tor DataDirectory 路径 —— 用于查找 `renew_identity` 的 cookie 文件 | | `TOR_TIMEOUT` | `45` | 单次请求超时(秒) | | `LLM_PROVIDER` | *(未设置)* | `openai` / `anthropic` / `gemini` / `ollama` / `llamacpp` | | `OPENAI_API_KEY` | *(未设置)* | OpenAI API key | | `OPENAI_MODEL` | `gpt-4o` | OpenAI 模型 | | `ANTHROPIC_API_KEY` | *(未设置)* | Anthropic API key | | `ANTHROPIC_MODEL` | `claude-opus-4-6` | Anthropic 模型 | | `GEMINI_API_KEY` | *(未设置)* | Google Gemini API key | | `GEMINI_MODEL` | `gemini-2.5-flash` | Gemini 模型 | | `OLLAMA_BASE_URL` | `http://127.0.0.1:11434` | Ollama API base URL | | `OLLAMA_MODEL` | `llama3.2` | Ollama 模型名称 | | `LLAMACPP_BASE_URL` | `http://127.0.0.1:8080` | llama.cpp 服务器 base URL | | `SICRY_MAX_CHARS` | `8000` | 传递给 LLM 的最大内容字符数 | **`TOR_DATA_DIR` 是最重要的 Tor 变量。** 将其设置为 Tor 的 `DataDirectory` 路径,以便 `renew_identity()` 能够找到用于认证的 cookie 文件。 ## Tor 设置 ### 默认系统 Tor 如果您运行了 `apt install tor && tor &`,搜索、获取和 check_tor 将立即工作。控制端口默认可能未启用。 检查控制端口是否打开: ``` ss -tlnp | grep 9051 ``` 如果没有显示,请启用它: ``` echo "ControlPort 9051" >> /etc/tor/torrc echo "CookieAuthentication 1" >> /etc/tor/torrc systemctl restart tor ``` ### SICRY™ 推荐的 torrc 用于开发 —— 一切都在 `/tmp` 中,无需更改系统: ``` SocksPort 9050 ControlPort 9051 CookieAuthentication 1 DataDirectory /tmp/tor_data ``` ``` tor -f /tmp/sicry_tor.conf & ``` 然后在 `.env` 中: ``` TOR_DATA_DIR=/tmp/tor_data ``` ### 使用密码代替 cookie ``` # 生成哈希密码 tor --hash-password "mypassword" # -> 16:...hash... # 添加到 torrc HashedControlPassword 16:...hash... # 在 .env 中 TOR_CONTROL_PASSWORD=mypassword ``` ### `renew_identity()` 认证工作原理 SICRY™ 按顺序尝试 4 种认证策略,直到有一种成功: 1. **`TOR_CONTROL_PASSWORD`** —— 使用环境变量作为字符串密码 2. **来自 `TOR_DATA_DIR` 的 Cookie 文件** —— 将 `$TOR_DATA_DIR/control_auth_cookie` 作为原始字节读取 3. **来自常见系统路径的 Cookie** —— 自动发现 `/tmp/tor_data`, `/var/lib/tor`, `~/.tor`, `/run/tor` 4. **Null/空认证** —— 用于完全没有设置控制密码的 Tor 如果全部四种都失败,则返回 `{"success": False, "error": "..."}` 及其有用的消息。**永不抛出异常。** ## 故障排除 **`tor_active: False`** ``` # Tor 是否正在运行? pgrep tor || tor & # SOCKS 端口是否开放? ss -tlnp | grep 9050 ``` **`renew_identity()` 返回 `success: False`** ``` # 控制端口是否开放? ss -tlnp | grep 9051 # cookie 文件是否存在? ls /tmp/tor_data/control_auth_cookie # custom torrc ls /var/lib/tor/control_auth_cookie # system Tor # 在 .env 中设置 TOR_DATA_DIR=/path/to/DataDirectory ``` **`.onion` 获取返回 `status: 0`** 隐藏服务已关闭或 Tor 速度慢。尝试 `search()` 中的另一个 URL,或先调用 `check_search_engines()` 确认 Tor 可达。 **搜索返回 0 个结果** 暗网索引经常宕机。运行 `check_search_engines()` 查找活跃的引擎,然后显式传递它们:`search(query, engines=["Ahmia", "Ahmia-clearnet"])`。 **`[SICRY™: OPENAI_API_KEY not set...]`** 设置 `LLM_PROVIDER=ollama` 以使用无密钥的本地推理,或将相关密钥添加到 `.env`。`search()`, `fetch()`, `check_tor()`, `renew_identity()`, `scrape_all()`, 和 `check_search_engines()` 都可以在没有任何 LLM 密钥的情况下工作。 **搜索缓慢** Tor 具有可变的延迟。使用 `check_search_engines()` 找到最快的活跃引擎。`engines=["Ahmia", "Ahmia-clearnet"]` 是最快且可靠的配置。 **日志噪音 / stem DEBUG 输出** SICRY™ 在导入时完全抑制 urllib3 和所有 stem 子记录器(`stem`, `stem.control`, `stem.response`, `stem.socket`, `stem.connection`, `stem.util`),将其设置为 CRITICAL 级别,使用 NullHandler 和 `propagate=False`。如果您仍然看到调试输出,请确保在配置任何根日志处理程序之前导入 `sicry`。 ## 致谢 - 搜索引擎列表和 OSINT 提示词来自 [@apurvsinghgautam](https://github.com/apurvsinghgautam) 的 [Robin](https://github.com/apurvsinghgautam/robin) —— MIT 许可证 - 额外验证过的 `.onion` 地址来自 [dark.fail](https://dark.fail) (PGP 验证) - Tor: [torproject.org](https://www.torproject.org/) ## 许可证 MIT License — Copyright (c) 2026 JacobJandon 完整文本见 [LICENSE](LICENSE)。 请负责任且合法地使用。
标签:AI风险缓解, Claude, CVE检测, DLL 劫持, ESC4, Gemini, LLM集成, MCP服务器, Onion路由, OpenAI, OSINT, Petitpotam, Robin OSINT, SOCKS5, Splunk, Tor网络, Web爬虫, 内存规避, 匿名代理, 单文件组件, 大语言模型, 威胁情报, 开发者工具, 搜索聚合器, 暗网访问, 网络安全, 网络隐私, 逆向工具, 隐私保护