2.6 KiB
HeifTrack
HeifTrack проверяет последовательности кадров с камер. Он загружает chunk, привязывает его к воспроизведению и сверяет таблицы. В ELF heiftrack обнаруживаем, что ошибочный chunk удаляется, но воспроизведение продолжает ссылаться на него.
Решение
Chunk занимает 108 байт:
struct chunk {
uint32_t magic;
uint32_t frames;
char label[32];
uint32_t approved;
char pad[64];
};
Экспорт проверяет два поля по указателю playback: magic == 0x48454946 и approved == 0x54524143. У обычного загруженного объекта approved равен нулю.
Сначала выбираем 1) load chunk, затем 2) bind track. Теперь и chunk0, и playback указывают на один объект. В 3) validate tables вводим несовпадающие значения 1, 2, 3. Валидация делает free(chunk0) и обнуляет chunk0, но про playback забывает. Получаем use-after-free.
Остаётся занять освободившуюся память своими данными. Пункт 4) add metadata item выделяет блок того же размера, 108 байт. Готовим поддельный chunk:
import struct
payload = struct.pack("<II", 0x48454946, 9)
payload += b"approved-track".ljust(32, b"\x00")
payload += struct.pack("<I", 0x54524143)
payload = payload.ljust(108, b"\x00")
Поле approved оказывается на смещении 40, как и у настоящего объекта. Выбираем 4) add metadata item, на запрос metadata bytes: передаём строку 108, затем на payload: отправляем 108 байт payload без добавленного перевода строки. Аллокатор переиспользует освобождённый блок, поэтому висячий playback теперь указывает на поддельный объект.
Выбираем 5) verify playback. Обе проверки проходят, и сервис выводит флаг.
Флаг
caplag{conflicting_track_tables_kept_the_chunk_alive}