Bug2Lab · Secure Code · Java / Serialization

Небезопасная десериализация Java-объектов

Приложение принимает сериализованный объект (например, Base64), десериализует его через ObjectInputStream и верит ему. Атакующий может подсунуть объект с вредоносным кодом и добиться RCE.

1
Как выглядит атака
Атакующий шлёт специально сконструированный сериализованный объект в /api/restore. Приложение десериализует его и выполняет вредоносный код при readObject().
POST /api/restore
Body: base64(...serialized payload...)
200 OK
{ "status":"restored" }
2
Почему это стало возможным
Код слепо десериализует входящий объект. Нет вайтлиста разрешённых типов, нет валидации.
Проблемный код
40@PostMapping("/api/restore")
41public String restore(@RequestBody String rawBase64) throws Exception {
42 byte[] data = Base64.getDecoder().decode(rawBase64);
43 ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data));
44 Object obj = ois.readObject(); // ❌ может быть что угодно с gadget-цепочкой
45 // ...
46 return "{\"status\":\"restored\"}";
47}
3
Как это чинится правильно
Не принимать «сырую Java-сериализацию» вообще. Использовать безопасные форматы (JSON DTO) и жёстко маппить поля.
Исправленный паттерн
40@PostMapping("/api/restore")
41public String restore(@RequestBody RestoreRequest dto) {
42 // ✅ Чётко описанный DTO, Jackson маппит только ожидаемые поля
43 service.restore(dto.getSnapshotId(), dto.getData());
44 return "{\"status\":\"restored\"}";
45}

bug2regressРегрессионный тест

Тест отправляет заведомо «левый» сериализованный объект. Если сервис всё ещё пытается десериализовать через ObjectInputStream и отвечает 200 — билд стопаем. Ожидаем 400/403.

#!/bin/bash
# deserialization-check.sh
MALICIOUS=$(cat malicious_payload.base64)

STATUS=$(curl -s -o /tmp/resp.json -w "%{http_code}" \
  -X POST \
  -H "Content-Type: text/plain" \
  --data "$MALICIOUS" \
  https://staging.example.internal/api/restore)

if [ "$STATUS" = "200" ]; then
  echo "[BLOCK] Небезопасная десериализация всё ещё включена"
  exit 1
fi

echo "[OK] Сырая десериализация объектов больше не допускается (HTTP $STATUS)"
exit 0

Это закрывает путь к удалённому выполнению кода внутри вашего сервиса.

Проверка пониманияЧто было критичным?

Стандарт:мы не принимаем "сырые сериализованные Java-объекты" от клиента. Только валидированные DTO.

Теория (по желанию) Сырая десериализация = прямой вход в ваш процесс