\n\n\n\n\n\n\n\n\n\n\n
flawopen.com/Симуляторы/Heartbleed Buffer Overread
Интерактивная визуальная модель памяти в браузере, демонстрирующая чтение за пределами буфера кучи (heap overread) из-за отсутствия проверки длины пакета TLS Heartbeat.
Представьте, что вы говорите дрессированному попугаю слово из 4 букв «BIRD» и просите: «Повтори это слово, но сделай ответ длиной в 64 000 букв». Попугай выкрикивает «BIRD», а затем начинает непрерывно выдавать следующие 63 996 символов из своей оперативной памяти — включая секретные пароли, приватные ключи SSL и финансовые данные других посетителей. В уязвимости Heartbleed OpenSSL слепо доверял заявленной клиентом длине, не проверяя реальный размер пакета, и копировал байты серверной памяти прямо злоумышленнику.
Злоумышленник отправляет запрос с телом в 1 байт ('A'), но в поле длины указывает 65 535 байт (0xFFFF).
OpenSSL считывает заявленный размер через n2s(p, payload) без проверки условия 1 + 2 + payload + 16 <= rrec.length.
Сервер выделяет в куче буфер размером 64 КБ, полностью полагаясь на фиктивные данные клиента.
Вызов memcpy() считывает 64 КБ данных за пределами входящего байта, сливая приватные ключи RSA и токены сессий.
/* Чтение 16-битной длины напрямую из пакета без проверки */
n2s(p, payload);
pl = p;
/* Выделение буфера ответа на основе размера, заявленного клиентом */
buffer = OPENSSL_malloc(1 + 2 + payload + padding);
bp = buffer;
/* ОШИБКА: Копирует до 64 КБ соседней памяти кучи сервера! */
memcpy(bp, pl, payload);
r = ssl3_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, 3 + payload + padding);
/* Чтение 16-битной длины из пакета */
n2s(p, payload);
pl = p;
/* ИСПРАВЛЕНИЕ: Проверяем, что заявленная длина не превышает реально полученную запись */
if (1 + 2 + payload + 16 > s->s3->rrec.length)
return 0; /* Бесшумно отбрасываем искаженный пакет */
buffer = OPENSSL_malloc(1 + 2 + payload + padding);
bp = buffer;
memcpy(bp, pl, payload);