July 28

Создание собственного портала мониторинга даркнета за 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 выполнял две задачи:

  1. Прокси: позволял нашему Python-скрипту посещать сайты даркнета (SOCKS5h).
  2. Хостинг: позволял публиковать отчёт как веб-сайт (скрытый сервис).

Установка Tor

sudo apt install tor nginx -y

Настройка Tor

Нам нужно отредактировать файл torrc, чтобы включить скрытый сервис.

sudo vi /etc/tor/torrc

Добавьте/раскомментируйте следующие строки:

Включите SOCKS-прокси для нашего скрипта сканирования.

SocksPort 9050

Настройка скрытой службы (Блог/Отчет)

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. Таким образом сканер превращается в живой блог. Вы можете использовать его и модифицировать под свои задачи.

Создайте файл scanner.py:

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, где будет еще больше полезной информации.