Ошибка Heartbleed: почему вообще возможно обработать запрос пульса до того, как полезная нагрузка будет доставлена?

Во-первых, я не программист на C, а кодовая база OpenSSL огромна, поэтому простите меня за вопрос, на который я, вероятно, мог бы найти ответ, учитывая, что у меня было время и навыки, чтобы копаться в коде.

Насколько я могу судить, TLS работает поверх TCP. TCP ориентирован на поток, поэтому невозможно узнать, когда сообщение было доставлено. Вы должны заранее знать, какой длины должно быть входящее сообщение, или иметь разделитель для сканирования.

Имея это в виду, как OpenSSL может обработать запрос пульса до того, как будет получена вся полезная нагрузка?

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

Итак, вопрос: как/почему OpenSSL может начать обработку сообщения, которое еще не доставлено?


person Niels B.    schedule 18.04.2014    source источник
comment
Этот вопрос относится к другому сайту в сети Stack Exchange. Возможно, security.stackexchange.com или crypto.stackexchange.com.   -  person jww    schedule 20.04.2014


Ответы (2)


Это определение пакета пульса.

struct {
  HeartbeatMessageType type;
  uint16 payload_length;
  opaque payload[HeartbeatMessage.payload_length];
  opaque padding[padding_length];
} HeartbeatMessage;

Неправильная обработка поля payload_length и вызвала ошибку Heartbleed.

Однако весь этот пакет инкапсулирован внутри другой записи, имеющей собственную длину полезной нагрузки. , выглядит примерно так:

 struct {
      ContentType type;
      ProtocolVersion version;
      uint16 length;
      opaque fragment[TLSPlaintext.length];
  } TLSPlaintext;

Структура HeartbeatMessage размещается внутри вышеуказанного fragment.

Таким образом, один полный «пакет» TLS может быть обработан, когда данные в соответствии с полем length здесь получены, но во внутреннем сообщении Heartbeat openssl не удалось проверить его payload_length.

Вот скриншот захвата пакета, на котором вы можете видеть, что внешняя длина 3 указывает длину «пакета», а внутренняя (неправильная) длина полезной нагрузки 16384 — это то, что вызвало эксплойт, поскольку openssl не смог проверить это на соответствие фактическая полученная длина пакета.

скриншот Wireshark пакета пульса

Конечно, аналогичная осторожность должна быть проявлена ​​при обработке поля length этой внешней записи, вы действительно хотите убедиться, что вы действительно получили length данные, прежде чем начать обрабатывать/анализировать содержимое пакета.

Также обратите внимание, что нет особой корреляции между чтением сокета и сегментами TCP, 1 чтение сокета может прочитать много сегментов или только часть сегмента. Для приложения TCP — это просто поток байтов, и одно чтение сокета может прочитать только половину поля длины одного пакета TLSPlaintext или несколько целых пакетов TLSPlaintext.

person nos    schedule 18.04.2014

В статье Heartbleed в Википедии довольно хорошо объясняется эксплойт. Перефразируя, RFC 6520 является расширением протокола TLS для сообщения «Heartbeat Request» (своего рода механизм проверки активности). Запрос состоит из поля длиной 16 бит и сообщения для сопоставления, а ответ должен повторять предоставленное сообщение. В реализации OpenSSL есть ошибка, из-за которой не выполняется проверка границ. Он принимает это поле длины по номинальной стоимости, не проверяя, не считывается ли оно во что-то, чего быть не должно (т. е. за границу, указанную в SSL-записи). Эксплойт возникает, когда «Запрос Heartbeat» имеет неверный формат с небольшим сообщением, но большим значением в поле длины. Это позволяет вредоносному клиенту попытаться прочитать с сервера информацию, которая в противном случае не была бы прочитана (эта информация вернется в ответе). То, что на самом деле содержится в этой информации, зависит от того, как что-то хранится в памяти на сервере, но возможность чтения конфиденциальной информации считается катастрофической для OpenSSL, который должен обеспечивать безопасную платформу.

person jxh    schedule 18.04.2014
comment
Но разве получающий OpenSSL неправильно сформированного запроса не должен ждать, пока он не получит все байты, как указано в поле длины? Что мешает OpenSSL ждать, чтобы прочитать столько байтов, сколько указано в поле длины? Один TCP recv() не гарантирует получение всего пакета, верно? - person Prabhu; 18.04.2014
comment
Именно прабху. Я не думаю, что jxh отвечает на вопрос здесь. TCP не работает ни с какой концепцией пакетов. Это просто поток данных. - person Niels B.; 18.04.2014
comment
@Prabhu: сообщение запроса сердцебиения похоже на любое другое сообщение SSL, оно инкапсулировано в запись SSL. При обработке записи SSL обнаруживается запрос Heartbeat, который интерпретируется ошибочно. Исправление состоит в том, чтобы убедиться, что длина запроса Heartbeat не превышает длину записи SSL. - person jxh; 19.04.2014