Init. commit

This commit is contained in:
Caplag
2026-04-22 10:42:16 +03:00
commit 98e51ca58b
35 changed files with 2371 additions and 0 deletions

View File

@@ -0,0 +1,30 @@
<h1 align="center">Summer Vacations</h1>
<p align="center">
<img src="https://img.shields.io/badge/category-Stego-blueviolet" alt="Stego"/>
<img src="https://img.shields.io/badge/points-799-yellow" alt="799 pts"/>
</p>
На входе — картинка `vacation.png`. Если провести классический LSB-скан по красному каналу, тогда быстро находится читаемая строка, похожая на флаг — и это ловушка. Настоящий флаг расположен в младшем бите альфа-канала.
## Решение
Открываем картинку в RGBA (принудительно, чтобы гарантированно получить альфа-канал) и проходим по пикселям в растровом порядке (слева направо, сверху вниз). Для каждого пикселя проверяем условие:
```text
(R * G * B) % 7 == 3
```
Только те, что прошли фильтр, несут бит данных — и из них забираем младший бит альфа-канала:
```python
if (r * g * b) % 7 == 3:
bits.append(a & 1)
```
Накопленные биты группируем по 8 (старший бит первым) и собираем в байты. Нулевой байт — маркер конца данных, аналог `\0`-терминатора в C. Принимаем только печатаемые ASCII (`0x20``0x7E`); всё остальное — либо конец флага, либо мусор.
Готовый солвер — [`solve/solver.py`](solve/solver.py).
## Флаг
`caplag{p4t13nc3_r3v34ls_truth}`

View File

@@ -0,0 +1,66 @@
#!/usr/bin/env python3
"""
Правильный флаг спрятан в младшем бите (LSB) альфа-канала пикселей,
где (R*G*B) % 7 == 3.
Ложный флаг находится в LSB красного канала.
Шаги:
1. Открыть изображение в режиме RGBA
2. Обойти пиксели в растровом порядке (слева направо, сверху вниз)
3. Для каждого пикселя проверить условие (R*G*B) % 7 == 3
4. Если условие выполнено — извлечь младший бит альфа-канала
5. Декодировать каждые 8 бит в один ASCII-символ
"""
import sys, os
from PIL import Image
def solve(filepath: str) -> str:
# Открываем изображение и принудительно переводим в режим RGBA
# (чтобы гарантированно получить альфа-канал)
img = Image.open(filepath).convert('RGBA')
pixels = img.load()
# Извлекаем младшие биты альфа-канала из подходящих пикселей
bits = []
for y in range(img.height):
for x in range(img.width):
r, g, b, a = pixels[x, y]
# Условие фильтрации: произведение RGB по модулю 7 равно 3
# Это нестандартный критерий, чтобы скрыть данные от обычных стего-сканеров
if (r * g * b) % 7 == 3:
# Берём только последний (младший) бит альфа-канала
bits.append(a & 1)
print(f"[*] Найдено {len(bits)} подходящих пикселей (бит)")
# Декодируем последовательность бит в строку флага
flag = ''
for i in range(0, len(bits) - 7, 8):
# Собираем байт из 8 последовательных бит (старший бит — первый)
byte_val = 0
for j in range(8):
byte_val = (byte_val << 1) | bits[i + j]
# Нулевой байт означает конец данных (аналог нуль-терминатора в C)
if byte_val == 0:
break
# Принимаем только печатаемые ASCII-символы (коды 32126)
# Всё остальное — признак конца флага или мусорных данных
if 32 <= byte_val <= 126:
flag += chr(byte_val)
else:
break
return flag
if __name__ == '__main__':
img_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),
'..', 'public', 'vacation.png')
if len(sys.argv) > 1:
img_path = sys.argv[1]
flag = solve(img_path)
print(f"[+] Флаг: {flag}")