2.7 KiB
RailAnnot
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}