dublen5269/Sicry
GitHub: dublen5269/Sicry
一个让 AI 代理能够通过统一接口访问 Tor 网络,并结合 18 个内置搜索引擎进行自动化 OSINT 情报收集的 Python 工具库。
Stars: 0 | Forks: 0
# SICRY™ — AI 代理的 Tor/Onion 网络访问层
[](https://github.com/JacobJandon/Sicry/blob/main/LICENSE)
[](https://github.com/JacobJandon/Sicry/actions/workflows/ci.yml)
**作者 JacobJandon** · [github.com/JacobJandon/Sicry](https://github.com/JacobJandon/Sicry)
只需一个 Python 文件。将其放入任何项目,你的 AI 代理即可获得对 Tor/.onion 暗网的完整访问权限 —— 使用与访问普通互联网相同的简洁工具接口,现在只需用于隐藏服务。
Robin 的完整搜索引擎目录(18 个引擎)和 OSINT pipeline 已直接内置。无需安装 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. [Tool schemas (Anthropic / OpenAI / Gemini)](#tool-schemas)
6. [框架集成](#framework-integration)
7. [CLI 参考](#cli-reference)
8. [完整 OSINT pipeline](#the-full-osint-pipeline)
9. [分析模式](#analysis-modes)
10. [18 个搜索引擎](#18-search-engines)
11. [环境变量](#environment-variables)
12. [Tor 设置](#tor-setup)
13. [架构](#architecture)
14. [故障排除](#troubleshooting)
15. [致谢](#credits)
## SICRY™ 的功能
SICRY™ 为 AI 代理提供恰好 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
# 打印适用于您的框架的 Tool 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. 空字符串 / 空认证(完全没有密码的 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": "页面标题 - 完整页面文本...(已截断)",
# "http://site2.onion/page": "页面标题 - 完整页面文本",
# ...
# }
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 key,则回退到原始查询。**永不引发异常**。
- 这是一个 Robin 模式 —— 暗网索引对短关键词的响应远优于自然语言。
- 在 `search()` 之前使用可显著改善结果。
### `filter_results(query, results, provider=None) → list[dict]`
通过 LLM 过滤搜索结果列表,仅保留前 20 个最相关的结果。
```
best = sicry.filter_results("hospital ransomware 2026", raw_results)
# 返回最多 20 个结果,由 LLM 根据相关性筛选
```
- 如果未设置 LLM key,则回退到 `results[:20]`。**永不引发异常**。
- 如果 LLM 对大型 payload 进行限流,会自动使用截断的标题重试。
- 在 `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 key,则返回 `[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()` 之前使用,以避免在失效引擎上浪费时间。
## Tool schemas
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 (与工具文档中的返回类型匹配)
# 抛出: 如果 tool_name 未知则抛出 ValueError
```
### 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 打印工具 schema |
| `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 pipeline
这是推荐的工作流。每一步都应用了 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** | `.ion` 索引 | |
| **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": "..."}` 及有用的消息。**永不引发异常。**
## 架构
各个组件如何协同工作 —— 从 AI 代理调用工具到获得 `.onion` 响应。
### 层级图
```
┌─────────────────────────────────────────────────────────────────────┐
│ AI Agent / Host │
│ Claude · GPT-4o · Gemini · Ollama · LangChain · CrewAI · MCP │
│ calls tool → reads JSON result │
└─────────────────────┬───────────────────────────────────────────────┘
│ tool_name + args (dict)
▼
┌─────────────────────────────────────────────────────────────────────┐
│ SICRY™ (sicry.py) │
│ │
│ dispatch() ──→ sicry_check_tor check_tor() │
│ ──→ sicry_renew_identity renew_identity() │
│ ──→ sicry_fetch fetch(url) │
│ ──→ sicry_search search(query, engines, ...) │
│ ──→ sicry_ask ask(content, mode, ...) │
│ ──→ sicry_check_engines check_search_engines() │
│ │
│ Quality helpers (call directly): │
│ refine_query() · filter_results() · scrape_all() │
│ │
│ State: SQLite DB (watch jobs · engine stats · result cache) │
└──────────┬──────────────────────────┬───────────────────────────────┘
│ SOCKS5 │ stem control socket
│ 127.0.0.1:9050 │ 127.0.0.1:9051
▼ ▼
┌──────────────────────┐ ┌──────────────────────┐
│ Tor Daemon (tor) │ │ Tor Control Port │
│ (tor / TorPool) │◄──│ renew_identity() │
└──────────┬───────────┘ └──────────────────────┘
│ onion routing (3 hops)
▼
┌─────────────────────────────────────────────────────────────────────┐
│ Dark Web / Tor Network │
│ │
│ .onion hidden services Clearnet via Tor exit nodes │
│ ┌───────────────────┐ ┌──────────────────────────────┐ │
│ │ 18 Search Engines│ │ Any clearnet HTTPS/HTTP URL │ │
│ │ Ahmia · Tor66 │ │ (exit node proxied) │ │
│ │ DuckDuckGo-Tor │ └──────────────────────────────┘ │
│ │ + 15 more... │ │
│ └───────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
```
### OSINT pipeline 流程
推荐的 7 步 pipeline(`pipeline.py` / 下文完整 OSINT pipeline 部分):
```
User query
│
▼
[1] check_tor() → verify Tor is active (abort if not)
│
▼
[2] check_search_engines() → ping all 18, collect live engine list
│
▼
[3] refine_query() → LLM: natural language → ≤5 search keywords
│
▼
[4] search() → query all live engines in parallel over Tor
│ ┌── Ahmia ──→ results
│ ├── Tor66 ──→ results
│ └── ...16 more (concurrent ThreadPoolExecutor)
│
▼
[5] filter_results() → LLM: pick top 20 most relevant results
│
▼
[6] scrape_all() → concurrent batch-fetch top pages over Tor
│
▼
[7] ask() → LLM OSINT report (threat_intel / ransomware
│ / personal_identity / corporate)
▼
Structured report
```
### TorPool 模式(可选)
当设置 `SICRY_POOL_SIZE=N`(推荐 2–4)时,SICRY™ 会生成 N 个独立的 Tor 进程,并在它们之间轮询请求以实现更高的吞吐量:
```
sicry_search ─→ TorPool
├── tor[0] :9050 ← SOCKS5 proxy 0
├── tor[1] :9052 ← SOCKS5 proxy 1
└── tor[N-1]:... ← SOCKS5 proxy N-1
```
在 `.env` 中设置:
```
SICRY_POOL_SIZE=3 # 2–4 recommended; each uses ~50 MB RAM
```
### 更新策略
`check_update()` 检查 **GitHub Releases API** (`/releases/latest`) —— 只有发布的正式版本才会触发更新通知。普通的 git 标签和预发布版本将被忽略。
## 故障排除
**`tor_active: False`**
```
# Tor 是否正在运行?
pgrep tor || tor &
# SOCKS 端口是否开放?
ss -tlnp | grep 9050
```
**`renew_identity()` 返回 `success: False`**
```
# Control 端口是否开放?
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` 以使用无 key 的本地推理,或将相关 key 添加到 `.env`。`search()`、`fetch()`、`check_tor()`、`renew_identity()`、`scrape_all()` 和 `check_search_engines()` 均可在没有任何 LLM key 的情况下工作。
**搜索缓慢**
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 prompt 来自 [@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工具, Dark Web, ESC4, HTTP/HTTPS抓包, IT运维, LLM工具, .onion站点, OSINT, Socks5代理, Tor网络, 匿名通信, 实时处理, 密码管理, 态势感知, 情报收集, 搜索集成, 暗网访问, 漏洞研究, 网络安全, 网络隐私, 自动化搜查, 逆向工具, 隐私保护