Статья Перехват трафика в устаревших криптобиблиотеках

1771442360582.webp


Тема сегодняшней ночной вахты - кладбище слонов. Буквально. Мы залезем в склепы, где догнивают протоколы, на которых до сих пор, как ни странно, держатся куски промышленных сетей, старых банкоматов, проприетарного железа и того самого "наследия", которое ваш техлид боится трогать руками. Речь про SSLv3 и его верного друга - RC4.

Почему это вообще работает до сих пор? Потому что бизнес не любит тратить деньги. Переписывать софт для заводского станка 1998 года выпуска, который шьет куртки или точит болванки, никто не будет. А контроллеры там общаются с сервером по старинке. И этот трафик летит по Wi-Fi, по Ethernet, а иногда, прости Господи, и по открытым каналам связи.

Мы с тобой - хакеры в хорошем смысле слова. Нам интересен механизм. Нам интересно, как из мешанины байтов, которые мы словим в эфире, получить пароль админа, команду на открытие люка или просто подтвердить, что система мертва, просто пока об этом не знает.

Готовь виртуалки. Ставь чай покрепче. Мы начинаем погружение.

Глава 1. Археология протоколов: почему мы тут, а не на пляже​

Мир, который забыл умереть​

Представь: идёт 2026 год. На Mars летают корабли, нейросети пишут романы, а где-то в подвале завода, выпускающего пластиковые вилки, сервер на Windows NT 4.0 исправно крутит базу данных, и общается с цеховыми контроллерами по протоколу, который был современным, когда твой старший брат ещё слушал кассеты с «Руки Вверх!». Этот протокол - SSLv3, а шифрует он трафик с помощью RC4. И всё бы ничего, но каждый пакет, улетающий от этого сервера, можно прочитать, имея ноутбук и немного терпения.

Я не утрирую. Legacy-системы - это не миф. Это бизнес-логика, в которую вбухали миллионы, и переписывать её никто не будет. Зачем? Ведь работает же!.. Работает, пока кто-то вроде нас с тобой не встанет посередине и не скажет: «А что это у вас за пароль тут летит? "admin:12345"? Очень мило».

Так что мы не просто копаемся в древностях. Мы готовимся к реальным пентестам и реальным боям. Потому что, когда на кону стоит остановка конвейера или утечка медицинских данных из старой поликлиники, знание SSLv3 превращается из «исторического интереса» в «инструмент взлома».

1.2. SSLv3: дедушка, которого пора усыпить​

1.2.1. Краткая история: от Netscape до POODLE​

SSL (Secure Sockets Layer) придумала компания Netscape в середине 90-х. Версия 3.0 вышла в 1996 году и стала основой для первого стандарта TLS (который, по сути, SSL 3.1 с переименованием). Тогда это была магия: можно было безопасно передавать данные по ненадёжной сети. Все радовались.

Но в 2014 году Google выпустила бюллетень об атаке POODLE (Padding Oracle On Downgraded Legacy Encryption). Оказалось, что в SSLv3 есть фатальная ошибка в обработке дополнения (padding) для блочных шифров. Серьёзность была такова, что все бросились отключать SSLv3 везде, где только можно. IETF официально объявила SSLv3 устаревшим (RFC 7568). Но, как ты понимаешь, не все прочитали RFC.

1.2.2. Анатомия протокола: что внутри?​

Чтобы понимать уязвимости, нужно знать структуру. SSLv3, как и все последующие версии, работает поверх TCP. Всё общение разбито на записи (records). Каждая запись имеет заголовок и данные.

Заголовок записи:
  • Content Type (1 байт) - тип данных: handshake (22), change cipher spec (20), alert (21), application data (23).
  • Protocol Version (2 байта) - для SSLv3 это 0x0300.
  • Length (2 байта) - длина данных (до 16384 байт).
Рукопожатие (Handshake): Самая сложная часть. Именно здесь клиент и сервер договариваются, как им шифровать. Включает в себя:
  1. ClientHello - клиент говорит: «Я умею такие-то версии (например, SSLv3, TLS 1.0) и такие-то наборы шифров (cipher suites)». Среди них может быть RC4-SHA, RC4-MD5, AES128-SHA и т.д.
  2. ServerHello - сервер выбирает версию и шифр из предложенных. Если сервер старенький, он может выбрать RC4.
  3. Сертификат - сервер шлёт свой сертификат (или цепочку).
  4. Клиентский ключ - клиент генерирует pre-master secret, шифрует его открытым ключом сервера и отправляет.
  5. Change Cipher Spec - обе стороны переключаются в режим шифрования.
  6. Finished - финальное подтверждение.
После рукопожатия начинается шифрованный обмен данными (Application Data).

1.2.3. Режимы шифрования в SSLv3​

SSLv3 поддерживал два типа шифров:
  • Потоковые: тогда был только RC4.
  • Блочные: DES, 3DES, IDEA, AES (позже добавили). В блочных использовался режим CBC (Cipher Block Chaining).
И вот здесь начинаются проблемы. В SSLv3 для блочных шифров схема дополнения (padding) была реализована так, что весь блок дополнения заполнялся длиной дополнения. Например, если нужно добавить 5 байт, каждый из этих пяти байт будет равен 5. А в более поздних версиях стали заполнять случайными байтами. Эта деталь - ключ к атаке POODLE.

1.2.4. Атака POODLE: как съесть собаку​

Разберём на пальцах. Пусть у нас есть блочный шифр с размером блока 16 байт (AES). Данные, которые нужно зашифровать, разбиваются на блоки. Последний блок дополняется до полного. Например, если у нас 30 байт данных, то будет 2 полных блока (32 байта) и остаток 14 байт. Дополнение будет 2 байта (чтобы заполнить до 16), и каждый из этих двух байт будет равен 2.

В CBC-режиме каждый блок шифротекста зависит от предыдущего. Расшифровка происходит так:

Код:
P_i = D(C_i) XOR C_{i-1}


где P_i - открытый текст i-го блока, C_i - шифротекст i-го блока, C_{i-1} - предыдущий шифротекст (для первого блока C_{0} - вектор инициализации).

Атака POODLE позволяет злоумышленнику, контролирующему сеть, расшифровать один байт за раз, манипулируя последним блоком. Как?
  1. Злоумышленник перехватывает зашифрованную запись.
  2. Он заменяет последний блок шифротекста на любой другой (например, копирует предпоследний).
  3. Отправляет модифицированную запись на сервер.
  4. Сервер расшифровывает. Если после расшифровки последний блок оказался корректным дополнением (например, последние байты равны длине дополнения), сервер принимает запись и, скорее всего, ответит нормально. Если дополнение некорректно, сервер выдаст ошибку (bad record mac).
  5. Наблюдая за реакцией сервера (есть ошибка или нет), злоумышленник понимает, угадал ли он байт.
В SSLv3 проверка подлинности (MAC) вычисляется до шифрования, но из-за особенностей padding-а атакующий может подменять блоки так, что MAC не проверяется, а сервер принимает данные.

Ключевой момент: Атака возможна, только если атакующий может заставить браузер жертвы отправить запрос с данными, которые он может контролировать (например, подсовывая JavaScript на HTTP-страницу). В ответ на такой запрос браузер пошлёт куки, и атакующий сможет их расшифровать побайтово.

1.2.5. Как проверить уязвимость к POODLE на практике​

Утилита testssl.sh - золотой стандарт. Скачиваем, запускаем:

Bash:
./testssl.sh --ssl3 target.com:443
Если увидишь VULNERABLE (NOT ok) - звони в колокола. Можно проверить и вручную через openssl, но это менее точно.

1.3. RC4: гамблер, который не умеет блефовать​

1.3.1. История появления и зачем его так любили​

RC4 (Rivest Cipher 4) разработал Рон Ривест в 1987 году. Долгое время это был trade secret, пока в 1994 году код не утёк в интернет. Шифр безумно простой и быстрый: инициализация ключа (KSA - Key Scheduling Algorithm) и генерация псевдослучайной последовательности (PRGA - Pseudo-Random Generation Algorithm). Всё, что нужно - массив из 256 байт и два индекса. Никаких сложных операций, поэтому RC4 работал даже на самом примитивном железе.

Именно за скорость и простоту его любили везде: WEP, WPA (опционально), SSL/TLS, SSH, даже в PDF для шифрования. В начале 2000-х казалось, что это идеальный потоковый шифр.

1.3.2. Как работает RC4: под капотом​

Код RC4 (упрощённо) выглядит так:

Python:
def rc4(key):
    # Инициализация S
    S = list(range(256))
    j = 0
    for i in range(256):
        j = (j + S[i] + key[i % len(key)]) % 256
        S[i], S[j] = S[j], S[i]

    # Генератор
    i = j = 0
    while True:
        i = (i + 1) % 256
        j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]
        K = S[(S[i] + S[j]) % 256]
        yield K

# Использование:
key_stream = rc4(b'secret_key')
plaintext = b'Hello, world!'
ciphertext = bytes([p ^ next(key_stream) for p in plaintext])

Гениально просто, не правда ли? Но простота здесь - враг.

1.3.3. Проблемы RC4​

1. Повторное использование ключа (Key reuse)
Самая страшная ошибка, которая встречалась в WEP, где ключи были статическими. Если мы зашифровали два сообщения одним и тем же ключом, то:

Код:
C1 = M1 XOR G
C2 = M2 XOR G
C1 XOR C2 = M1 XOR M2

А зная один открытый текст (например, стандартный заголовок), легко восстановить второй. В TLS, к счастью, для каждой сессии генерируется новый ключ (на основе pre-master secret), так что повторное использование минимально. Однако, если сервер использует один и тот же ключ для множества соединений (например, из-за бага), это катастрофа.

2. Смещения (Biases) в начале ключевого потока
RC4 - не идеальный генератор случайных чисел. Первые байты гаммы не равновероятны. Самые известные смещения:
  • Второй байт (индекс 1) с вероятностью ~1/128 равен нулю (а должно быть 1/256).
  • Множество других смещений, особенно сильные в первых 256 байтах.
В 2013 году исследователи (AlFardan et al.) показали, что, собрав достаточно много сессий, можно использовать эти смещения для восстановления открытого текста. Для полного взлома HTTP-куки требовалось около 2^30 сессий - на практике многовато, но для демонстрации возможности хватало.

В 2015 году атака усилилась (NOMORE - Numerous Occurrence MOnitoring & Recovery Exploit), которая позволила восстанавливать куки всего за несколько часов при активном MITM.

3. Слабые ключи (Weak keys)
Некоторые ключи приводят к тому, что первые байты гаммы предсказуемы. Это особенно критично для WEP, где использовались 104-битные ключи. Но в TLS ключи генерируются случайно, вероятность слабого ключа мала.

1.3.4. Как атаковать RC4 в TLS​

Самый реальный сценарий - атака на основе смещений с пассивным сбором трафика. Допустим, мы знаем, что клиент каждую минуту отправляет один и тот же запрос с cookie. Мы перехватываем тысячи таких запросов, записываем шифротексты. Затем применяем статистику: для каждой позиции в сообщении строим гистограмму байтов. Из-за смещений наиболее частый байт с высокой вероятностью равен открытому тексту (если смещение достаточно сильное). Для повышения точности используют несколько известных смещений и методы типа "Bayesian".

Пример упрощённого кода для сбора статистики:

Python:
import numpy as np
from collections import Counter

def collect_biases(ciphertexts, position):
    """Собираем значения байтов на определённой позиции."""
    values = []
    for ct in ciphertexts:
        if len(ct) > position:
            values.append(ct[position])
    counter = Counter(values)
    return counter

# Пусть у нас есть список ciphertexts
# Предположим, мы хотим расшифровать 20-й байт сообщения
counts = collect_biases(ciphertexts, 20)
# Самый частый байт
most_common = counts.most_common(1)[0][0]
print(f"Скорее всего, открытый текст байта 20 = {most_common:#04x}")

В реальности используются сложные методы, учитывающие несколько позиций одновременно и корреляцию между ними. Но суть та же: статистика решает.

1.3.5. Проверка поддержки RC4 на сервере​

Всё тем же testssl.sh:

Bash:
./testssl.sh --cipher-per-proto target.com | grep -i rc4
Или вручную через openssl:

Bash:
openssl s_client -connect target.com:443 -cipher RC4 2>&1 < /dev/null
Если видишь CONNECTED и сертификаты, значит RC4 поддерживается.

1.4. Инструментарий для первой разведки​

Перед тем как лезть в дебри, нужно понять, с чем имеем дело.

1.4.1. Nmap с скриптами​

Nmap умеет проверять SSL/TLS через скрипты:

Bash:
nmap --script ssl-enum-ciphers -p 443 target.com
Вывод покажет, какие версии протоколов и шифры поддерживаются. Если увидишь SSLv3 и RC4 - цель готова к атаке.

1.4.2. Wireshark-фильтры для быстрого поиска​

Когда уже есть pcap, можно быстро найти устаревшие протоколы:
  • ssl.record.version == 0x0300 - SSLv3.
  • ssl.handshake.ciphersuite == 0x0005 - RC4-SHA (или другие значения: 0x0004 - RC4-MD5).
  • Также можно фильтровать по наличию handshake с этими cipher suite.

1.4.3. Скрипт для проверки POODLE на Python​

Вот простой пример, который проверяет, падает ли сервер при отправке некорректного padding-а. Это не полноценный эксплоит, а индикатор.

Python:
import socket
import ssl
import struct

def test_poodle(host, port=443):
    """Пытается установить SSLv3-соединение и отправить кривой запрос."""
    # Создаём контекст с SSLv3 (в новых версиях Python может не работать)
    # Лучше использовать openssl через командную строку, но для примера:
    context = ssl.SSLContext(ssl.PROTOCOL_SSLv3)
    context.verify_mode = ssl.CERT_NONE
    context.check_hostname = False
    try:
        with socket.create_connection((host, port), timeout=5) as sock:
            with context.wrap_socket(sock, server_hostname=host) as ssock:
                # Получаем сертификат и т.д. (просто тест, что рукопожатие прошло)
                print(f"SSLv3 supported for {host}")
                # Здесь можно попытаться отправить некорректную запись
                # но для реальной проверки POODLE нужно больше кода
    except Exception as e:
        print(f"SSLv3 not supported or error: {e}")

test_poodle("example.com")

В новых версиях Python поддержка SSLv3 отключена, поэтому лучше использовать системный openssl или утилиту.

1.5. Почему это всё ещё актуально: живые примеры​

Я не буду называть имена, но поищи по багбаунти: до сих пор находят SSLv3 на сайтах банков, в API старых платёжных шлюзов, в embedded-устройствах (принтеры, IP-камеры, контроллеры доступа). Иногда это просто забытый сервер на внутреннем порту, который админ открыл наружу.

Ещё пример: программное обеспечение для управления автопарками. Ставят софт на Windows Server 2008, включают поддержку всего подряд, забывают обновить. И вот этот сервер болтается в интернете с SSLv3 и RC4, потому что «так исторически сложилось». А через него проходят данные о местоположении машин, грузах, маршрутах.

Наш план действий​

Мы с тобой не будем взламывать RC4 в реальном времени на лету - это пока что требует слишком много трафика. Мы будем его перехватывать, а потом анализировать.
Схема классическая:
  1. MITM (Man-in-the-Middle). Нам нужно встать между жертвой и сервером. В локальной сети это ARP-спуфинг, на своей машине - простейший прокси-сервер (mitmproxy, Burp), если жертва - мы сами (тестирование своего кода).
  2. Принуждение к слабости (Downgrade). Если сервер и клиент умные, они захотят говорить по TLS 1.2. Нам нужно заставить их забыть про хорошие манеры и перейти на SSLv3. Это делается либо обрывом хороших handshake'ов, либо использованием специальных утилит типа sslstrip (для HTTPS), либо ожиданием, когда клиент сам предложит устаревший метод (например, старая Java-либа, вшитая в софт).
  3. Перехват и логгирование. Записываем всё в PCAP.
  4. Оффлайн-анализ. Тащим pcap в Wireshark или скрипт на Python, который будет дергать уязвимые места.

Глава 2. Лаборатория. Готовим инструментарий​

Ты же не будешь это делать на рабочей сети? Будешь? Ну, смотри сам, я предупредил. Всё только в своей виртуалке или в сети, где есть письменное разрешение владельца. Честное слово, это важно.

Нам понадобятся:
  1. Жертва. Виртуальная машина со старой ОС (Windows XP, 7 без обновлений) или просто контейнер с запущенным старым OpenSSL (версии 0.9.8, например). Можно поднять простой HTTPS-сервер на Python с принудительным SSLv3 (соберем из исходников, это весело).
  2. Атакующий. Кали Линукс или просто любой Linux с установленными инструментами.
  3. Сеть. Host-Only или NAT в VirtualBox, чтобы не задеть реальных соседей по Wi-Fi.

Поднимаем сервер-жертву (SSLv3 + RC4)​

Зачем искать проблемы на стороне, если можно создать их самому? Напишем простой HTTPS-сервер на Python с использованием старой версии OpenSSL. Но проще использовать openssl как сервер.
Создадим самоподписанный сертификат (да, браузер будет ругаться, но нам это и нужно - жертва привыкла жать "Продолжить").

Bash:
# Генерируем ключ и сертификат
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes

Теперь запускаем сервер, который будет принимать ТОЛЬКО SSLv3 и использовать RC4.

Bash:
openssl s_server -accept 4433 -cert cert.pem -key key.pem -ssl3 -cipher RC4-SHA
Параметры:
  • -ssl3 - форсируем протокол.
  • -cipher RC4-SHA - форсируем конкретный шифр.
Вуаля. У нас есть сервер, который говорит на языке динозавров.

Настраиваем перехватчик (mitmproxy)​

Если жертва - это мы сами (тестируем свой браузер), то проще всего поставить mitmproxy. Это гениальная вещь.

Bash:
sudo apt install mitmproxy
# или pip install mitmproxy

Запускаем:

Bash:
mitmproxy --mode transparent --showhost
Но для прозрачного режима нужно настроить форвардинг пакетов и iptables. Для простого теста можно запустить в режиме обычного прокси: mitmproxy и выставить в браузере жертвы прокси 127.0.0.1:8080.
Минус: приложение-жертва должно уметь работать через системный прокси. Не все умеют.

Тяжелая артиллерия: Wireshark и tcpdump​

Нам нужен дамп трафика. tcpdump - консольный бог.

Bash:
sudo tcpdump -i eth0 -w sslv3_traffic.pcap host 192.168.1.100
Пишем весь трафик с машины-жертвы (192.168.1.100) в файл. Потом откроем его в Wireshark и будем смотреть руками.

Глава 3. Охота на POODLE: Ручное кормление зверя​

Атака POODLE нацелена на SSLv3 с блочными шифрами (AES-CBC, DES-CBC). Но мы-то с тобой включили RC4? Да. Но суть в том, что клиент и сервер договариваются о самом сильном из поддерживаемых шифров. Если мы (атакующий) заблокируем пакеты, предлагающие RC4, или клиент по какой-то причине предпочтет блочный шифр, мы окажемся в зоне риска POODLE.

Техническая суть для понимания:
В CBC-режиме каждый блок шифротекста зависит от предыдущего. POODLE позволяет атаковать последний блок, манипулируя padding'ом. Если злоумышленник может контролировать часть запроса (например, заставив браузер отправить данные, содержащие секретный cookie), он может по одному байту восстанавливать содержимое.

На практике для нас это означает:
  1. Жертва заходит на сайт (например, bank.local).
  2. У неё есть сессионная cookie (важные данные).
  3. Мы стоим в MITM и можем подменять пакеты.
  4. Атакующий заставляет браузер жертвы отправить запрос, где данные выровнены специальным образом.
  5. Атакующий перехватывает этот зашифрованный запрос, модифицирует его (сдвигает блоки) и отправляет на сервер.
  6. Если сервер принимает модифицированный запрос (а в SSLv3 проверка padding'а слабая), то по косвенным признакам (обрыв соединения или успех) атакующий понимает, угадал ли он байт данных.
Это сложно делать вручную. Для этого есть готовые эксплойты. Но для понимания - это манипуляция байтами на лету.

Инструмент: poodle-exploit​

На гитхабе есть куча скриптов. Один из них (на Python) делает примерно следующее: он принимает на вход целевой HTTPS URL и жертвует временем, чтобы вытащить cookie.
Схема работы такого скрипта:
  1. Устанавливается MITM-соединение.
  2. Скрипт ожидает, пока клиент пошлет запрос.
  3. Перехватывает его, разрывает (или модифицирует) handshake, форсируя падение до SSLv3.
  4. Начинает итеративно угадывать байты заголовка.
Главный враг тут - время. На восстановление одной cookie может уйти несколько минут и сотни запросов. Но если трафик идет через нас, мы можем просто ждать и автоматизировать.

POODLE сегодня редкость даже в legacy, потому что серверы обычно отключают SSLv3 совсем. Но если ты видишь при тесте, что сервер говорит SSLv3 - бей в колокола.

Глава 4. RC4: Охота за смещениями​

Вот мы и добрались до мяса. RC4 - это наш клиент. Он быстрый, красивый, но проклятый. Атака на RC4 называется атакой на основе смещений (RC4 biases). Самая известная реализация - атака, описанная в 2013 году (атака на TLS, использующий RC4).

Если совсем просто: первые 256 байт ключевого потока RC4 не случайны. Второй байт, например, с вероятностью 1/128 равен нулю, а не 1/256, как должен быть. Кажется, мелочь. Но если мы имеем тысячи и тысячи сессий, зашифрованных разными ключами, эти маленькие отклонения накапливаются, и мы можем восстановить открытый текст.

Сценарий атаки "Номер станции"​

Представь, что промышленный контроллер каждую секунду шлет на сервер пакет с данными. В пакете 50 байт, первые 10 - заголовок, а 11-й байт - код команды (0x01 - "все ок", 0x02 - "авария"). Шифруется всё это RC4 с уникальным ключом на каждую сессию (что обычно и делается в TLS).

Мы, как атакующие, записываем 100 000 таких пакетов.
Мы знаем, что первые 10 байт заголовка одинаковы всегда (или предсказуемы). Мы можем сложить все 100 000 пакетов и для каждой позиции посмотреть распределение байтов.
В позиции 11 (команда) байт 0x01 будет встречаться в 99.9% случаев, а 0x02 - в 0.1%. Это и есть открытый текст. Атака смещений не нужна - это просто частотный анализ. Но если команда зашифрована, мы видим просто кучу разных байтов. Как их расшифровать?

Мы применяем статистику смещений. Мы знаем, например, что в позиции 11 байт ключевого потока с вероятностью чуть выше средней равен, скажем, 0x00. Мы берем все наши зашифрованные байты C[11] и считаем, какой байт встречается чаще всего. Допустим, чаще всего встречается 0xAB. Это значит, что, скорее всего, C[11] = M[11] XOR K[11], и так как K[11] смещен в сторону 0x00, то M[11] скорее всего и есть 0xAB.

Это грубое приближение. Реальная атака использует несколько смещений для каждой позиции и перебор вариантов.

Инструмент: наш собственный статистический анализатор на Python​

Мы напишем простой скрипт, который будет анализировать pcap-файл, вытаскивать из него зашифрованные данные TLS-записей с RC4 и пытаться применить статистику.

Это не будет готовый эксплойт для взлома реального банка. Это будет educational tool, чтобы ты руками пощупал, как работает bias.

Шаг 1. Извлекаем шифротексты из PCAP
Нам нужна библиотека scapy. Она умеет парсить pcap.

Python:
from scapy.all import *
import numpy as np

def extract_rc4_ciphertexts(pcap_file):
    packets = rdpcap(pcap_file)
    ciphertexts = []
    for pkt in packets:
        # Фильтруем TCP-пакеты на 443 порт (или наш тестовый 4433)
        if TCP in pkt and (pkt[TCP].dport == 4433 or pkt[TCP].sport == 4433):
            payload = bytes(pkt[TCP].payload)
            # Это слишком упрощенно. Нужно парсить TLS-записи.
            # В реальности тут надо пропускать Handshake и брать только Application Data.
            # Но для демо-примера с нашим тестовым сервером, где всё летит в открытую, сойдет.
            # Пропускаем пустые пакеты и пакеты с хэндшейком (они маленькие обычно)
            if len(payload) > 100: # Допустим, данные начинаются после 100 байт (грубо)
                 # Отрезаем заголовок TLS-записи (5 байт: тип, версия, длина)
                 # и оставляем только шифрованные данные
                record_header = payload[:5]
                if len(payload) > 5:
                    encrypted_data = payload[5:]
                    ciphertexts.append(encrypted_data)
    return ciphertexts

# Использование
# ct_list = extract_rc4_ciphertexts("sslv3_traffic.pcap")
# print(f"Извлечено {len(ct_list)} шифротекстов")

Важно: Это примитивный код. В реальном TLS шифрованные данные идут внутри записей, и их надо правильно собрать по TCP-сегментам. Но суть ты уловил.

Шаг 2. Собираем статистику по байтам
Допустим, у нас есть список шифротекстов разной длины. Мы хотим проанализировать позицию, например, 20-й байт (индекс 19 в Python).

Python:
def analyze_position(ciphertexts, pos):
    byte_counts = {}
    for ct in ciphertexts:
        if len(ct) > pos:
            b = ct[pos]
            byte_counts[b] = byte_counts.get(b, 0) + 1
    # Сортируем по частоте
    sorted_counts = sorted(byte_counts.items(), key=lambda x: x[1], reverse=True)
    return sorted_counts

# pos = 19
# result = analyze_position(ct_list, pos)
# print(f"Топ-5 байт на позиции {pos}: {result[:5]}")

Шаг 3. Применяем известные смещения для RC4
Исследователи вычислили смещения для каждой позиции. Например, для позиции 2 смещение в сторону 0. Есть таблицы. Мы можем взять самую частую байту в нашей выборке и сказать: "С вероятностью N% это и есть настоящий открытый текст на этой позиции, XORed с предсказуемым значением".

Чтобы превратить это в реальный взлом, нужно:
  1. Знать структуру сообщения (где какой заголовок).
  2. Иметь тысячи и тысячи сообщений.
  3. Использовать технику, похожую на атаку "Miredo" или "RC4 NOMORE" (которая еще страшнее, позволяет внедрять данные)

1771442385691.webp


Глава 5. Автоматизация: ставим всё на рельсы​

Ручками дергать пакеты скучно. Есть утилиты, которые делают эту грязную работу за нас.

bettercap: Швейцарский нож для сетевых игр​

Это эволюция ettercap. Умеет всё: ARP-spoof, сниффинг, и главное - умеет создавать скрипты на Lua и JavaScript для модификации трафика на лету.

Простой сценарий для нас:
Мы хотим заставить клиента и сервер отказаться от хороших шифров и перейти на RC4 (если он поддерживается). bettercap может подменять приветственные сообщения (ClientHello), вырезая оттуда продвинутые шифры.

Bash:
sudo bettercap -eval "set arp.spoof.targets 192.168.1.100; arp.spoof on; set http.proxy.sslstrip true; http.proxy on"
Но sslstrip - это для HTTPS -> HTTP. Для понижения версии протокола есть более хитрые методы. Можно написать скрипт, который в TCP-потоке находит ClientHello и заменяет версию протокола с 0x0303 (TLS 1.2) на 0x0300 (SSL 3.0). Это работает, если сервер не проверяет подлинность (а в старых библиотеках часто не проверяют).

Wireshark: аналитика на кончиках пальцев​

Открываем наш pcap. В Wireshark есть замечательный инструмент: Statistics -> Protocol Hierarchy. Если там висит SSLv3 - мы в игре.
Дальше, чтобы отфильтровать только нужные пакеты, используем фильтр:
ssl.record.version == 0x0300 - для SSLv3.
А чтобы найти пакеты, где согласован RC4, нужно смотреть на Handshake: ssl.handshake.ciphersuite == 0x0005 (это RC4-SHA) или 0x0004 (RC4-MD5).
Задайте фильтр ssl &amp;&amp; ip.addr == 192.168.1.100 и смотрите поток. Вы удивитесь, как много интересной информации передается в открытую внутри зашифрованного канала. Имена серверов (SNI), сертификаты - всё это летит в открытом виде до установки шифрования.

Глава 6. Взлом в реальном времени с помощью Fiddler / mitmproxy + скрипты​

Когда мы ставим MITM-прокси типа mitmproxy, мы получаем суперсилу: мы видим трафик ДО того, как он будет зашифрован, и ПОСЛЕ того, как он будет расшифрован на нашей стороне. Если прокси поддерживает старые протоколы, он может выступить в роли моста.

Задача: Есть клиент (старая программа), который говорит ТОЛЬКО SSLv3+RC4. Есть сервер в интернете, который тоже говорит на этом (или мы его сдампили). Мы хотим перехватить данные в читаемом виде.

Решение:
  1. Запускаем mitmproxy с поддержкой SSLv3. Для этого нам нужно скомпилировать OpenSSL для mitmproxy с поддержкой старых протоколов или использовать системную библиотеку, где они не отключены.
  2. Настраиваем клиента на наш прокси.
  3. mitmproxy принимает SSLv3-соединение от клиента, расшифровывает его, показывает нам в консоли (или сохраняет в файл), а затем устанавливает новое (уже безопасное) соединение с сервером, либо пересылает как есть.
  4. PROFIT.
Это не ломает шифрование в прямом смысле. Это использует тот факт, что прокси - это "человек посередине" легально. Клиент доверяет нашему самоподписанному сертификату (мы его скормили клиенту заранее). Для тестирования legacy-систем - это идеальный метод.

Глава 7. Защита: как нас не должны были ловить​

Рано или поздно ты окажешься по ту сторону баррикад - либо как штатный безопасник, либо как внешний аудитор, который должен не только найти дыру, но и предложить, как её заткнуть. Или как админ, который просто хочет спать спокойно, зная, что его legacy-сервер не светит паролями на каждом углу.

Я не буду вещать про "лучшие практики" из википедии. Я расскажу, что реально работает в условиях, когда железо старое, софт не обновляется, а начальство не даёт денег на полную замену. Это окопная правда инженерной защиты.

7.1. Изоляция: физическая и логическая. Не подходи, убьёт​

Самый надёжный способ защитить систему от сетевых атак - сделать так, чтобы до неё вообще нельзя было достучаться извне. Это как спрятать ключи от квартиры не под ковриком, а в сейфе в другой квартире.

7.1.1. Физическая изоляция (Air Gap)​

Звучит как паранойя, но иногда это единственный выход. Если сервер с SSLv3 висит в сети цеха, к которой подключены только станки и рабочие станции операторов, и при этом никакой внешний трафик (включая Wi-Fi для гостей) не может достичь этого сегмента - это уровень защиты, который не взломать удалённо. Чтобы добраться до такого сервера, злоумышленнику нужно физически проникнуть на территорию и воткнуться в розетку.

Но есть нюанс: физическая изоляция часто нарушается ради удобства. Кто-то ставит свой ноутбук в цех, подключается к той же сети, и привет - мост между мирами построен. Поэтому если уж делаешь air gap, делай его жёстко: никаких лишних портов, строгий учёт устройств, контроль физического доступа.

7.1.2. Сетевая изоляция: VLAN'ы и ACL​

Когда физически отрезать нельзя (например, сервер должен быть доступен из других отделов), используем логическую изоляцию.

VLAN (Virtual LAN) - делим коммутатор на виртуальные куски. Весь legacy-трафик живёт в своём VLAN'е, например, ID 100. Доступ из других VLAN'ов (скажем, из бухгалтерии или гостевой сети) запрещён на уровне коммутатора или маршрутизатора.

Пример конфигурации на Cisco (упрощённо):

Код:
vlan 100
 name LEGACY_ZONE
interface GigabitEthernet0/1
 switchport access vlan 100
interface Vlan100
 ip address 192.168.100.1 255.255.255.0
 no ip proxy-arp
access-list 101 deny ip any 192.168.100.0 0.0.0.255
access-list 101 permit ip any any
interface Vlan100
ip access-group 101 in

Но это только база. Нужно не забыть запретить и меж-VLAN маршрутизацию.

ACL на фаерволе - если у тебя есть центральный межсетевой экран (pfSense, Cisco ASA, iptables на Linux), на нём выставляем правила: к legacy-сегменту могут обращаться только определённые IP-адреса (например, только серверы приложений, которые должны стучаться к базе). Всё остальное - дроп.

Пример на iptables для Linux-роутера:

Bash:
# Разрешить доступ с доверенного сервера 10.0.0.5 к порту 443 legacy-сервера 192.168.100.10
iptables -A FORWARD -s 10.0.0.5 -d 192.168.100.10 -p tcp --dport 443 -j ACCEPT
# Остальное на 192.168.100.10 - запретить
iptables -A FORWARD -d 192.168.100.10 -j DROP

Таким образом, даже если внутри сети завелась вредоносная программа, она не сможет достучаться до древнего сервера, если её IP не в белом списке.

7.1.3. Микросегментация​

Современный тренд, который отлично ложится на legacy. Каждому приложению или серверу выделяется свой крошечный сегмент сети. Доступ разрешён только между конкретными парами "клиент-сервер". Это можно делать на управляемых коммутаторах или с помощью технологий типа VMware NSX (если виртуализация). Для старых физических серверов - только VLAN + ACL.

7.2. VPN: туннель в прошлое с защитой настоящего​

Если legacy-система должна быть доступна извне (например, удалённым филиалам или подрядчикам), никогда не открывай её напрямую в интернет. Никогда. Используй VPN.

7.2.1. Классический удалённый доступ​

Ставим VPN-сервер (OpenVPN, WireGuard, IPSec) на границе сети. Удалённый сотрудник подключается к VPN, получает внутренний IP и уже через него стучится к legacy-серверу. При этом весь трафик между ним и VPN-сервером зашифрован современными алгоритмами (AES-256-GCM, ChaCha20). Сам legacy-сервер даже не знает, что трафик пришёл из интернета - он видит только пакеты от VPN-сервера.

Пример настройки OpenVPN (серверная часть):

Код:
port 1194
proto udp
dev tun
ca ca.crt
cert server.crt
key server.key
dh dh.pem
server 10.8.0.0 255.255.255.0
push "route 192.168.100.0 255.255.255.0"
client-to-client
keepalive 10 120
cipher AES-256-GCM
auth SHA256
user nobody
group nogroup
persist-key
persist-tun
status openvpn-status.log
verb 3

На клиенте после подключения маршрут к 192.168.100.0/24 идёт через VPN. Вуаля - legacy трафик внутри туннеля.

7.2.2. Сайт-сайт VPN для связи филиалов​

Если два завода обмениваются данными по старым протоколам, между ними поднимается VPN-туннель (например, IPSec). Внутри туннеля трафик может быть любой, хоть SSLv3. Снаружи - только зашифрованный IPSec-пакет.

Пример конфигурации для strongSwan (IPsec):

Код:
# /etc/ipsec.conf
conn site-a-to-site-b
    left=1.2.3.4          # внешний IP завода А
    leftsubnet=192.168.100.0/24
    right=5.6.7.8          # внешний IP завода Б
    rightsubnet=192.168.200.0/24
    keyexchange=ikev2
    authby=secret
    ikelifetime=24h
    lifetime=8h
    dpddelay=30
    dpdtimeout=120
    dpdaction=restart
    esp=aes256-sha256-modp2048!
    auto=start

Файл с ключами /etc/ipsec.secrets содержит общий секрет. Всё, трафик между сетями заводов идёт внутри защищённого туннеля.

7.2.3. Почему VPN - не панацея​

VPN защищает трафик на пути между точками, но не защищает внутри сети назначения. Если злоумышленник уже проник в локальную сеть филиала, он может перехватывать трафик уже после расшифровки VPN. Поэтому VPN должен сочетаться с изоляцией внутри периметра.

7.3. Прокси-обёртки: stunnel и его друзья​

Это моё любимое решение. Позволяет вообще не трогать legacy-приложение, но при этом обернуть его трафик в современный TLS. Принцип прост: ставится прокси на той же машине, что и legacy-сервер (или перед ним), который принимает внешние соединения по TLS 1.2/1.3, расшифровывает их и отправляет локально на legacy-порт уже в открытом виде (или наоборот, если legacy-клиент).

7.3.1. Stunnel: классика жанра​

Stunnel - это легковесный прокси, который умеет создавать TLS-туннели поверх любых TCP-соединений. Работает на всех платформах, включая Windows (что важно для старого софта).

Сценарий 1: Legacy-сервер с SSLv3 торчит наружу.
Мы не можем отключить SSLv3 на самом сервере, но можем поставить stunnel перед ним на том же или отдельном хосте. Внешние клиенты подключаются к stunnel по современному TLS, stunnel расшифровывает трафик и шлёт его на legacy-сервер уже как обычный TCP (или даже как SSLv3, если нужно, но лучше plain, если сервер понимает). Сервер получает команды, отвечает, stunnel зашифровывает ответ обратно.

Конфиг stunnel (/etc/stunnel/stunnel.conf):

Код:
; Глобальные настройки
pid = /var/run/stunnel.pid
output = /var/log/stunnel.log
sslVersion = TLSv1.2  ; или TLSv1.3, если версия позволяет
options = NO_SSLv2
options = NO_SSLv3

; Сервис для legacy-сервера
[legacy_service]
accept = 0.0.0.0:443        ; внешний порт, который слушает stunnel (современный TLS)
connect = 127.0.0.1:1443    ; локальный порт, где висит legacy-сервер (plain TCP)
cert = /etc/stunnel/stunnel.pem
; Можно добавить проверку клиента, если нужно
; verify = 2
; CAfile = /etc/stunnel/ca.pem

На legacy-сервере (который теперь висит на 127.0.0.1:1443) мы должны убедиться, что он слушает только локальный интерфейс. В идеале - настроить его на приём plain TCP (без шифрования), потому что stunnel уже обеспечил безопасность канала. Если приложение требует SSLv3 (например, в нём жёстко прописано использование SSL), можно направить stunnel на другой stunnel, который уже будет говорить по SSLv3, но это оверхед.

Сценарий 2: Legacy-клиент, который умеет только SSLv3, должен соединиться с современным сервером.
Здесь stunnel работает в обратную сторону. Клиент подключается к локальному stunnel, который принимает SSLv3, расшифровывает и устанавливает современное TLS-соединение с удалённым сервером. Либо, если сервер тоже старый, stunnel может просто проксировать трафик, но добавить слой защиты между клиентом и внешней сетью.

Конфиг для клиентской стороны:

Код:
[legacy_client]
client = yes
accept = 127.0.0.1:2443      ; локальный порт, к которому подключается legacy-клиент
connect = real-server.com:443 ; внешний современный сервер
; Тут можно задать протокол для внешнего соединения
sslVersion = TLSv1.2

7.3.2. Более современные варианты: HAProxy, Nginx​

HAProxy и Nginx тоже умеют проксировать TCP-трафик с терминированием SSL/TLS. Они мощнее stunnel, но и тяжелее. Если у тебя уже стоит HAProxy как балансировщик, можно использовать его.

Пример секции для HAProxy (frontend/backend):

Код:
frontend legacy_front
    bind *:443 ssl crt /etc/ssl/certs/my-cert.pem no-sslv3
    mode tcp
    default_backend legacy_back

backend legacy_back
    mode tcp
    server legacy1 127.0.0.1:1443 send-proxy-v2  # если нужно сохранить исходный IP

Здесь важно mode tcp, потому что мы проксируем сырой TCP, а не HTTP.

7.3.3. Риски и подводные камни прокси-обёрток​

  • Потеря исходного IP: Сервер будет видеть IP прокси, а не реального клиента. Это проблема для аудита и некоторых приложений. Решается протоколом PROXY (send-proxy в HAProxy, опция в stunnel).
  • Увеличение задержки: Дополнительная расшифровка и шифрование добавляют latency, но для большинства legacy-систем это некритично.
  • Единая точка отказа: Прокси должен быть отказоустойчивым.
  • Сложность отладки: Если что-то идёт не так, приходится смотреть логи на двух уровнях.

7.4. Шлюзы прикладного уровня (ALG) и MITM в хорошем смысле​

Иногда простого TCP-прокси недостаточно. Например, если протокол содержит внутри себя информацию об IP-адресах или требует аутентификации, которая зависит от шифрования. Тогда нужен более умный шлюз.

7.4.1. Reverse-прокси для HTTP/HTTPS​

Если legacy-приложение - это веб-сервер с SSLv3, можно поставить перед ним Nginx в режиме reverse-proxy. Nginx будет принимать HTTPS с современными настройками, а с бэкендом общаться по HTTP (или даже по HTTPS, но с пониженными требованиями, если очень надо).

Пример конфига Nginx:

NGINX:
server {
    listen 443 ssl http2;
    server_name legacy.example.com;
    ssl_certificate /etc/nginx/ssl/cert.pem;
    ssl_certificate_key /etc/nginx/ssl/key.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    location / {
        proxy_pass http://127.0.0.1:8080; # legacy-сервер на локальном порту (plain HTTP)
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Таким образом, весь внешний трафик защищён, а внутри локальной петли идёт открытый текст (или старый протокол). Если внутренний сервер требует HTTPS, можно указать proxy_pass https://..., но тогда нужно возиться с сертификатами.

7.4.2. Для не-HTTP протоколов​

Сложнее. Но можно использовать специализированные прокси. Например, для баз данных есть прокси типа ProxySQL (для MySQL), который умеет терминировать TLS и отправлять запросы в plaintext на старую базу. Или для почтовых протоколов (SMTP, POP3) - postfix с соответствующими настройками.

7.5. Мониторинг и обнаружение атак (или как понять, что тебя ломают)​

Даже если ты всё закрыл, нужно знать, не пытается ли кто-то обойти защиту. Пассивный мониторинг поможет вовремя заметить сканирование, попытки понижения версии или подозрительный трафик.

7.5.1. Сигнатуры для IDS (Snort/Suricata)​

Хорошие сеты правил (ET Open, VRT) содержат сигнатуры на атаки типа POODLE, на попытки согласовать SSLv3, на использование RC4.

Пример сигнатуры Suricata для обнаружения SSLv3 handshake:

Код:
alert tls $EXTERNAL_NET any -> $HOME_NET any (msg:"ET POLICY SSLv3 outbound connection"; tls.version; content:"|03 00|"; offset:0; depth:2; classtype:policy-violation; sid:12345; rev:1;)
Такая сигнатура сработает, если кто-то внутри сети пытается установить SSLv3-соединение наружу. Можно настроить на любое событие.

7.5.2. Логи прокси и серверов​

Если используешь stunnel или Nginx, смотри их логи. Подозрительно много неудачных handshake'ов, ошибок верификации сертификатов, попыток подключиться на странные порты - всё это повод насторожиться.

7.5.3. Анализ трафика на смещения RC4​

Тут сложнее. Обнаружить пассивный сбор статистики почти невозможно, потому что атакующий просто слушает. Но если ты видишь необычно много сессий с одного IP к одному ресурсу, возможно, идёт сбор данных для статистической атаки. Хотя это может быть и обычный пользователь.

7.5.4. Honeypot внутри legacy-сегмента​

Можно поставить ложную цель (приманку), которая имитирует уязвимый сервис. Любое обращение к ней - почти гарантированно сканирование или атака. Поднимаешь простой сервер на Python, который отвечает на SSLv3, и смотришь, кто стучится.

7.6. А если вообще ничего нельзя менять?​

Бывает и такое. Железка 20-летней давности, прошивка не обновляется, stunnel на неё не поставишь, а выключать нельзя. Что делать?
  1. Максимальная изоляция: Физически отключаем от всех сетей, кроме самого необходимого минимума. Убираем все лишние маршруты.
  2. Туннелирование на уровне связи: Если есть возможность, используем аппаратные шифраторы канального уровня (но это редкость и дорого).
  3. Допуск только по воздуху: Вся передача данных через сменные носители. Да, это больно, но иногда безопаснее, чем открытый сетевой протокол.
  4. План реагирования: Готовим сценарий на случай, если компрометация всё же произойдёт. Как быстро отключить, как восстановить данные, кого звать.

Заключение.​

Мы с тобой проделали огромный путь. От теории, от которой у нормальных админов начинается аллергическая крапивница, до реальных примеров кода и команд, которые можно запустить прямо сейчас. Если ты дочитал до этого места (или просто промотал вниз, но обещаешь вернуться), ты уже не просто пользователь. Ты - человек, понимающий, как гниёт софт под поверхностью блестящего Web 3.0.

Мы живём в эпоху, когда каждый день выходят обновления для браузеров, патчи для ядра Linux, новые версии OpenSSL. Но основная масса кода, который управляет реальным миром - светофорами, электростанциями, заводскими станками, банкоматами, системами контроля доступа - была написана 10, 15, а то и 20 лет назад. Её никто не трогает, потому что она работает. Принцип «не чини то, что не сломано» здесь возведён в абсолют.

И вот эта «работающая» система тихонько шлёт по сети пакеты, зашифрованные SSLv3 и RC4. Для неё это норма. Для нас с тобой - приглашение к разговору.

Пока существуют старые системы, знание их уязвимостей будет востребовано. Это не архаика, это field craft. Как умение развести костёр без спичек в эпоху зажигалок.
Мир не станет безопаснее после прочтения этой статьи. Где-то в этот самый момент какой-нибудь заводской контроллер радостно обменивается RC4-пакетами с сервером, даже не подозревая, что каждый его чих можно прочитать. И это нормально. Мы не можем переписать весь legacy-код вселенной. Но мы можем стать теми, кто понимает риски и умеет их минимизировать или, наоборот, демонстрировать.

Если ты прочитал всё это не для галочки, а чтобы реально разобраться - ты свой. Добро пожаловать в клуб людей, которые не верят в магию, а верят в байты, статистику и здравый смысл.

А теперь иди и проверь свой старый роутер на даче. Вдруг он до сих пор шепчется по SSLv3 с твоим ноутбуком? Мир ломается не только кувалдой, но и скальпелем. Мы выбираем скальпель.
 
Мы в соцсетях:

Взломай свой первый сервер и прокачай скилл — Начни игру на HackerLab