Init. import
This commit is contained in:
18
GAME/nas/Stegano/README.md
Normal file
18
GAME/nas/Stegano/README.md
Normal file
@@ -0,0 +1,18 @@
|
||||
GameStegoAudio | Stego | Medium?
|
||||
|
||||
## Автор
|
||||
instanc3:@instanc3
|
||||
|
||||
## Информация для участников
|
||||
|
||||
## Выдать участникам
|
||||
Аудио файл: some_secret.wav
|
||||
|
||||
## Решение
|
||||
1. Понять, что информация скрыта в правом канале → проверить распределение LSB по каналам/участкам.
|
||||
2. Замечаем, что данные начинаются после ~1 с и идут через один.
|
||||
3. Считать LSB правого канала с skip=1s, step=2, собрать в байты (MSB→LSB).
|
||||
4. Увидеть заголовок STAG, прочитать длину и CRC, взять полезную нагрузку, zlib-decompress → получить caplag{...}.
|
||||
|
||||
## Флаг
|
||||
`caplag{gam3_au1d0_st3g0_1s_d0n3}`
|
||||
68
GAME/nas/Stegano/stego_task_solve.py
Normal file
68
GAME/nas/Stegano/stego_task_solve.py
Normal file
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import wave
|
||||
import struct
|
||||
import zlib
|
||||
import numpy as np
|
||||
|
||||
SR = 44100
|
||||
SKIP_SEC = 1.0
|
||||
STEP = 2
|
||||
IN_WAV = "some_secret.wav"
|
||||
|
||||
def read_wav_int16(path: str):
|
||||
with wave.open(path, "rb") as wf:
|
||||
assert wf.getnchannels() == 2
|
||||
assert wf.getsampwidth() == 2
|
||||
sr = wf.getframerate()
|
||||
frames = wf.readframes(wf.getnframes())
|
||||
arr = np.frombuffer(frames, dtype=np.int16).reshape(-1, 2)
|
||||
return sr, arr
|
||||
|
||||
def bits_to_bytes_big_endian(bits: np.ndarray) -> bytes:
|
||||
# Длина должна быть кратна 8
|
||||
n = (bits.size + 7) // 8 * 8
|
||||
if n != bits.size:
|
||||
bits = np.pad(bits, (0, n - bits.size), constant_values=0)
|
||||
by = np.packbits(bits.astype(np.uint8), bitorder='big').tobytes()
|
||||
return by
|
||||
|
||||
def extract_header_and_length(right: np.ndarray, sr: int):
|
||||
skip = int(sr * SKIP_SEC)
|
||||
# Считываем первые 12 байт (заголовок: 4 + 4 + 4)
|
||||
header_bits_count = 12 * 8
|
||||
idxs = skip + np.arange(header_bits_count) * STEP
|
||||
bits = (right[idxs] & 1).astype(np.uint8)
|
||||
header = bits_to_bytes_big_endian(bits)
|
||||
magic = header[:4]
|
||||
if magic != b"STAG":
|
||||
raise ValueError("Магия заголовка не совпала — это не тот контейнер.")
|
||||
length = struct.unpack(">I", header[4:8])[0]
|
||||
crc = struct.unpack(">I", header[8:12])[0]
|
||||
return length, crc
|
||||
|
||||
def extract_all(sr: int, stereo: np.ndarray):
|
||||
right = stereo[:, 1]
|
||||
length, crc_expected = extract_header_and_length(right, sr)
|
||||
total_bytes = 12 + length
|
||||
total_bits = total_bytes * 8
|
||||
skip = int(sr * SKIP_SEC)
|
||||
idxs = skip + np.arange(total_bits) * STEP
|
||||
bits = (right[idxs] & 1).astype(np.uint8)
|
||||
data = bits_to_bytes_big_endian(bits)
|
||||
header = data[:12]
|
||||
payload = data[12:12+length]
|
||||
crc_actual = zlib.crc32(payload) & 0xFFFFFFFF
|
||||
if crc_actual != crc_expected:
|
||||
raise ValueError("CRC не сошлась — данные повреждены или неверные параметры извлечения.")
|
||||
flag = zlib.decompress(payload).decode("utf-8")
|
||||
return flag
|
||||
|
||||
def main():
|
||||
sr, stereo = read_wav_int16(IN_WAV)
|
||||
flag = extract_all(sr, stereo)
|
||||
print("[+] DATA [ ", flag, " ]")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
70
GAME/nas/writeup.md
Normal file
70
GAME/nas/writeup.md
Normal file
@@ -0,0 +1,70 @@
|
||||
# Writeup для NAS (русская версия)
|
||||
|
||||
## Цель
|
||||
Зайти в хранилище
|
||||
|
||||
## 1 Задание Посчитать пароль админа и войти
|
||||
Пароль админа — первые 12 символов:
|
||||
```
|
||||
sha1(KETTLE_PROOF + ":" + PRINTER_PROOF) находим из исходников репозитория
|
||||
Входим
|
||||
|
||||
```
|
||||
|
||||
Пример:
|
||||
```python
|
||||
import hashlib
|
||||
|
||||
admin_pass = hashlib.sha1(f"{KETTLE_PROOF}:{PRINTER_PROOF}".encode()).hexdigest()[:12]
|
||||
print(admin_pass)
|
||||
```
|
||||
|
||||
Логин: `/login` с:
|
||||
```
|
||||
username=admin
|
||||
password=<admin_pass>
|
||||
```
|
||||
Сохраните cookie `sid` из ответа.
|
||||
Получаем доступ к файлу .wav
|
||||
Дальше решение из папки Stegano.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 2 задание Сковать bearer JWT и забрать финальный флаг
|
||||
`/admin/flag` требует:
|
||||
- cookie `sid` (админская сессия)
|
||||
- `Authorization: Bearer <jwt>`
|
||||
|
||||
Ограничения на payload:
|
||||
- `role: "admin"`
|
||||
- `kpf: <KETTLE_PROOF>`
|
||||
- `aud: "nas-admin"`
|
||||
- `iat`: текущее UNIX‑время (допуск примерно ±120 сек)
|
||||
|
||||
Пример:
|
||||
```python
|
||||
import time, jwt
|
||||
|
||||
payload = {
|
||||
"role": "admin",
|
||||
"kpf": KETTLE_PROOF,
|
||||
"aud": "nas-admin",
|
||||
"iat": int(time.time()),
|
||||
}
|
||||
token = jwt.encode(payload, JWT_SECRET, algorithm="HS256")
|
||||
print(token)
|
||||
```
|
||||
|
||||
Запрос:
|
||||
```
|
||||
GET /admin/flag
|
||||
Cookie: sid=<sid>
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
В ответе — финальный флаг.
|
||||
Reference in New Issue
Block a user