TagPreview

Crypto easy

Сервис хранит запечатанную заметку и умеет проверять её целостность. При успешной проверке он подтверждает приём, но текст не показывает. Для отклонённых записей сервис возвращает поле `preview`. Проверяем его содержимое. ## Решение Забираем исходную запись: ```bash curl -sS http://:31359/sealed-note -o note.bin ``` Публичный клиент на неизменённой записи получает `status=accepted` без plaintext: ```bash python3 public/client.py http://:31359 ``` В `inspect_record()` сначала вычисляется открытый текст, затем проверяется authentication tag. Сама расшифровка до проверки ещё не раскрывает данные клиенту. Ошибка находится в ветке отказа. При несовпадении тега функция возвращает эти байты в поле `preview`. Последние 16 байт записи — тег. Меняем один его байт, не трогая шифротекст, чтобы расшифровка осталась прежней, а проверка провалилась: ```python from pathlib import Path record = bytearray(Path("note.bin").read_bytes()) record[-1] ^= 1 Path("tampered.bin").write_bytes(record) ``` Отправляем подготовленный `tampered.bin` в `POST /inspect` с `Content-Type: application/octet-stream`. ```bash curl -sS --data-binary @tampered.bin \ -H 'Content-Type: application/octet-stream' \ 'http://:31359/inspect' ``` При несовпадении тега обработчик возвращает открытый текст вместе с флагом в поле `preview`. Одной испорченной записи достаточно, поскольку утечка происходит непосредственно в обработчике ошибки. > Расшифрованные байты до проверки тега нельзя отдавать вызывающему коду. Здесь проверка обнаружила повреждение, но обработчик ошибки всё равно раскрыл содержимое заметки. [Солвер](solve/solve.py). ## Флаг `caplag{tag_failure_previewed_the_plaintext}`