Wireshark декодирует только в одном направлении.

Вопрос или проблема

Я написал чат-клиент на Python, который использует TLS-шифрование. Сервер работает на одном ПК, а клиент на другом.

Сервер создает SSL-ключи (server.key и server.crt), а затем я копирую server.crt на клиентский ПК.

Клиент не создает свои собственные SSL-ключи.

Используя LD_PRELOAD, я собираю SSLKEYLOGFILE на серверном ПК.
Я также собираю pcap, используя tcpdump на серверном ПК.

Я беру их оба в Wireshark для дешифровки pcap.

Однако только пакеты Client -> Server декодируются. Сообщения Server -> Client остаются зашифрованными. Почему так?

Keylog.txt:

SERVER_HANDSHAKE_TRAFFIC_SECRET 6e1c671e89c253c9670297d7af1c651236cb52ffcec31f393ff2d4c345b65b83 83156d3d139ab2bda9fb30bc68699fadeaff736373585e9296618973b804e67b858f904b6d67d35791f154d2df1c53ec
CLIENT_HANDSHAKE_TRAFFIC_SECRET 6e1c671e89c253c9670297d7af1c651236cb52ffcec31f393ff2d4c345b65b83 d27b9286b3f209da0cfca1055cd6c5a0b7dc638a3b47b760fc52c46530c6f0129e3ab8cb97de02d708dcd78e4b8eeef6
EXPORTER_SECRET 6e1c671e89c253c9670297d7af1c651236cb52ffcec31f393ff2d4c345b65b83 a81094854b39ab0a39ab4b1d0669591024a3c05d4a8b0df0870e2df824b447b9cdd206e4f120dbeb871a0f642bff783b
SERVER_TRAFFIC_SECRET_0 6e1c671e89c253c9670297d7af1c651236cb52ffcec31f393ff2d4c345b65b83 fa8a418607881a3c78082009acded37a4f1640b6d7e4932785b071bd3dcae67aaef91ef664bb1fc1f01e22d800b11e73
CLIENT_TRAFFIC_SECRET_0 6e1c671e89c253c9670297d7af1c651236cb52ffcec31f393ff2d4c345b65b83 f90a697b55859c7144ccf34c499869cddbec964f37386ab08cf7ed137cd54c53b9c119b42fda4f37b0ba3e5a62694cf7

Server.py:

import socket
import ssl
import argparse

# Серверная сторона
def create_tls_server(certfile, keyfile, port):
    context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
    context.load_cert_chain(certfile, keyfile)

    hostname = socket.gethostname()
    IPAddr = socket.gethostbyname(hostname)
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
    sock.bind((IPAddr, port))
    sock.listen(2)

    print(f"Сервер запущен на {IPAddr}:{port}. Ожидание подключений...")

    while True:
        client_socket, addr = sock.accept()  # Принимаем незащищенное соединение
        try:
            ssl_conn = context.wrap_socket(client_socket, server_side=True)  # Оборачиваем здесь
            print(f"Подключено {addr}. Ожидание сообщения...")
            while True:
                data = ssl_conn.recv(1024).decode()
                if not data:
                    break
                print(f"Получено: {data}")
                if data == 'bye':
                    break
                print(">> ", end='')
                response = input()
                ssl_conn.send(response.encode())
        except Exception as e:
            print(f"Ошибка: {e}")
        finally:
            ssl_conn.close()
            client_socket.close()  # закрываем соединение
            print(f"Соединение с {addr} закрыто.")
            break

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="TLS Server")
    parser.add_argument("-p", "--port", type=int, default=8500, help="Номер порта")
    parser.add_argument("-v", "--version", type=int, default=ssl.PROTOCOL_TLS_SERVER, help="Версия TLS")
    args = parser.parse_args()

    create_tls_server('./server.crt', './server.key', args.port)

Client.py:

import socket
import ssl
import argparse

# Клиентская сторона
def connect_tls_client(cafile, port, host):
    context = ssl.create_default_context()
    context.load_verify_locations(cafile)

    sock = socket.socket()  # создаем сокет
    sock.connect((host, port))  # подключаемся к серверу

    client_socket = context.wrap_socket(sock, server_hostname=host)

    print(">> ", end='')
    message = input()

    while message.lower().strip() != 'bye':
        client_socket.send(message.encode())  # отправляем сообщение
        data = client_socket.recv(1024).decode()  # получаем ответ
        if not data:
            break

        print('Получено от сервера: ' + data)  # выводим на терминал

        if data == 'bye':
            break

        print(">> ", end='')
        message = input()

    client_socket.close()  # закрываем соединение

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="TLS Client")
    parser.add_argument("-s", "--server_ip", default="name-of-remote-serverenter image description here", help="IP адрес сервера")
    parser.add_argument("-p", "--port", type=int, default=8500, help="Номер порта")
    parser.add_argument("-v", "--version", type=int, default=ssl.PROTOCOL_TLS_SERVER, help="Версия TLS")
    args = parser.parse_args()

    connect_tls_client('./server.crt', args.port, args.server_ip)

Вот как это было решено для меня.

Я сделал 2 вещи:

  1. Разрешил поддисектору восстанавливать TCP-потоки.
Следующие предпочтения протокола TCP также необходимы для активации дешифрования TLS:

Разрешить поддисектору восстанавливать TCP-потоки. Включено по умолчанию.
Восстановление сегментов вне порядка (с Wireshark 3.0, отключено по умолчанию).

Ссылка
https://gitlab.com/wireshark/wireshark/-/issues/16713
https://wiki.wireshark.org/TLS#%E2%80%8DPreference_Settings

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

Я изменил свой запрос tcpcap для сбора только TLS-пакетов – это уменьшило шум в моих захватах и позволило захватить оба направления:

tcpdump -i any 'tcp[((tcp[12:1] & 0xf0) >> 2):1] & 0x80 = 0 && (tcp[((tcp[12:1] & 0xf0) >> 2):1] >= 0x14 && tcp[((tcp[12:1] & 0xf0) >> 2):1] <= 0x17)' -w tls_any_port.pcap

Сработало отлично!
Спасибо всем.

Ответ или решение

Когда вы сталкиваетесь с проблемой расшифровки пакетов с помощью Wireshark, где данные расшифровываются только в одном направлении, это может вызывать разочарование. Такая ситуация часто возникает в результате неправильной настройки или ошибки при сборе данных. Рассмотрим подробно возможные причины и пути их решения, используя указанный пример с клиент-серверным приложением на Python, работающим через TLS.

Теория

Когда вы используете протокол TLS для шифрования трафика, данные пересылаемые между клиентом и сервером шифруются с использованием симметричных и асимметричных ключей. Wireshark способен расшифровывать этот трафик, если у вас есть доступ к ключевым материалам, таким как SSLKEYLOGFILE. Даже когда все ключи собраны правильно, важно удостовериться, что все требования для расшифровки выполняются: использование корректных версий протоколов и спецификаций TCP/IP.

Основные причины того, что пакеты расшифровываются только в одном направлении (например, только от клиента к серверу), могут включать:

  1. Отсутствие ключей для одной из сторон: Каждая сторона имеет свои собственные секреты трафика, которые нужны для расшифровки сообщения, и если ключи для сервера отсутствуют, записи в направлении "сервер-клиент" останутся зашифрованными.

  2. Неправильный сбор сетевого трафика: Использование не того интерфейса, фильтрация трафика только по определенному порту или другой аспект конфигурации tcpdump может привести к тому, что пакеты от другой стороны просто не захватываются.

  3. Настройки Wireshark: Отсутствие конфигурации собирающих подпроцессоров (subdissectors) для повторного объединения TCP сегментов может нарушить правильную расшифровку штрихов, так как некоторые пакеты в потоке могут быть пропущены или собраны неправильно.

Пример

Рассмотрим ваш пример:

  • Серверная часть написана на Python и использует ssl.SSLContext для обработки TLS соединений, создавая ключи server.key и server.crt.
  • Клиентская часть использует ssl.create_default_context() для установления защищенного соединения с сервером.
  • Вы используете LD_PRELOAD с SSLKEYLOGFILE на серверной машине для сбора ключей шифрования.

Логика сборки и использования SSL ключей описана корректно, однако, существует несколько важных аспектов, на которые стоит обратить внимание:

Применение

  1. Проверка ключей: Убедитесь, что файл с ключами SSLKEYLOGFILE содержит как клиентские, так и серверные секреты трафика. Чтобы проверить, следует обратить внимание на наличие обеих записей CLIENT_TRAFFIC_SECRET и SERVER_TRAFFIC_SECRET в лог-файле. В предоставленном вами лог-файле они присутствуют, поэтому это не является проблемой.

  2. Захват трафика: Используйте tcpdump без привязки к конкретному порту; в вашем решении вы уже использовали фильтр для захвата конкретных пакетов TLS, что было эффективным шагом. Сбор всех пакетов, а затем их фильтрация с помощью фильтров отображения Wireshark, такая как tls, может упростить обнаружение проблемы, если захват не корректен. Это позволило вашему решению сработать корректно.

  3. Настройка Wireshark: Основной исправленный момент — это настройка Wireshark, чтобы он разрешал собирателям объединять TCP потоки, а также "reassemble out-of-order segments". Это критически важно для корректной обработки зашифрованных протоколов. Данные настройки находятся в разделе "Edit" -> "Preferences" -> "Protocols" -> "TCP", и от них зависит, как шифрованные данные будут приняты Wireshark.

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

Оцените материал
Добавить комментарий

Капча загружается...