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

41 lines
2.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<h1 align="center">PulseWidth</h1>
<p align="center">
<img src="https://img.shields.io/badge/category-PWN-blueviolet" alt="PWN"/>
<img src="https://img.shields.io/badge/difficulty-easy-brightgreen" alt="easy"/>
</p>
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:
```python
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` проверяет уже подменённые поля и печатает флаг.
[Солвер](solve/solve.py).
## Флаг
`caplag{len_folded_into_live_capability}`