Init. commit
This commit is contained in:
66
stego-summer-vacations/solve/solver.py
Normal file
66
stego-summer-vacations/solve/solver.py
Normal 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-символы (коды 32–126)
|
||||
# Всё остальное — признак конца флага или мусорных данных
|
||||
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}")
|
||||
Reference in New Issue
Block a user