Files
2026-09-17 00:50:07 +03:00

2.7 KiB
Raw Permalink Blame History

RailAnnot

PWN medium

RailAnnot обрабатывает служебные аннотации PDF-нарядов. В раздатке есть ELF railannot. У объекта аннотации 16-битный счётчик ссылок, а у страницы — отдельный указатель на него. Если счётчик обнулится при переполнении, объект освободится, но указатель страницы продолжит ссылаться на него.

Решение

Создаём аннотацию через 1) load annotation: refs = 1. Затем 2) attach annotation to page добавляет вторую ссылку, и refs становится равен 2.

Пункт 3) replay stream references прибавляет произвольное n:

ann->refs = (uint16_t)(ann->refs + n);

При нуле объект освобождается, но page_ref не обнуляется. Передаём 65534 и получаем 2 + 65534 = 65536, что в uint16_t превращается в 0. Аннотация удалена, страница продолжает держать висячий указатель.

В 4) allocate replacement cache object выделяется блок того же размера. Заполняем его поддельной аннотацией:

import struct

payload = struct.pack("<HHI", 0, 7, 0x414e4e52)
payload += b"sealed depot note".ljust(64, b"\x00")
payload += struct.pack("<I", 0x5241494c)

Первые два поля — refs и id, затем magic, 64 байта текста и sealed. Размер получается 76 байт, а sealed стоит на смещении 72.

Выбираем 4) allocate replacement cache object. На запрос replacement bytes: отправляем строку 76, затем на payload: передаём 76 байт поддельной аннотации без добавленного перевода строки.

Освобождённый блок переиспользуется, и page_ref указывает на поддельную структуру. При выборе 5) render sealed annotation сервис проверяет поля magic и sealed. Они содержат ожидаемые значения, поэтому сервис выводит флаг.

Солвер.

Флаг

caplag{annotation_refcount_wrapped_into_the_depot_note}