Files
Serdtse-Sysoly/finals/pulsewidth-pwn-easy/WRITEUP.md
T
2026-09-17 00:50:07 +03:00

2.1 KiB
Raw Blame History

PulseWidth

PWN easy

PulseWidth принимает телеметрию промышленных датчиков и выдаёт закрытый экспорт только с нужными правами сессии. В раздатке есть ELF pulsewidth. При проверке длины кадра ограничение применяют к 8-битному значению, а чтение использует полное число байт.

Решение

В ingest_frame() сравнивают (uint8_t)n с размером scratch[64], затем вызывают read_exact(session_state.scratch, n). Старшие биты длины при проверке теряются.

Берём n = 320. После приведения к uint8_t остаётся 64, поэтому лимит пройден. А чтение запишет все 320 байт, из которых 256 окажутся за пределами scratch-буфера.

Сразу за ним лежат поля сессии:

Смещение Поле Нужное значение
64 role, 4 байта 0x4341504c
68 export_lane, 4 байта 0x45585054
72 audit_cookie, 8 байт 0x2605061337c0ffee

Собираем кадр в little-endian:

import struct

payload = b"A" * 64
payload += struct.pack("<IIQ", 0x4341504c, 0x45585054, 0x2605061337c0ffee)
payload = payload.ljust(320, b"B")

В 1) ingest pulse frame указываем длину 320 и передаём payload. Кадр перезаписывает поля role, export_lane и audit_cookie значениями, необходимыми для экспорта. Пункт 3) export sealed bundle проверяет уже подменённые поля и печатает флаг.

Солвер.

Флаг

caplag{len_folded_into_live_capability}