HOME FORUMS MEMBERS RECENT POSTS LOG IN  
× Авторизация
Имя пользователя:
Пароль:
Нет аккаунта? Регистрация
Баннер 1   Баннер 2

ANTICHAT — форум по информационной безопасности, OSINT и технологиям

ANTICHAT — русскоязычное сообщество по безопасности, OSINT и программированию. Форум ранее работал на доменах antichat.ru, antichat.com и antichat.club, и теперь снова доступен на новом адресе — forum.antichat.xyz.
Форум восстановлен и продолжает развитие: доступны архивные темы, добавляются новые обсуждения и материалы.
⚠️ Старые аккаунты восстановить невозможно — необходимо зарегистрироваться заново.
Вернуться   Форум АНТИЧАТ > БЕЗОПАСНОСТЬ И УЯЗВИМОСТИ > Уязвимости > Веб-уязвимости
   
 
 
Опции темы Поиск в этой теме Опции просмотра

  #1  
Старый 29.04.2026, 22:37
B3Hap_py
Новичок
Регистрация: 22.12.2025
Сообщений: 0
Провел на форуме:
0

Репутация: 0
По умолчанию

1. Введение: proactive phishing monitoring
Забудьте про времена, когда просто ждали, пока клиент пришлет скриншот фейковой формы в саппорт. Если сидите и ждете жалоб – вы уже проиграли. Наша задача – обнаружить фишинговый лендинг еще на этапе "прогрева" или сразу после регистрации сертификата, пока на него не нагнали трафик.



1.1. Масштаб проблемы (РФ 2025)
За 2025 год доля фишинговых атак впервые снизилась с 85,7% до 67,87%. На первый взгляд – позитивная динамика. Но злоумышленники перешли на более сложные и высокодоходные схемы. По данным ЦБ РФ, по итогам 2025 года сумма похищенных средств достигла 29,3 млрд рублей, увеличившись на 6,4%. Представитель МВД на форуме "Антифрод Россия" называл оценку свыше 154 млрд рублей, зампред Сбербанка оценил объём в 275–295 млрд рублей.

По данным системы Минцифры "Антифишинг" в 2025 году было выявлено более 74 тыс. фишинговых интернет-ресурсов. По подсчётам специалистов Центра мониторинга и управления сетью связи общего пользования, количество заблокированных фишинговых ресурсов в 2025 году превысило 100 тыс., что в 3,3 раза больше предыдущего года.

Координационный центр доменов .RU/.РФ опубликовал итоги 2025 года для российских национальных доменных зон. В течение года в .RU было зарегистрировано 1810861 новое доменное имя, число новых зарегистрированных доменных имен .РФ выросло на 207654. В течение года направлено 62168 обращений к регистраторам о прекращении делегирования вредоносных доменов. Доля фишинга в общем объеме составила 67,87% (~42192).

По данным компании F6, за первое полугодие 2025 года злоумышленники создавали около 2299 фишинговых ресурсов и 1238 скам-ресурсов на один бренд: то есть ежедневно злоумышленники запускали в среднем по 13 фишинговых и по 7 мошеннических ресурсов на каждый бренд. Примерно 80% создаваемых мошеннических ресурсов эксплуатируют бренды известных компаний, а лидером по числу атак стал ритейл: на него приходится 50% всех фишинговых и 32% скам-атак (похищение денежных средств).
Среди финансовых брендов мошенники чаще всего имитируют "Сбер" и "ТБанк", а в сегменте E-commerce – "Wildberries", "Авито" и "Юла".
1.2. Manual vs automated approach: почему ручной подход больше не работает
Мы только что посмотрели на цифры. Серьезно, кто-то до сих пор пытается мониторить это вручную?
Пока аналитик открыл браузер, вбил URL, загрузил страницу, CAPTCHA, WAF, собрал информацию, отправил отчет, злоумышленник собрал сотни учёток, снес страницу и ушёл на следующий домен. Фишинг-как-услуга (PhaaS) и автоматизированные наборы инструментов демократизировали киберпреступность до уровня "купил подписку – запустил атаку". Среднее время жизни фишингового сайта – часы, ручное обнаружение и блокировка растягивается на недели.

Ручной анализ не работает даже в теории:
  • Объёмы: в 2025 году в зоне .RU десятки тысяч фишинговых доменов. Даже команда захлебнётся проверять вручную.
  • Скорость реакции злоумышленников: PhaaS позволяет развернуть готовую страницу-клон за 2 минуты, кампании запускают синхронно по 100+ доменам. Мы не можем отвечать со скоростью "открыл браузер – подумал – написал письмо".
  • Человеческий фактор: коэффициент ложных срабатываний растёт пропорционально усталости. Руководители SOC называют усталость аналитиков главной операционной угрозой. Ошибки в копировании IOC, пропущенные детали в whois, забытые вложения в abuse-отчёт – это снижает эффективность.
Автоматизированный пайплайн на Python + Scrapy – не про увольнение TI-специалистов. Это про то, чтобы перестать тратить мозги на рутинную работу.
  • Генерация кандидатов - тысячи вариантов подозрительных доменов через dnstwist, URLCrazy за секунды.
  • Мониторинг Certificate Transparency – crt.sh, Certstream позволяют слушать поток сертификатов 24/7.
  • Обход CAPTCHA и WAF – ротация прокси, User-Agent, retry-механизмы.
  • Скачивание страниц – парсер под тысячу потоков за минуту обработает то, на что человек потратит час.
  • Fuzzy matching текста (косинусное расстояние, Левенштейн) – алгоритм даёт результат за доли секунды с высокой точностью.
  • Сравнение скриншотов – скрипт находит расхождения там, где на глаз "вроде похоже".
  • Извлечение IOC – регулярки без устали вытаскивают домены, IP, email из HTML и JavaScript.
  • Отправка в MISP/TheHive – API-колл за доли секунды, без ручного копирования.
  • Генерация abuse-отчёта – шаблон на Jinja2 подставляется в API регистратора, не забывая приложить скриншот.
2. Typosquatting Detection: охота на близнецов
Typosquatting detection - генерация, обнаружение и проверка доменов-"двойников", которые отличаются от вашего оригинального домена на один-два символа.
2.1. dnstwist: генерация вариаций
dnstwist – швейцарский нож для тайпсквоттинга берёт домен и генерирует сотни вариаций, которые злоумышленник мог бы зарегистрировать.

Основные алгоритмы dnstwist: соседние клавиши, омоглифы (визуально похожие буквы из других алфавитов), добавление/удаление символов, перестановка соседних символов, использование цифр, добавление суффиксов через внешние словари, альтернативные доменные зоны.

Запуск:

Bash:


Код:
dnstwist --registered superbank.ru
>
candidates.txt
Код:
--registered
- заставляет dnstwist сразу делать DNS-проверку – показывает только те домены, которые зарегистрированы и имеют A/AAAA записи.
2.2. URLCrazy: алгоритмы подмены
URLCrazy – делает упор на алгоритмы подмены, характерные именно для фишинга, генерация вариаций на основе звукоподобия и обфускации.

Чего нет в dnstwist, но есть в URLCrazy:
  • Замена букв по звучанию
    Код:
    superbank => superbeink (ai => e)
  • Более гибкое добавление префиксов/суффиксов
  • Поддержка нескольких раскладок клавиатуры: генерация опечаток для QWERTY, AZERTY, QWERTZ и DVORAK
  • База из 8000+ распространённых опечаток
Запуск:

Bash:


Код:
urlcrazy -f json superbank.ru
>
urlcrazy_candidates.json
Большинство команд используют dnstwist как основной, а URLCrazy – как дополнение для специфичных кейсов.
2.3. Фильтрация: DNS resolution check
DNSTwist и URLCrazy сгенерировали тысячи доменов-кандидатов. Из них реально зарегистрировано, скажем, 200. Нам нужны те, у которых открыт 80/443 порт и есть веб-интерфейс. Поэтому после генерации делаем DNS resolution check – проверяем, что домен резолвится и IP отвечает на HTTP-запрос.

Используя библиотеку
Код:
asyncio
для асинхронности,
Код:
aiodns
для DNS‑запросов и
Код:
aiohttp
для HTTP‑проверок, реализуем двухэтапную фильтрацию доменов-кандидатов. На первом этапе для каждого домена параллельно запрашиваются A‑записи (IPv4) и AAAA‑записи (IPv6) через публичные DNS‑серверы (например, 8.8.8.8), чтобы обойти системный DNS. Домены, которые не получили ни одного IP (нерезолвящиеся), отбрасываются. На втором этапе для оставшихся доменов асинхронно проверяется доступность по HTTP/HTTPS с игнорированием ошибок SSL‑сертификатов (
Код:
ssl=False
– необходимо, так как фишинговые сайты часто используют невалидные или самоподписанные сертификаты). Запросы выполняются с таймаутом, успехом считается любой HTTP‑статус в диапазоне 200–499 (сайт отвечает). В итоге получаем для каждого домена информацию о наличии IP, сами IP‑адреса и статус веб‑доступности – всё без блокировок и за счёт асинхронности с минимальными задержками. После DNS-фильтрации остаётся, допустим, 50 доменов, которые реально резолвятся. Это и есть кандидаты для Scrapy.

Важные нюансы:
  • некоторые фишеры используют fast-flux DNS – IP постоянно меняется, но домен резолвится всегда, его всё равно передаем дальше.
  • регистраторы часто паркуют неиспользуемые домены на заглушки с рекламой, такие домены резолвятся, веб-сервер возвращает 200OK с заглушкой. Их фильтруем по контенту (слова "parking", "domain for sale").
3. Certificate Transparency: ловим на взлёте
Certificate Transparency даёт нам реальные, только что родившиеся домены с сертификатами. Фишер регистрирует домен – получает сертификат – сертификат попадает в публичные CT-логи. Засветился ещё до того, как отправил первое письмо.
Ключевая метрика для понимания масштаба: Let's Encrypt, крупнейший центр сертификации, в конце 2025 года выдаёт 10 миллионов сертификатов в день. 450 тысяч сертификатов каждый час проходят через всю экосистему WebPKI.
3.1. crt.sh API: база, которую мы заслужили
crt.sh – поисковик по CT-логам. По сути, огромная база данных, в которой можно найти все сертификаты, выпущенные для домена или по маске.

Запрос:

Bash:


Код:
curl
-s
"https://crt.sh?q=%25.superbank.ru&exclude=expired&output=json"
Код:
excluded=expired
– отсекаем просроченные сертификаты, чтобы не плодить шум.

Получаем:

JSON:


Код:
[
...
{
"issuer_ca_id"
:
213378
,
"issuer_name"
:
"C=US, O=Let's Encrypt, CN=R13"
,
// кто выпустил
"name_value"
:
"p2p.superbank.ru"
,
// домен или список SAN
"id"
:
25413374039
,
"entry_timestamp"
:
"2026-04-06T14:06:10.498"
,
// когда попал в лог
"not_before"
:
"2026-04-06T13:07:39"
,
"not_after"
:
"2026-07-05T13:07:38"
,
// срок действия
"serial_number"
:
"0474ac7b90be68283b6d0d1467724398e405"
,
}
,
...
]
,
Subject Alternative Name (SAN) – поле в SSL/TLS-сертификате, которое позволяет указать несколько доменных имён (или IP-адресов), для которых этот сертификат считается валидным. Может содержать несколько доменов, разделённых символом новой строки (
Код:
\n
) или запятыми. Поэтому когда парсим ответ от crt.sh, обязательно нужно разбивать
Код:
name_value
по
Код:
\n
.

Запрос:

Bash:


Код:
curl
-s
"https://crt.sh?q=%25.superbank.ru&exclude=expired&output=json"
|
jq -r
'.[].name_value'
Ответ:

Код:


Код:
p2p.superbank.ru
*.superbank.ru
superbank.ru
emails.superbank.ru
Важные нюансы:
  1. Rate Limiting: crt.sh ограничивает запросы до 60 запросов в минуту на IP. Если ваш парсер запускается раз в час с одним IP – ок. Если чаще – нужна ротация IP.
  2. crt.sh не даёт real-time: данные поступают в crt.sh с задержкой, поэтому для оперативного мониторинга используем Certstream, а crt.sh оставляем для периодических "прочёсываний" (раз в 6-12 часов) на случай пропусков.
3.2. Certstream: real-time monitoring пока теплый
Certstream – это WebSocket-поток, агрегирующий свежие сертификаты со всех CT-логов в реальном времени. В него попадают все сертификаты, выпускаемые всеми центрами сертификации для всех доменов в мире. Как только какой-то центр сертификации (Let's Encrypt, DigiCert и т.д.) выпускает свежий сертификат, Certstream отправляет уведомление. Идеально для автоматического мониторинга 24/7.

Подключение к потоку Certstream:

Python:


Код:
from
certstream
import
cert_stream_callback
import
json
# Сгенерированные dnstwist'ом варианты в set
MONITORED_DOMAINS
=
{
'superbenk.ru'
,
'superbakn.ru'
,
'superrbank.ru'
,
.
.
.
}
def
callback
(
message
,
context
)
:
# message – словарь, который Certstream присылает по WebSocket
# Выбираем сообщения о новом сертификате
if
message
[
'message_type'
]
==
'certificate_update'
:
cert_data
=
message
.
get
(
'data'
,
{
}
)
san
=
cert_data
.
get
(
'leaf_cert'
,
{
}
)
.
get
(
'extensions'
,
{
}
)
.
get
(
'san'
,
[
]
)
for
dns_name
in
san
:
if
dns_name
.
get
(
'type'
)
==
'DNS'
:
domain
=
dns_name
.
get
(
'value'
)
# Если домен из сертификата есть в списке – это наш кандидат
if
domain
in
MONITORED_DOMAINS
:
print
(
f"Найден фишинговый домен:{domain}"
)
# Отправляем в Scrapy на анализ
cert_stream_callback
(
callback
,
skip_heartbeats
=
True
)
# skip_heartbeats=True – убирает служебные сообщения, которые приходят раз в 30 секунд, чтобы держать соединение открытым
В боевом пайплайне добавляем домен в очередь (
Код:
redis,
Код:
kafka
), откуда Scrapy забирает задачи на скачивание. И так как в message получаем информацию вообще обо всех новых сертификатах, необходимо делать фильтрацию – проверять, содержит список доменов интересующих нас кандидатов или ключевое слово.

Почему Certstream, а не crt.sh в polling-режиме:
  • Real-time – узнаем о новом домене в момент его появления. Certstream выдаёт сертификат через 1-5 секунд после его публикации в CT-лог.
  • Не нужно дёргать API каждую минуту и заморачиваться с rate limits.
  • Certstream отдаёт только новые сертификаты, а crt.sh возвращает всю историю.
Нюансы для реальной эксплуатации:
  • В Certstream один и тот же сертификат может попасть в несколько CT-логов. Поэтому на приёме нужно делать дедупликацию по
    Код:
    domain
    ,
    Код:
    not_before
    или по хешу сертификата.
  • Certstream может отвалиться. В бою оборачивай
    Код:
    cert_stream_callback
    в цикл с
    Код:
    try-except
    и переподключением.
  • Certstream – это публичный сервис, он может лечь или замедлиться. В боевых системах стоит предусмотреть fallback на crt.sh.
3.3. Keyword matching: зерна от плевел
Подключились к Certstream, летят десятки тысяч событий в час. Задача keyword matching – отсеять 99.9% шума и оставить домены, которые связаны с нашим брендом.

Строим фильтр на трёх китах:
  1. Присутствие бренда – домен должен содержать название нашей компании (или его опечатку/мутацию).
  2. Исключение своих доменов – whitelist легитимных доменов, которые не трогаем.
  3. Фишинговые паттерны – слова, характерные для мошеннических страниц (login, verify, secure, account, confirm и т.д.).
Пишем функцию, которая принимает домен и возвращает флаг + скор:

Python:


Код:
BRAND
=
'superbank'
PHISHING_PATTERNS
=
[
'login'
,
'verify'
,
'secure'
,
'account'
,
'auth'
,
'confirm'
]
WHITELIST
=
{
'superbank.ru'
,
'www.superbank.ru'
,
'login.superbank.ru'
}
def
is_relevant
(
domain
:
str
)
-
>
tuple
[
bool
,
int
]
:
domain_lower
=
domain
.
lower
(
)
# 1. Свои домены пропускаем
if
domain_lower
in
WHITELIST
:
return
False
,
0
# 2. Проверяем наличие бренда
if
BRAND
not
in
domain_lower
:
return
False
,
0
score
=
10
# базовый вес за упоминание бренда
# 3. Бонус за структуру официального поддомена (но не в whitelist)
if
domain_lower
.
endswith
(
f'.{BRAND}.ru'
)
or
domain_lower
==
f'{BRAND}.ru'
:
score
+=
5
# 4. Штрафуем фишинговые паттерны
for
pattern
in
PHISHING_PATTERNS
:
if
pattern
in
domain_lower
:
score
+=
15
break
return
True
,
score
При интеграции в Certstream-коллбэк функция callback с фильтрацией выглядит так:

Python:


Код:
def
callback
(
message
,
context
)
:
if
message
[
'message_type'
]
==
'certificate_update'
:
cert_data
=
message
.
get
(
'data'
,
{
}
)
san
=
cert_data
.
get
(
'leaf_cert'
,
{
}
)
.
get
(
'extensions'
,
{
}
)
.
get
(
'san'
,
[
]
)
for
dns_name
in
san
:
if
dns_name
.
get
(
'type'
)
==
'DNS'
:
domain
=
dns_name
.
get
(
'value'
)
# Проверяем релевантен ли домен и его скор
relevant
,
score
=
is_relevant
(
domain
)
if
relevant
:
# Отправляем в очередь Scrapy
send_to_scrapy_queue
(
domain
,
score
)
log
.
info
(
f"Found candidate:{domain}(score={score})"
)
Итог
  • Keyword matching – первый этап фильтрации в потоке сертификатов.
  • Проверяем наличие бренда, исключаем whitelist, штрафуем фишинговые слова.
  • Не пытаемся заменить dnstwist – его задача генерировать мутации, а на этапе keyword matching – проверка точных вхождений. Keyword matching нужен для доменов, которые не попали в MONITORED_DOMAINS (п.3.2.), но всё ещё подозрительны.
4. Scrapy Spider: монстр на службе антифрода
Сгенерировали dnstwist'ом, отфильтровали по DNS, наловили сертификатов через Certstream и прогнали через keyword matching. В очереди лежат сотни URL. Задача: скачать страницы так, чтобы не заблокировали, и подготовить HTML для анализа.
Scrapy – это асинхронный фреймворк, который переваривает тысячи запросов в секунду. В отличие от
Код:
requests
с потоками, Scrapy использует
Код:
Twisted
, за счёт event loop он крутит десятки параллельных соединений в одном потоке и не блокируется на ожидании ответа.
4.1. Настройка проекта
Создаём проект:

Bash:


Код:
startproject phishing_monitor
cd
phishing_monitor
scrapy genspider clone_checker example.com
# команда для создания файла-заготовки для нового парсера
Структура проекта:

Код:


Код:
phishing_monitor/
├── phishing_monitor/
│   ├── spiders/
│   │   └── clone_checker.py     # наш парсер
│   ├── middlewares.py           # кастомные middleware
│   ├── settings.py              # настройки проекта
│   └── items.py                 # модель данных (опционально)
└── scrapy.cfg
Не пишем
Код:
start_requests
статически – будем забирать URL из очереди, например из Redis:

Python:


Код:
# clone_checker.py
import
scrapy
import
redis
class
CloneCheckerSpider
(
scrapy
.
Spider
)
:
name
=
'clone_checker'
def
start_requests
(
self
)
:
r
=
redis
.
Redis
(
host
=
'localhost'
,
port
=
6379
,
db
=
0
)
while
True
:
# костыль для примера, не для прода
# Блокирующая pop – спим, ждём новые URL
url
=
r
.
brpop
(
'phishing:urls'
)
[
1
]
.
decode
(
)
yield
scrapy
.
Request
(
url
,
callback
=
self
.
parse
)
def
parse
(
self
,
response
)
:
# Здесь будет анализ страницы
self
.
logger
.
info
(
f"Processing{response.url}"
)
# Сохраняем HTML для дальнейшего fuzzy matching
yield
{
'url'
:
response
.
url
,
'body'
:
response
.
text
,
'status'
:
response
.
status
}
В боевом окружении используем
Код:
scrapy-redis
: Scrapy слушает Redis-очередь, а Certstream-коллбэк пушит туда URL.

Для запуска команда crawl:

Bash:


Код:
scrapy crawl clone_checker
# JSON Lines (рекомендуется для потоковой записи)
scrapy crawl clone_checker -o output.jl
# JSON
scrapy crawl clone_checker -o output.json
Важные настройки в settings.py:

Python:


Код:
# Для задач антифрода обычно устанавливают `False`
ROBOTSTXT_OBEY
=
False
# Глубина обхода
DEPTH_LIMIT
=
1
# Для задержки между запросами к одному домену
DOWNLOAD_DELAY
=
1
RANDOMIZE_DOWNLOAD_DELAY
=
True
# Автоматическое ограничение параллельных запросов
CONCURRENT_REQUESTS
=
32
CONCURRENT_REQUESTS_PER_DOMAIN
=
8
# Таймауты – чтобы не висеть на мёртвых сайтах
DOWNLOAD_TIMEOUT
=
15
# Retry
RETRY_ENABLED
=
True
RETRY_TIMES
=
2
# Куда складывать результат
FEEDS
=
{
'output/phishing.json'
:
{
'format'
:
'jsonlines'
,
'encoding'
:
'utf8'
,
}
}
4.2. Middleware: proxy rotation, user-agent чтобы не вычислили
Фишинговые сайты часто висят на дешёвом хостинге, но некоторые используют WAF и блокируют ботов. Без ротации прокси и User-Agent IP забанят после 5-10 запросов. Scrapy позволяет написать Downloader Middleware, которая подменяет параметры запроса.

Пример middleware для ротации User-Agent:

Python:


Код:
# middlewares.py
from
fake_useragent
import
UserAgent
class
RandomUserAgentMiddleware
:
def
__init__
(
self
)
:
self
.
ua
=
UserAgent
(
fallback
=
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
)
# fallback на случай недоступности сервера fake-useragent
# метод, который Scrapy вызывает перед отправкой каждого HTTP-запроса
def
process_request
(
self
,
request
,
spider
)
:
request
.
headers
[
'User-Agent'
]
=
self
.
ua
.
random
Подключаем в settings.py:

Python:


Код:
DOWNLOADER_MIDDLEWARES
=
{
# отключаем встроенный UA, чтобы не перезаписывал кастомный
'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware'
:
None
,
# приоритет выполнения для кастомных middleware
'phishing_monitor.middlewares.RandomUserAgentMiddleware'
:
400
,
}
Proxy rotation – позволяет использовать публичные списки или купить пул резидентных прокси. Пример middleware, который берёт прокси из Redis-списка:

Python:


Код:
class
ProxyMiddleware
:
def
__init__
(
self
)
:
# список проксей
self
.
proxies
=
[
'http://user:pass@proxy1:8080'
,
'http://user:pass@proxy2:8080'
,
]
self
.
current
=
0
def
process_request
(
self
,
request
,
spider
)
:
proxy
=
self
.
proxies
[
self
.
current
%
len
(
self
.
proxies
)
]
# если в meta есть ключ 'proxy', Scrapy автоматически отправляет запрос через указанный прокси-сервер
request
.
meta
[
'proxy'
]
=
proxy
# таймаут, чтобы не висеть на мёртвом прокси
request
.
meta
[
'download_timeout'
]
=
15
self
.
current
+=
1
Для реального антифрод-пайплайна его нужно доработать: добавить проверку здоровья прокси, вынос конфигурации, обработку ошибок. В бою используют
Код:
scrapy-rotating-proxies
или аналоги, а этот код – для понимания. Для надёжности лучше использовать библиотеку
Код:
scrapy-rotating-proxies
или крутить прокси через
Код:
scrapy-proxy-middleware
.
4.3. Стратегии обхода CAPTCHA: я не робот
Злоумышленники ставят капчи, чтобы отсеять ботов. Полностью автоматически решать reCAPTCHA сложно и дорого, но есть несколько стратегий:
  1. Игнорирование страниц с капчей скриптами: детектируем, отправляем аналитику на ручную проверку.
  2. Использование сервисов распознавания: для простых капч (текстовых, математических) можно использовать
    Код:
    2Captcha
    ,
    Код:
    ruCaptcha
    . Они стоят копейки, но добавляют задержку. В Scrapy это делается через middleware, которая при получении капчи приостанавливает запрос, отправляет капчу в сервис, получает ответ и повторяет запрос с токеном.
  3. Эмуляция браузера: Scrapy не умеет рендерить JavaScript. Поэтому для сайтов, где капча появляется после выполнения JS, можно использовать
    Код:
    scrapy-selenium
    или
    Код:
    scrapy-playwright
    .
5. Content Analysis: какое совпадение
Есть подозрительный домен, Scrapy скачал HTML, возможно, даже сделан скриншот через Selenium. Это фишинг или нет? Применяем систему оценки, которая комбинирует несколько сигналов: текст, структура страницы, визуальное сходство.



5.1. Text similarity (Levenshtein, cosine)
Текстовое сравнение – первая линия обороны. Выкачиваем из оригинального сайта (эталон) и из подозрительной страницы все видимые тексты, очищаем от HTML-тегов, скриптов, лишних пробелов, и сравниваем.

Расстояние Левенштейна
Левенштейн считает, сколько односимвольных правок (вставка, удаление, замена) нужно сделать, чтобы превратить одну строку в другую. Хорош для коротких строк: заголовков, текста кнопок, форм.

Python:


Код:
from
rapidfuzz
import
distance
# В rapidfuzz реализован алгоритм Левенштейна
title_original
=
"Login to Super-Bank"
title_phish
=
"Login to SyperBank"
lev
=
distance
.
Levenshtein
.
normalized_distance
(
title_original
,
title_phish
)
# Получим нормализованное расстояние Левенштейна: 0.1053
К примеру, порог 0.2 – эмпирически обоснованная отправная точка, но требует калибровки на своих данных. Если полученное значение меньше 0.2 – считаем строки практически одинаковыми. Результат 0.1053 говорит о высокой степени сходства, что добавляет очков в скоринговую модель.

Подводные камни:[LIST][*]Ложноотрицательные срабатывания. Расстояние Левенштейна – мощный инструмент для коротких строк, но оно слепо к омоглифам. Строки "Вход в Супер-Банк" и "Вход в Супер-Bank" дадут расстояние 0.2353 > 0.2. Модель скажет, что заголовки не похожи. А ведь это явный фишинг!
[*]Обязательно применяйте транслитерацию для кириллицы перед сравнением. После транслитерации строки станут идентичными, и расстояние Левенштейна станет 0.
[*]Либо повышайте порог срабатывания, к примеру до 0.3. Тогда 0.2353 0.7 – страницы семантически близки. Снова, никакого мирового стандарта, 0.7 – лишь популярная отправная точка, результат практического опыта.
Ещё можно сравнивать: title, h1, атрибуты action и name, мета-теги. Для длинных страниц – это главный инструмент, для коротких строк – Левенштейн. Вместе они дают надёжную систему детекции клонов.
5.2. Visual: SSIM comparison - сходство не случайно
Текстовый анализ может ошибаться, если фишер полностью переписал текст, но сохранил дизайн. В таких случаях нас спасает сравнение скриншотов.

Structural Similarity Index Measure (SSIM) – метрика, которая оценивает структурное сходство двух изображений. В отличие от прямого попиксельного сравнения, SSIM учитывает яркость, контраст и структуру (границы, формы, расположение объектов). SSIM смотрит на картинку как человек.

Алгоритм:
  1. Делаем скриншот оригинальной страницы (эталон).
  2. Для каждого подозрительного домена через Selenium рендерим страницу, делаем скриншот.
  3. Сравниваем скриншоты через
    Код:
    skimage.metrics.structural_similarity
    .

Python:


Код:
from
skimage
.
metrics
import
structural_similarity
as
ssim
import
cv2

original
=
cv2
.
imread
(
"original.png"
,
cv2
.
IMREAD_GRAYSCALE
)
candidate
=
cv2
.
imread
(
"candidate.png"
,
cv2
.
IMREAD_GRAYSCALE
)
# Приводим к одному размеру
h
=
min
(
original
.
shape
[
0
]
,
candidate
.
shape
[
0
]
)
w
=
min
(
original
.
shape
[
1
]
,
candidate
.
shape
[
1
]
)
original
=
cv2
.
resize
(
original
,
(
w
,
h
)
)
candidate
=
cv2
.
resize
(
candidate
,
(
w
,
h
)
)
score
=
ssim
(
original
,
candidate
)
# score ≈ 0.92 (чем ближе к 1, тем более похожи)
Порог: если SSIM > 0.85 – почти наверняка визуальный клон.

Подводные камни:
  • Динамический контент (баннеры, курс валют) снижает SSIM.
  • Разная ширина вьюпорта, структура страницы может измениться. SSIM чувствителен к структурным изменениям. Фиксируем размер окна браузера.
  • Производительность: рендеринг скриншота – 2–5 секунд. Не применяем ко всем подряд, только к самым подозрительным кандидатам после текстового анализа.
5.3. Scoring model: взвешенное решение
У нас есть три группы метрик (текст, структура DOM, визуал), каждая даёт свой score. Нужно их скомбинировать и принять решение: фишинг, чисто или требует ручной проверки.

Пример простой скоринговой модели:
  • Тайпсквоттинг: вычисляем расстояние Левенштейна между доменами, если проходит по нашему порогу, score +10.
  • Наличие фишинговых слов в домене: проводим keyword matching. Есть – score +15.
  • Текстовое сходство: cos_sim = 0.85 > 0.7, score +30.
  • Проверка action форм: указывает на чужой домен, на текущий подозрительный домен, или пустой – один из самых явных признаков фишинга, score +20.
  • Визуальное сходство: SSIM > 0.85, score +25.
Итоговый score = сумма сигналов. Максимум – 100.

Правила принятия решения:
  • Score ≥ 70 => фишинг. Автоматически генерируем abuse-отчёт и отправляем в takedown.
  • 40 ≤ Score подозрительно. Отправляем аналитику на ручную верификацию.
  • Score ложное срабатывание. Игнорируем.
Как улучшить модель:
  • Добавить проверку структуры DOM (схожесть HTML-дерева).
  • Анализировать SSL-сертификат: выпущен ли недавно, самоподписанный или Let's Encrypt.
Веса и пороги подбираются эмпирически под ваш бренд. Нужно прогонять тестовую выборку из реальных фишинговых и легитимных сайтов, смотреть на распределение score, регулировать пороги, чтобы минимизировать ложные срабатывания.

6. IOC Extraction: собираем улики
Перед нами фишинг, что делать дальше? Просто заблокировать – мало. Нужно вытащить из неё IOC, которые помогут защитить инфраструктуру: домены, IP-адреса, email’ы злоумышленников. А после извлечения – отправить в MISP, где эти индикаторы будут жить, обогащаться и использоваться для детекции будущих атак.
6.1. Парсинг: домены, IP, email, все, что не приколочено
Задача: из фишинговой страницы вытащить индикаторы, полезные для TI: домены перенаправления, IP-адреса панелей управления и C2, email’ы. Самый простой и надёжный способ – использовать регулярные выражения для поиска паттернов во всём HTML и JavaScript-коде.

Домены

Python:


[CODE]
import
re
def
extract_domains
(
html
)
:
pattern
=
r'(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}'
domains
=
set
(
re
.
findall
(
pattern
,
html
)
)
blacklist
=
{
'example.com'
,
'localhost'
,
'0.0.0.0'
}
return
[
d
for
d
in
domains
if
d
not
in
blacklist
and
len
(
d
)
MISP сформировал событие => скрипт отправляет данные в API (или через SMTP на email-адреса) компетентной организации => партнер направляет обращение регистратору.
8. Full Pipeline: end‑to‑end - по полной программе
Вот схема потока данных:
  1. Генерация кандидатов
    • Крон (раз в 6–12 часов) запускает dnstwist для вашего бренда.
    • dnstwist --registered выдаёт JSON со списком живых тайпо‑доменов.
    • Этот список загружается в Redis Set monitored_typos.
  2. Real‑time мониторинг
    • Демон Certstream крутится 24/7. На каждый новый сертификат:
      • Извлекаем домены из SAN.
      • Сначала проверяем if domain in monitored_typos: (совпадение с мутацией).
      • Если нет – прогоняем keyword matching (бренд + фишинговые слова).
    • При совпадении → rpush в Redis List scrapy:urls.
  3. Scrapy
    • Висит и ждёт URL.
    • Для каждого URL:
      • Скачивает страницу, обходит простую капчу (или маркирует).
      • Возвращает PhishingItem с HTML, скриншотом и метаданными.
  4. Content Analysis
    • Вычисляем текстовое сходство.
    • Сравниваем скриншоты (SSIM).
    • Выставляем общий score (0–100) по взвешенной модели.
  5. Decision & IOC Extraction
    • score >= 70 → фишинг.
      • Из HTML вытаскиваем домены, IP, email.
    • 40 <= score < 70 → отправляем аналитику на ручную верификацию.
  6. Threat Intelligence
    • Создаём событие в MISP.
    • Добавляем индикаторы с категориями Network activity, Payload delivery.
  7. Takedown
    • Определяем abuse‑контакты через abuse-whois.
    • Генерируем abuse‑отчёт.
    • Пробуем отправить через API регистратора.
    • Если API нет – падаем на email (SMTP) или на веб‑форму через requests.
    • В российских зонах .RU/.РФ – передаём в API, на email (SMTP) или на веб‑форму компетентной организации.


Фишинг не исчезнет. Проактивный мониторинг + автоматический takedown = минимум жертв. Внедряйте, тестируйте, масштабируйте, спите спокойно.
 
Ответить с цитированием
 





Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 


Быстрый переход




ANTICHAT ™ © 2001- Antichat Kft.