Новоразкрита уязвимост в OpenSSL, наречена „HollowByte“, позволява на отдалечен атакуващ без автентификация да предизвика състояние на отказ от услуга (DoS), използвайки злонамерен код с размер от едва 11 байта.
Открит от Red Team екипа на Okta, този дефект експлоатира начина, по който OpenSSL предварително заделя памет по време на TLS ръкостискането (handshake), принуждавайки сървърите да резервират огромни части от паметта, преди изобщо да е извършена каквато и да е автентификация.
Уязвимост „HollowByte“ в OpenSSL
Всяко TLS ръкостискане започва с ClientHello съобщение, обвито в запис, съдържащ 4-байтов хедър, който декларира размера на тялото на входящото съобщение. В по-старите версии на OpenSSL библиотеката заделя буфер за приемане изцяло въз основа на тази декларирана от атакуващия дължина, преди да са пристигнали каквито и да било реални данни.
Когато пристигне специално подготвен злонамерен код от 11 байта, TLS машината на състоянията прочита хедъра и задейства следната верига от заделяне на памет без валидиране: Read Header → grow_init_buf() → OPENSSL_clear_realloc() → malloc(attacker_size).
Тъй като на този етап не се извършва валидиране, един-единствен злонамерен пакет може да принуди функцията malloc() да задели до 131 KB само въз основа на твърдението на атакуващия. След това работната нишка блокира за неопределено време, чакайки данни, които никога не пристигат.
Класическите атаки за изчерпване на връзките като Slowloris разчитат на поддържане на отворени връзки, за да оставят сървърните нишки без ресурси. HollowByte утежнява това с проблем с фрагментацията на паметта, коренящ се в начина, по който glibc управлява освободената памет.
Когато връзката на атакуващия прекъсне, OpenSSL освобождава буфера, но glibc не връща веднага малките до средни заделени обеми към операционната система; тя ги запазва за потенциална повторна употреба.
Чрез стартиране на вълни от връзки с произволно заявени размери, атакуващите пречат на алокатора да използва повторно тези освободени сегменти, което кара постоянния размер на набора (RSS) на сървъра да нараства непрекъснато и постоянно, дори след като атакуващият се разкачи. Единственото решение е рестартиране на самия процес.
Тестовете на Okta Red Team върху непачвана инфраструктура на OpenSSL, работеща с NGINX, разкриват сериозни последици:
- В среда с 1 GB RAM сървърът е бил прекратен от OOM-killer (out-of-memory) след натрупване на 547 MB замразена, фрагментирана памет.
- В среда с 16 GB RAM атаката е блокирала 25% от общата системна памет, като същевременно е останала под стандартните лимити за връзки — което означава, че типичните защити за ограничаване на връзките не успяват да я спрат.
Тъй като OpenSSL стои в основата на огромна част от интернет инфраструктурата, обхватът на въздействие на уязвимостта се разпростира до уеб сървъри като Apache и NGINX, среди за изпълнение на езици за програмиране, включително Node.js, Python, Ruby и PHP, както и бази данни като MySQL и PostgreSQL.
OpenSSL разреши проблема чрез преминаване към постепенно нарастване на буфера, внедрено чрез pull requests #30792, #30793 и #30794. Вместо да се доверява сляпо на твърдението в хедъра, OpenSSL сега разширява буфера само когато байтовете действително пристигат по мрежата — което означава, че празната заявка не струва нищо на сървъра.
Корекцията беше тихо внедрена в OpenSSL v4.0.1, с неафиширани бекпортове към 3.6.3, 3.5.7, 3.4.6 и 3.0.21. Прави впечатление, че OpenSSL третира това по-скоро като подобрение на защитата (hardening), отколкото да издаде официален CVE бюлетин — модел, наблюдаван и при други скорошни разкрития на OpenSSL, където проблеми от клас DoS се отстраняват без високопрофилни CVE обозначения.
Поради факта, че HollowByte получи тихо отстраняване на уязвимостта вместо CVE, много организации може да не я засекат чрез стандартно сканиране за уязвимости. Като се има предвид широкото разпространение на OpenSSL в уеб сървъри, среди за изпълнение и бази данни, екипите по сигурността трябва да третират това като приоритетно инсталиране на корекции за сигурност, независимо от липсата на CVE статус.
- Обновете незабавно до OpenSSL 4.0.1 или съответната бекпортната версия (3.6.3, 3.5.7, 3.4.6 или 3.0.21).
- Одитирайте вградените OpenSSL версии в средите за изпълнение (Node.js, Python, Ruby, PHP), тъй като корекциите на ниво операционна система няма да поправят пакетираните копия.
- Наблюдавайте тенденциите на RSS паметта на сървърите, прекратяващи TLS сесии, за признаци на постепенно, необяснимо раздуване на паметта, съвместимо с атаки за фрагментиране.