О софте:
ENet мощная библиотека обработки UDP соединений с открытым исходным
кодом. Именно этот программный продукт используется в играх типа Cube,
Sauerbraten, Duke3d_w32 и так далее.
Уязвимости:
1) Неверный доступ к памяти.
ENet использует 32 битный номер для почти всех параметров в его пакете,
например фрагментах значений, размера данных, временные задержки, номера
вызовов и другие.
Каждый пакет, полученный из библиотеки (enet_host_service) проверяется
функцией enet_protocol_handle_incoming_commands.
Эта функция использует указатель, который указывает на текущий команды,
каждый пакет может нести одну или несколько команд, которые описываються
в запросе соединения, подтверждения, фрагменте, сообщения и так далее.
Инструкция, которая проверяет эти указатели, избегает, что бы указатель
по полученному пакету, мог уклоняться через большой
header.commandLength параметр.
После проверки currentData укажет на недопустимую зону памяти и когда
цикл продолжиться на следующей операции - программа зависнет.
64-битные процессоры не уязвимые.
Фрагмент protocol.c:
...
currentData = host -> receivedData + sizeof (ENetProtocolHeader);
while (commandCount > 0 &&
currentData < & host -> receivedData [host ->
receivedDataLength])
{
command = (ENetProtocol *) currentData;
if (currentData + sizeof (ENetProtocolCommandHeader) > & host ->
receivedData [host -> receivedDataLength])
return 0;
command -> header.commandLength = ENET_NET_TO_HOST_32 (command ->
header.commandLength);
if (currentData + command -> header.commandLength > & host ->
receivedData [host -> receivedDataLength])
return 0;
-- commandCount;
currentData += command -> header.commandLength;
...
2) Аварийное завершение работы.
ENet поддерживает обработку фрагментов и имеет обыкновение создавать
сообщения большие, чем MTU Пользователя.
Когда фрагмент получен, библиотека распределяет полный размер сообщения
в памяти, так что это может легко восстанавливать все последующие
фрагменты в этом буфере.
Если полный размер данных, указанный нападавшим не может быть
распределен, происходит аварийное прекращение работы запросов abort() и
вся программа заканчивается.
Фрагмент protocol.c:
...
startCommand = enet_peer_queue_incoming_command (peer,
& hostCommand,
enet_packet_create (NULL, totalLength, ENET_PACKET_FLAG_RELIABLE),
fragmentCount);