Создание собственного портала мониторинга даркнета за 30 минут
Это перевод оригинальной статьи Building a Self-Hosted Dark Web Monitoring Portal in 30 minutes.
Подписывайтесь на телеграм-канал usr_bin, где я публикую много полезного по Linux, в том числе ссылки на статьи в этом блоге.
В этой статье мы превратим локальную машину с Ubuntu в автоматизированный монитор даркнета. Он будет сканировать список целевых сайтов onion и размещать «страницу статуса», доступную через Tor, при этом не потребуется открывать ни одного порта на вашем домашнем маршрутизаторе.
Очевидно, это лишь первый шаг, с несколькими жестко заданными ONION-ссылками, которые отслеживаются. В следующей статье мы расширим это решение, чтобы получать список onion-ссылок из определённого репозитория и выполнять более автоматизированный мониторинг, с динамическим удалением и дополнительным сбором информации.
Этап 1: Усиление безопасности ОС
Поскольку эта машина находится в вашей локальной сети, нам необходимо обеспечить её защиту. В отличие от VPS, нам не нужно беспокоиться о проверках со стороны провайдера. Уровень защиты зависит от того, где вы размещаете сервер, поскольку в данном случае это локальная виртуальная машина, но она может работать буквально на любом облачном провайдере. Я использую облако OVH для всех своих нужд, связанных с VPS и выделенными серверами.
Сначала основы
Убедитесь, что ваша недавно установленная Ubuntu обновлена до последней версии.
sudo apt update && sudo apt upgrade -y
Далее: Создание пользователя-аналитика
Никогда не запускайте постоянные скрипты от имени root.
sudo adduser osint_lab sudo usermod -aG sudo osint_lab su - osint_lab
Брандмауэр
Прелесть скрытых сервисов Tor в том, что вам не нужно настраивать переадресацию портов. Ваш компьютер инициирует исходящее соединение с сетью Tor. Поэтому, при желании, мы можем заблокировать весь входящий трафик из интернета. Просто убедитесь, что вы учли другие сервисы, размещённые на этой машине.
Мы настроим брандмауэр так, чтобы он разрешал доступ по SSH только из вашей локальной сети (LAN), чтобы вы могли управлять устройством из дома, но запрещал всё остальное. Вы также можете сделать это через такие сервисы, как ZeroTier, чтобы иметь возможность доступа и извне дома. Уже делал об этом видео, делюсь им здесь, хотя оно, конечно, нуждается в обновлении :).
Если у вас ещё не установлен ufw
sudo apt install ufw -y
Запретите весь входящий трафик по умолчанию
sudo ufw default deny incoming
Разрешите исходящий трафик (чтобы Tor мог взаимодействовать с сетью)
sudo ufw default allow outgoing
Разрешите SSH только из вашей локальной сети (замените 192.168.50.0/24 на вашу подсеть).
sudo ufw allow from 192.168.50.0/24 to any port 22
sudo ufw enable
Проверка: Попробуйте подключиться к вашему серверу по SSH с вашего ноутбука в той же сети, которую вы разрешили. Должно сработать. Попробуйте подключиться извне (если есть возможность) — соединение должно быть отклонено.
Скрытая сервисная инфраструктура
Нам нужно, чтобы Tor выполнял две задачи:
- Прокси: позволял нашему Python-скрипту посещать сайты даркнета (SOCKS5h).
- Хостинг: позволял публиковать отчёт как веб-сайт (скрытый сервис).
Установка Tor
sudo apt install tor nginx -y
Настройка Tor
Нам нужно отредактировать файл torrc, чтобы включить скрытый сервис.
sudo vi /etc/tor/torrc
Добавьте/раскомментируйте следующие строки:
Включите SOCKS-прокси для нашего скрипта сканирования.
Настройка скрытой службы (Блог/Отчет)
HiddenServiceDir /var/lib/tor/onion_monitor/
HiddenServicePort 80 127.0.0.1:80
Примените изменения
Перезапустите Tor, чтобы сгенерировать ключи.
sudo systemctl restart tor
Узнайте свой адрес
Узнайте, какой у вас новый URL-адрес в даркнете:
sudo cat /var/lib/tor/onion_monitor/hostname
Сохраните этот адрес (например, v2xyz…onion). Именно по нему будет доступен ваш отчёт.
Этап 3: Среда Python
Мы будем использовать виртуальное окружение, чтобы изолировать зависимости.
sudo apt install python3-venv python3-pip -y mkdir ~/dark-monitor cd ~/dark-monitor python3 -m venv venv source venv/bin/activate # Install libraries # 'requests' for fetching pages # 'pysocks' for routing through Tor # 'stem' for controlling the Tor process pip install requests pysocks stem
Скрипт сканера и публикации
Это короткий скрипт, который сканирует цели и генерирует статический HTML-файл, который может обслуживаться Nginx. Таким образом сканер превращается в живой блог. Вы можете использовать его и модифицировать под свои задачи.
vi scanner.py
import requests
import socks
import socket
import datetime
import urllib3
import re
import time
# Suppress SSL warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# --- CONFIGURATION ---
OUTPUT_HTML = "/var/www/html/index.html"
# TARGET LIST
TARGETS =
# Configure Tor Proxy (Remote DNS Resolution)
PROXIES = {
'http': 'socks5h://127.0.0.1:9050',
'https': 'socks5h://127.0.0.1:9050'
}
HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; rv:109.0) Gecko/20100101 Firefox/115.0'
}
def get_page_title(html_content):
"""Simple regex to extract the <title> tag"""
try:
match = re.search(r'<title>(.*?)</title>', html_content, re.IGNORECASE | re.DOTALL)
if match:
return match.group(1).strip()[:40] # Truncate to 40 chars
except:
pass
return "Unknown Title"
def check_site(url):
try:
start_time = time.time()
# Timeout 60s
resp = requests.get(url, proxies=PROXIES, headers=HEADERS, timeout=60, verify=False)
latency = round(time.time() - start_time, 2)
title = get_page_title(resp.text)
if 200 <= resp.status_code < 300:
return "UP", "green", f"{latency}s", title
elif resp.status_code == 403:
return "UP (Blocked)", "orange", f"{latency}s", "403 Forbidden"
else:
return "ISSUES", "orange", f"{latency}s", f"Status {resp.status_code}"
except requests.exceptions.ConnectionError:
return "DOWN", "red", "-", "Connection Failed"
except requests.exceptions.Timeout:
return "DOWN", "red", ">60s", "Timed Out"
except Exception as e:
return "ERROR", "red", "-", str(e)[:30]
def generate_report():
# FIX: Get local time with correct Timezone Name (e.g., PST/CST)
now = datetime.datetime.now().astimezone()
timestamp = now.strftime("%Y-%m-%d %H:%M %Z")
html_content = f"""
<!DOCTYPE html>
<html>
<head>
<title>Dark Web Observatory</title>
<meta http-equiv="refresh" content="300">
<style>
body {{ font-family: 'Courier New', monospace; background: #0d0d0d; color: #e0e0e0; padding: 20px; }}
h1 {{ color: #00ff00; text-transform: uppercase; border-bottom: 2px solid #333; padding-bottom: 10px; }}
table {{ border-collapse: collapse; width: 100%; max-width: 1400px; margin-top: 20px; font-size: 0.9em; }}
th, td {{ border: 1px solid #333; padding: 12px; text-align: left; vertical-align: middle; }}
th {{ background-color: #1a1a1a; color: #fff; text-transform: uppercase; letter-spacing: 1px; }}
tr:nth-child(even) {{ background-color: #111; }}
a {{ color: #888; text-decoration: none; }}
a:hover {{ color: #fff; text-decoration: underline; }}
.green {{ color: #00ff00; font-weight: bold; background-color: #001a00; text-align: center; }}
.orange {{ color: #ffa500; font-weight: bold; background-color: #1a1000; text-align: center; }}
.red {{ color: #ff3333; font-weight: bold; background-color: #1a0000; text-align: center; }}
.small {{ font-size: 0.85em; color: #999; }}
.title-text {{ font-style: italic; color: #aaa; }}
</style>
</head>
<body>
<h1>/var/log/onion_status</h1>
<p>Last Scan: {timestamp}</p>
<table>
<tr>
<th style="width: 15%">Target Name</th>
<th style="width: 35%">Onion Address</th>
<th style="width: 8%">Status</th>
<th style="width: 8%">Latency</th>
<th style="width: 34%">Page Title / Error</th>
</tr>
"""
print(f"[*] Starting scan at {timestamp}")
for target in TARGETS:
print(f" > Scanning {target['name']}...")
status, color, latency, detail = check_site(target['url'])
print(f" Result: {status} ({latency}s)")
html_content += f"""
<tr>
<td>{target['name']}</td>
<td class="small"><a href="{target['url']}">{target['url']}</a></td>
<td class="{color}">{status}</td>
<td style="text-align: center;">{latency}</td>
<td class="title-text">{detail}</td>
</tr>
"""
html_content += """
</table>
<p style="margin-top:50px; font-size: 0.8em; color: #555;">
<i>Generated by Automated Local Sentinel (Ubuntu 25.04)</i>
</p>
</body>
</html>
"""
try:
with open(OUTPUT_HTML, "w") as f:
f.write(html_content)
print(f"[*] Report successfully updated")
except PermissionError:
print("[!] Error: Cannot write to /var/www/html.")
if __name__ == "__main__":
generate_report()Исправление прав доступа
По умолчанию пользователь osint_lab не может записывать данные в /var/www/html. Давайте это исправим, чтобы наш скрипт мог обновлять веб-сайт.
sudo chown -R osint_lab:osint_lab /var/www/html
Автоматизация
crontab -e
0 * * * * /home/osint_lab/dark-monitor/venv/bin/python3 /home/osint_lab/dark-monitor/scanner.py
Доступ к вашей обсерватории
Откройте браузер Tor на своем ноутбуке или телефоне.
Вставьте имя хоста, которое вы сгенерировали на предыдущих шагах.
Вы увидите свою собственную панель управления с автоматическим обновлением.
Я специально добавил несколько неправильных URL, чтобы показать различные статусы, которые вы будете получать. Это будет выглядеть примерно так:
На этом все! Спасибо за внимание! Если статья была интересна, подпишитесь на телеграм-канал usr_bin, где будет еще больше полезной информации.