# Reverse 10 — AESвариус

## Флаг

- **Флаг:** `vsosh{V3ry_345y_isnt_it?:)}`

---

## Анализ

Участнику выдаётся бинарь `safe_packer` и зашифрованный файл `flag_enc`.

Программа принимает команду `encrypt`/`decrypt`, файл и строку-ключ.  
Ключ преобразуется через `process_enc()` в 32-байтный AES-ключ и 16-байтный IV,
после чего вызывается `AES_CTR_xcrypt_buffer()` из библиотеки `tiny-AES-c`.

### Баг 1 — утечка ключевого потока

В `process_file()` цикл `do-while` начинает работу **до первого** `fread`:

```c
do {
    AES_CTR_xcrypt_buffer(&ctx, buf, 256);  // buf = {0,0,...,0}
    fwrite(buf, 1, 256, op);               // пишет XOR(0, keystream) = keystream
    memset(buf, 0, 256);
} while ((bytes_read = fread(buf, 1, 256, fp)) > 0);
```

При первой итерации `buf` — нулевой, поэтому в начало файла записывается
чистый ключевой поток (256 байт).

### Баг 2 — счётчик CTR никогда не меняется

В реализации `AES_CTR_xcrypt_buffer` IV не инкрементируется между 16-байтными блоками.
Каждые 16 байт — это AES-шифрование **одного и того же** IV.

В результате весь ключевой поток — это один и тот же 16-байтный блок, повторённый по кругу.

Это можно проверить: первые 256 байт `flag_enc` — это `key[0:16]` × 16.

## Решение

1. Взять первые 16 байт `flag_enc` — это и есть ключевой блок.
2. XOR остатка файла с этим блоком циклически.
3. Получить PNG с флагом.

Скрипт решения:

```python
data = open("flag_enc", "rb").read()
key  = data[:16]
dec  = bytes(data[256 + i] ^ key[i % 16] for i in range(len(data) - 256))
open("flag.png", "wb").write(dec[:dec.find(b"IEND") + 8])
```

Флаг: `vsosh{V3ry_345y_isnt_it?:)}`