-
Notifications
You must be signed in to change notification settings - Fork 4
Проверка слуха
- Категория: Stegano
- Стоимость: 500
- Автор: Владимир Черепанов
- Репозиторий
Мы записали звуки, исходящие из аномалии.
Возможно, где-то между ними спрятана секретная информация.
sound.wav
- sound.wav
Откроем этот файл в Audacity.
Звуковой файл состоит из двух каналов (левого и правого), визуально они ничем не отличаются. При прослушивании не слышно и намёка на флаг, поэтому нужно заглянуть глубже внутрь файла.
Для этого воспользуемся Python 3 и библиотекой wave для него. Сначала посмотрим общую информацию, чтобы понять, как именно сохранён звук.
>>> import wave
>>> wav = wave.open('sound.wav', 'rb')
>>> wav.getparams()
_wave_params(nchannels=2, sampwidth=2, framerate=8000, nframes=962154, comptype='NONE', compname='not compressed')
>>>
Что это значит? Звуковой файл содержит два канала (левый+правый), в каждом канале хранится 962154 сэмпла, в каждом сэмпле лежит два байта, отвечающих за амплитуду (громкость). В итоге, потоковые данные занимают 962154 * 2 * 2 = 3848616 байтов. В файле отсутствует сжатие, а частота дискретизации нам сейчас не нужна.
Чтобы понять, что всё это такое, нужно вспомнить, как вообще выглядит оцифрованный звук.
Сам звук представляет из себя волну, которая распространяется по воздуху (или другим средам). Именно эту волну улавливает наше ухо и передаёт в мозг. В природе такие волны непрерывны и физикой описываются как непрерывные функции, но компьютер - дискретное устройство, а его память конечна. Поэтому для представления звука в компьютере функцию волны дискретизируют - то есть, грубо говоря, измеряют значение её амплитуды через некоторые интервалы времени. Частота, с которой это делают, и называется частотой дискретизации.
После этого дискретные значения нужно как-то сохранить. Для этого часто применяют сжатие, например, чтобы срезать звуки, которые человек вообще не способен услышать. В нашем случае формат wav хранит звук вообще без сжатия, то есть таким, каким он был записан (или сгенерирован).
Примерно вот так выглядят данные, лежащие внутри wav:
[ __ __ | __ __ ] - [ __ __ | __ __ ] - [ __ __ | __ __ ] - ...
2 bytes + 2 bytes 2 bytes + 2 bytes 2 bytes + 2 bytes
left right left right left right
Что означают эти два байта в амплитуде? Они нужны, чтобы представить в памяти компьютера число, большее, чем может вместить в себя один байт. В 8 бит можно записать 2^8 = 256 различных чисел, а в 16 бит (2 байта) умещаются 2^16 = 256 * 256 = 65536 чисел.
Стоит учесть, что байты хранятся в обратном порядке: сначала записывается младший байт, потом старший. Такой способ записи называется little-endian. Получается, что при незначительном изменении амплитуды скорее изменится первый байт, чем второй.
Мы разобрались со структурой контейнера, чтобы проверить кое-что важное по поводу нашего sound.wav: действительно ли оба канала одинаковы, или же у них есть какие-то различия. Для этого напишем скрипт на питоне, который будет сравнивать каждый первый байт потока с каждым третьим (младшие байты амплитуд обоих каналов). Этого должно быть достаточно, чтобы заметить изменения, если они есть.
>>> data = wav.readframes(962154)
>>> for i in range(0, len(data), 4):
... assert data[i] == data[i+2], i
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
AssertionError: 2580
Так и есть, каналы различаются. Сейчас нужно догадаться, как следует понимать эту разницу.
Можно попытаться применить LSB или другие техники стеганографии, но они не сработают, потому что флаг в этом задании спрятан в звуке, который нужно услышать. А сам звук - в разнице между каналами.
В Audacity есть много удобных функций, среди них - те, которые могут нам помочь. Для начала разделим трек на две дорожки с помощью стрелки вниз около названия -> Split Stereo to Mono. Потом инвертируем один из каналов, выделив его и применив Effect -> Invert.
Что мы сделали? Если кратко, то мы умножили численные значения амплитуд на -1, то есть первернули звуковую волну вверх ногами. Теперь выберем Track -> Mix and Render, это обратно соединит две дорожки в одну и сложит амплитуды.
В итоге у нас останется только разница между каналами. Но она настолько незаметная, что мы не только не услышим флаг, мы его даже не увидим в Audacity. Поэтому применим Effect -> Normalize, и нам осталось только прослушать флаг.
В эксплоите есть решение, написанное полностью на Python 3 без использования Audacity.