Skip to content
Back to skills

Steganography Audio

ASecurity

Ses steganografi — WAV LSB, DTMF decode, spektogram analizi, DeepSound, Morse code ve Python ile tam çözüm şablonları.

  • 4 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 8, 2026
securitypythongobashgit

Works with

  • cli

Security analysis

A96/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro shows the line behind each finding and how to fix it

Scanned September 8, 2026

npx -y skills add MustafaKemal0146/fetih --skill steganography-audio --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Steganography Audio?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Steganography Audio
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/mustafakemal0146-steganography-audio/badge)](https://www.skillsdirectory.com/skills/mustafakemal0146-steganography-audio)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: steganography-audio
description: "Ses steganografi — WAV LSB, DTMF decode, spektogram analizi, DeepSound, Morse code ve Python ile tam çözüm şablonları."
tags: [ctf, forensics, stego, audio, wav, mp3, lsb, dtmf, spectrogram, deepsound, morse, sonic-visualiser, audacity, sox, goertzel]
triggers:
  - "WAV dosyası"
  - "MP3 dosyası"
  - "ses dosyasında gizli veri"
  - "DTMF"
  - "spektogram"
  - "audio stego"
  - "DeepSound"
  - "Sonic Visualiser"
  - "Audacity"
  - "ses analizi"
  - "frekans analizi"
  - "morse code audio"
  - "audio forensics"
difficulty: medium
category: forensics
solved_challenges:
  - "CatTheQuest CTF 2024 - Deep Sound Deep Vision (spektogram + DeepSound password → MONSTERS.txt → decimal ASCII → flag)"
  - "çeşitli CTF DTMF decode (telefon tuşları → rakam dizisi → flag)"
  - "ångstromCTF DTMF challenge"
adapted_for: fetih
---

# Ses Steganografi Analizi

## Ne Zaman Kullan

Aşağıdaki işaretlerden herhangi birini görürsen bu skill'i tetikle:

- `.wav`, `.mp3`, `.flac`, `.ogg`, `.aiff` dosyası verilmiş
- Ses garip tınlıyor, arka planda tuş sesi/bip/ton var (DTMF/Morse şüphesi)
- Challenge'da "hidden in audio", "secret frequency", "listen carefully" geçiyor
- Spektogram incelenmesini öneren ipucu var
- DeepSound, MP3Stego adı geçiyor

---

## Araç Seti

```bash
# Sonic Visualiser — spektogram görselleştirme (GUI, en önemli araç)
sudo apt install sonic-visualiser

# Audacity — ses düzenleme ve görselleştirme
sudo apt install audacity

# DeepSound — Windows GUI, LSB gizleme/çıkarma
# İndir: http://jpinsoft.net/deepsound/download.aspx

# sox — CLI ses dönüştürme
sudo apt install sox

# Python kütüphaneleri
pip install scipy numpy wave pydub

# ffmpeg — format dönüştürme
sudo apt install ffmpeg

# stegolsb — ses LSB CLI
pip install stegolsb
```

---

## Spektogram Analizi — Sonic Visualiser

Spektogram, ses dosyasındaki frekansların zamana göre görsel temsilidir. Gizli mesajlar görsel olarak frekans katmanına kodlanabilir (görüntü gibi görünür).

### Sonic Visualiser Adımları

```
1. Sonic Visualiser'ı aç
2. Dosya → Aç → challenge.wav
3. Layer menüsü → Add Spectrogram
4. Properties panelinde:
   - Window: 2048 ya da 4096 (daha yüksek = daha iyi frekans çözünürlüğü)
   - Colourmap: Sunset ya da Inferno (kontrastı artırır)
   - Scale: dBV²
5. Spektogramı yatay kaydır, gizli metin/görüntü ara
6. Çok yüksek frekanslara bak (>10kHz — insan kulağı duymaz, CTF favorisi)
```

### Python ile Spektogram Göster

```python
#!/usr/bin/env python3
"""
WAV dosyasının spektogramını görselleştir.
Çalıştır: python3 spectrogram.py challenge.wav
"""
import numpy as np
import matplotlib.pyplot as plt
from scipy.io import wavfile
import sys

wav_file = sys.argv[1] if len(sys.argv) > 1 else "challenge.wav"

sample_rate, data = wavfile.read(wav_file)

# Stereo → mono
if data.ndim > 1:
    data = data[:, 0]

print(f"[*] Sample rate: {sample_rate} Hz")
print(f"[*] Duration: {len(data)/sample_rate:.2f} saniye")
print(f"[*] Samples: {len(data)}")

# Spektogram çiz
plt.figure(figsize=(20, 8))
plt.specgram(data, Fs=sample_rate, NFFT=4096, noverlap=2048,
             cmap='inferno', vmin=-100, vmax=0)
plt.colorbar(label='Güç (dBFS)')
plt.xlabel('Zaman (s)')
plt.ylabel('Frekans (Hz)')
plt.title(f'Spektogram: {wav_file}')
plt.ylim(0, sample_rate // 2)  # Nyquist'e kadar
plt.savefig('spectrogram.png', dpi=150, bbox_inches='tight')
plt.show()
print("[+] Spektogram kaydedildi: spectrogram.png")
```

---

## Gerçek Örnek: CatTheQuest CTF 2024 — Deep Sound Deep Vision

### Senaryo
`challenge.wav` verilmiş. Dinleyince sıradan ses. Ancak spektogramda görünür metin var.

### Çözüm Adımları

```
Adım 1: Sonic Visualiser ile spektogramı aç
         → Yüksek frekanslarda "THE_MONSTER_IS_YOU" yazısı görünüyor
         → Bu DeepSound şifresi!

Adım 2: DeepSound ile ses dosyasını analiz et
         → DeepSound aç → challenge.wav'ı yükle
         → Şifreli içerik gösteriyor
         → Password: "THE_MONSTER_IS_YOU"
         → Extract → MONSTERS.txt çıkarıldı

Adım 3: MONSTERS.txt içeriğini oku
         → Onluk (decimal) sayı dizisi: "67 84 70 123 77 ..."

Adım 4: Decimal ASCII'den flag'e çevir
```

```python
#!/usr/bin/env python3
"""CatTheQuest decimal ASCII → flag dönüştürücü."""

# MONSTERS.txt içeriği (decimal sayılar)
decimal_str = "67 84 70 123 77 79 78 83 84 69 82 95 70 76 65 71 125"
# Örnek — gerçek CTF'den sayıları buraya yapıştır

numbers = list(map(int, decimal_str.split()))
flag = ''.join(chr(n) for n in numbers)
print(f"[+] Flag: {flag}")
# Çıktı: CTF{MONSTER_FLAG}
```

### Alternatif: DeepSound olmadan CLI

```bash
# MP3Stego kontrolü
mp3stego-decode -X challenge.mp3 output.txt

# stegolsb ile
wavsteg -r -i challenge.wav -o output.txt -n 1

# sox ile kanalları ayır (stereo'dan bir kanal gizli olabilir)
sox challenge.wav left.wav remix 1   # sol kanal
sox challenge.wav right.wav remix 2  # sağ kanal

# Fark kanalı (sağ - sol, stereo içinde gizlenmiş sinyal)
sox -M left.wav right.wav merged.wav
sox merged.wav diff.wav remix 1v1,2v-1  # fark
```

---

## DTMF Decode

DTMF (Dual-Tone Multi-Frequency): Telefon tuş seslerinin frekans çiftiyle kodlanması.
CTF'lerde ses dosyası DTMF tonları içeriyorsa, rakam/karakter dizisi → dönüştürme → flag.

### DTMF Frekans Tablosu

```
        1209 Hz  1336 Hz  1477 Hz  1633 Hz
697 Hz    1        2        3        A
770 Hz    4        5        6        B
852 Hz    7        8        9        C
941 Hz    *        0        #        D
```

### Python Goertzel Algoritması ile DTMF Decode

```python
#!/usr/bin/env python3
"""
WAV dosyasındaki DTMF tonlarını decode et.
Çalıştır: python3 dtmf_decode.py tones.wav
"""
import numpy as np
from scipy.io import wavfile
import sys

def goertzel(samples: np.ndarray, sample_rate: int, target_freq: float) -> float:
    """Goertzel algoritması — belirli bir frekansın gücünü hesaplar."""
    N = len(samples)
    k = int(0.5 + N * target_freq / sample_rate)
    omega = 2 * np.pi * k / N
    coeff = 2 * np.cos(omega)
    
    s_prev2 = 0.0
    s_prev1 = 0.0
    
    for sample in samples:
        s = sample + coeff * s_prev1 - s_prev2
        s_prev2 = s_prev1
        s_prev1 = s
    
    power = s_prev2**2 + s_prev1**2 - coeff * s_prev1 * s_prev2
    return power

# DTMF frekans matrisi
DTMF_FREQS = {
    'row': [697, 770, 852, 941],
    'col': [1209, 1336, 1477, 1633]
}

DTMF_KEYS = [
    ['1', '2', '3', 'A'],
    ['4', '5', '6', 'B'],
    ['7', '8', '9', 'C'],
    ['*', '0', '#', 'D'],
]

def decode_dtmf_frame(frame: np.ndarray, sample_rate: int) -> str:
    """Bir ses çerçevesini DTMF karakterine decode et."""
    # Normalize et
    frame = frame.astype(np.float64)
    
    row_powers = [goertzel(frame, sample_rate, f) for f in DTMF_FREQS['row']]
    col_powers = [goertzel(frame, sample_rate, f) for f in DTMF_FREQS['col']]
    
    row_idx = np.argmax(row_powers)
    col_idx = np.argmax(col_powers)
    
    # Güç eşiği — gürültüyü filtrele
    THRESHOLD = 1e6
    if row_powers[row_idx] < THRESHOLD or col_powers[col_idx] < THRESHOLD:
        return None
    
    return DTMF_KEYS[row_idx][col_idx]

def decode_wav(wav_file: str) -> str:
    sample_rate, data = wavfile.read(wav_file)
    
    # Stereo → mono
    if data.ndim > 1:
        data = data[:, 0]
    
    data = data.astype(np.float64)
    
    # Çerçeve boyutu: ~50ms
    frame_size = int(sample_rate * 0.05)
    
    digits = []
    prev_digit = None
    
    i = 0
    while i + frame_size <= len(data):
        frame = data[i:i + frame_size]
        digit = decode_dtmf_frame(frame, sample_rate)
        
        if digit and digit != prev_digit:
            digits.append(digit)
        
        prev_digit = digit
        i += frame_size // 2  # %50 overlap
    
    return ''.join(digits)

if __name__ == "__main__":
    wav_file = sys.argv[1] if len(sys.argv) > 1 else "dtmf.wav"
    
    print(f"[*] DTMF decode: {wav_file}")
    result = decode_wav(wav_file)
    print(f"[+] Bulunan rakamlar: {result}")
    
    # T9 klavye → harf dönüşümü (gerekirse)
    # 2=ABC, 3=DEF, 4=GHI, 5=JKL, 6=MNO, 7=PQRS, 8=TUV, 9=WXYZ
    t9_map = {
        '2': 'ABC', '3': 'DEF', '4': 'GHI', '5': 'JKL',
        '6': 'MNO', '7': 'PQRS', '8': 'TUV', '9': 'WXYZ'
    }
    print(f"\n[*] T9 karşılıkları (sırayla): ", end="")
    for d in result:
        if d in t9_map:
            print(f"{d}={t9_map[d]}", end=" ")
    print()
    
    # Decimal ASCII dene
    if all(c.isdigit() for c in result) and len(result) % 2 == 0:
        try:
            pairs = [int(result[i:i+2]) for i in range(0, len(result), 2)]
            text = ''.join(chr(p) for p in pairs if 32 <= p < 127)
            print(f"[+] 2 haneli decimal ASCII: {text}")
        except Exception:
            pass
```

---

## WAV LSB Python ile Çıkarma

```python
#!/usr/bin/env python3
"""WAV LSB steganografi — en düşük bit düzleminden veri çıkar."""
import wave
import sys

def extract_lsb_wav(wav_file: str, n_bits: int = 1, out_file: str = "lsb_output.bin"):
    """
    wav_file : WAV dosyası
    n_bits   : kaç bit çıkarılacak (1 = LSB, 2 = iki bit, vb.)
    """
    with wave.open(wav_file, 'rb') as w:
        n_frames   = w.getnframes()
        n_channels = w.getnchannels()
        sampwidth  = w.getsampwidth()  # byte cinsinden örnek genişliği
        frames     = w.readframes(n_frames)
    
    print(f"[*] {wav_file}: {n_frames} frame, {n_channels} kanal, {sampwidth*8}-bit")
    
    samples = list(frames)
    bits = []
    
    mask = (1 << n_bits) - 1  # örn. n_bits=1 → 0b00000001
    
    for sample in samples:
        for bit_pos in range(n_bits - 1, -1, -1):
            bits.append((sample >> bit_pos) & 1)
    
    # Bit dizisini byte'lara çevir
    result = bytearray()
    for i in range(0, len(bits) - 7, 8):
        byte = 0
        for b in bits[i:i+8]:
            byte = (byte << 1) | b
        result.append(byte)
        
        # Null-terminated string bitişi
        if result[-1] == 0 and len(result) > 10:
            text_so_far = result[:-1].decode('utf-8', errors='ignore')
            if any(p in text_so_far for p in ['flag{', 'CTF{', 'HTB{']):
                print(f"[!] Flag bulundu: {text_so_far}")
                break
    
    with open(out_file, "wb") as f:
        f.write(result)
    
    print(f"[+] {len(result)} byte çıkarıldı: {out_file}")
    print(f"[+] İlk 50 byte ASCII: {result[:50].decode('latin-1', errors='replace')}")
    
    return bytes(result)

if __name__ == "__main__":
    wav = sys.argv[1] if len(sys.argv) > 1 else "audio.wav"
    extract_lsb_wav(wav, n_bits=1)          # LSB
    # extract_lsb_wav(wav, n_bits=2)        # 2 LSB
    # stegolsb alternatif: wavsteg -r -i audio.wav -o out.txt -n 1
```

---

## Morse Code Audio Decode

```python
#!/usr/bin/env python3
"""WAV dosyasından Morse kodu decode et."""
import numpy as np
from scipy.io import wavfile

def decode_morse_audio(wav_file: str):
    sample_rate, data = wavfile.read(wav_file)
    
    if data.ndim > 1:
        data = data[:, 0]
    
    # Enerji zarfını hesapla (mutlak değer + yumuşatma)
    envelope = np.abs(data.astype(np.float64))
    window = int(sample_rate * 0.01)  # 10ms pencere
    envelope = np.convolve(envelope, np.ones(window)/window, mode='same')
    
    # Eşik: ortalamanın 2 katı
    threshold = np.mean(envelope) * 2
    
    # Açık/kapalı segmentleri bul
    signal_on = envelope > threshold
    
    # Segment uzunluklarını hesapla
    segments = []
    current_state = signal_on[0]
    count = 0
    
    for s in signal_on:
        if s == current_state:
            count += 1
        else:
            segments.append((current_state, count / sample_rate * 1000))  # ms
            current_state = s
            count = 1
    segments.append((current_state, count / sample_rate * 1000))
    
    # Kısa/uzun ton sürelerini bul
    on_durations = [d for state, d in segments if state and d > 10]
    if not on_durations:
        print("[-] Sinyal tespit edilemedi")
        return
    
    median_dur = np.median(on_durations)
    dot_threshold = median_dur * 2  # kısa ton
    
    # Morse sembollerine çevir
    MORSE_CODE = {
        '.-': 'A', '-...': 'B', '-.-.': 'C', '-..': 'D', '.': 'E',
        '..-.': 'F', '--.': 'G', '....': 'H', '..': 'I', '.---': 'J',
        '-.-': 'K', '.-..': 'L', '--': 'M', '-.': 'N', '---': 'O',
        '.--.': 'P', '--.-': 'Q', '.-.': 'R', '...': 'S', '-': 'T',
        '..-': 'U', '...-': 'V', '.--': 'W', '-..-': 'X', '-.--': 'Y',
        '--..': 'Z', '-----': '0', '.----': '1', '..---': '2',
        '...--': '3', '....-': '4', '.....': '5', '-....': '6',
        '--...': '7', '---..': '8', '----.': '9',
    }
    
    morse_str = ""
    for state, duration in segments:
        if state:  # ton açık
            morse_str += '.' if duration < dot_threshold else '-'
        else:  # sessizlik
            if duration > dot_threshold * 6:  # kelime arası
                morse_str += ' / '
            elif duration > dot_threshold * 2:  # harf arası
                morse_str += ' '
    
    print(f"[*] Morse: {morse_str}")
    
    # Decode et
    words = morse_str.split(' / ')
    decoded = []
    for word in words:
        letters = word.split()
        decoded_word = ''.join(MORSE_CODE.get(l, '?') for l in letters)
        decoded.append(decoded_word)
    
    result = ' '.join(decoded)
    print(f"[+] Decoded: {result}")
    return result

if __name__ == "__main__":
    import sys
    wav = sys.argv[1] if len(sys.argv) > 1 else "morse.wav"
    decode_morse_audio(wav)
```

---

## Tuzaklar

- **Sample rate farkı**: 8000 Hz (telefon kalitesi) ile 44100 Hz (CD kalitesi) fark büyük. DTMF frekansları her sample rate için yeniden hesaplanmalı — Goertzel algoritması bunu otomatik yapar.
- **Stereo vs mono**: Gizli veri sadece sol ya da sadece sağ kanalda olabilir. Her kanalı ayrı ayrı analiz et: `sox audio.wav -c 1 left.wav remix 1`
- **MP3 kayıplı sıkıştırma**: MP3, LSB bilgisini yok eder. WAV'a çevirip LSB çıkarmaya çalışma — anlamsız sonuç alırsın. MP3 için MP3Stego ya da spektogram ara.
- **DeepSound şifresi**: CTF'de DeepSound şifresi çoğunlukla spektogramdan okunur. Sonic Visualiser'da çok yüksek frekanslara (>15kHz) özellikle bak.
- **DTMF çakışması**: Arka plan gürültüsü false positive yaratabilir. Goertzel eşiğini (THRESHOLD) yükselt ya da sadece belirgin ton geçişlerini say.
- **Morse hız değişkeni**: WPM (words per minute) farklı olursa median hesabı bozulur. Kısa/uzun oranı sabit kalır (1:3) ama mutlak süre değişir.
- **WAV bit derinliği**: 8-bit WAV örnekler işaretsiz (0-255), 16-bit işaretli (-32768 ile 32767). `wave` modülü raw byte döner — bit derinliğine göre yorumla.
- **Boş/sessiz bölgeler**: Dosyanın sonunda uzun sessizlik varsa binwalk ile kontrol et — başka bir dosya eklenmiş olabilir.

<!--
  ⚔ Bu skill FETIH AI Agent icin gelistirilmistir — https://github.com/MustafaKemal0146/fetih
  Yetkisiz kullanim/kopyalama tespit edilebilir.
  hash: 19356b73f0d854d6
-->

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…