CTF密码学之侧信道攻击-声学攻击出题指南

admin 2024年7月3日23:11:22评论5 views字数 11075阅读36分55秒阅读模式

0.省流

今天继续介绍侧信道攻击的声学攻击,没看过前面文章的,可以点击侧信道攻击之电磁侧信道攻击出题指南。此篇省流部分:声学攻击原理、密钥值恢复代码示例、CTF题目3道。

CTF密码学之侧信道攻击-声学攻击出题指南

1.声学攻击

1.1.概念

声学攻击是一种利用设备在操作过程中产生的声波来获取信息的攻击方法。这种攻击归类为侧信道攻击(Side-Channel Attack),侧信道攻击是一种通过设备运行时的物理现象(如电磁泄漏、功耗变化、声音、热量等)来推测设备内部状态和操作的信息泄漏方法。

在声学攻击中,攻击者利用高灵敏度的麦克风或其他声学传感器,捕获设备发出的声音。这些声音可能包含设备操作时的特征信息,通过分析这些声音,攻击者能够推测或重建出设备操作的具体内容,例如用户输入的文本、密码,甚至是硬件的操作状态。

1.2.原理

声学攻击的原理基于设备在执行不同任务时发出的声音存在差异,这些差异可以被捕捉并分析,进而提取出有用的信息。以下是声学攻击的一些核心原理:

  • 声音的特征差异:

不同的操作会产生不同的声音特征。例如,键盘按键的声音因按键位置和力度的不同而有所差异。打印机在打印不同字符或图像时,打印头的移动和墨水喷射也会产生不同的声波模式。硬盘在读取和写入不同数据块时,磁头移动和盘片旋转的声音也各有不同。

  • 信号捕获与处理:

攻击者使用高灵敏度的麦克风或其他声学传感器来捕获设备发出的声音。这些捕获的声音信号通常包含大量的背景噪音和其他干扰,攻击者需要通过信号处理技术(如滤波、去噪、频谱分析等)来提取出有用的声音特征。

  • 模式识别与分析:

通过对处理后的声音信号进行模式识别和分析,攻击者可以识别出不同操作对应的声音特征,并推测出设备正在执行的具体操作。例如,使用机器学习算法对不同按键的声音进行分类,可以还原用户输入的内容;分析打印机的声音模式,可以重建打印的文档内容。

1.3.示例

以键盘声学攻击为例,详细说明声学攻击的原理:

  • 捕获声音信号:

攻击者将麦克风放置在目标键盘附近,捕获用户敲击键盘时发出的声音。每个按键的敲击都会产生独特的声音信号,这些信号可以被录制下来。

  • 信号处理:

录制的声音信号通常包含背景噪音和其他干扰,攻击者需要使用滤波和去噪技术来清除这些干扰,并提取出每个按键敲击的声音特征。

  • 特征提取:

对处理后的声音信号进行频谱分析,提取出每个按键敲击的频率特征和时域特征。不同按键的声音特征会有所不同,这些特征可以用于区分不同的按键。

  • 模式识别:

使用模式识别算法(如机器学习分类器)对不同按键的声音特征进行分类。训练分类器以识别每个按键对应的声音特征,分类器可以根据输入的声音特征预测出用户敲击的具体按键。

  • 还原输入内容:

通过识别出每个按键的声音特征,可以还原出用户输入的文本内容。例如,捕获并分析用户输入密码时的键盘声音,可以推测出用户输入的密码。

1.4.代码示例

代码示例部分生成了三个声音文件,攻击者需要从这三个声音文件当中恢复出密钥值。

CTF密码学之侧信道攻击-声学攻击出题指南恢复密钥的主要步骤:

  • 加载录音文件:

使用 librosa 库加载音频文件,获取音频信号数组 y 和采样率 sr。

  • 绘制波形图:

使用 matplotlib 库绘制音频信号的波形图,方便可视化和分析。

  • 小波去噪:

使用 pywt 库进行小波变换,对信号进行软阈值处理去噪,并重构去噪后的信号。

  • 短时傅里叶变换(STFT):

使用 librosa.stft 函数对去噪后的信号进行 STFT,将信号从时域转换到频域。

  • 能量计算:

计算每个频率 bin 的总能量,找出能量最高的频率 bin。

  • 找到能量峰值频率:

确定能量最高的频率 bin 对应的实际频率。

  • 恢复密钥值:

通过比较恢复的频率和预设的频率列表,找到最接近的原始频率,恢复密钥值。

# recover_keys.py
import numpy as np
import soundfile as sf
import librosa
import matplotlib.pyplot as plt
import pywt
def load_audio(file_path):
    y, sr = librosa.load(file_path, sr=None)
    print(f"Loaded audio from {file_path} with sample rate {sr} and first 50 samples:n{y[:50]}"
    return y, sr
def plot_waveform(y, sr, title='Waveform', start=0, end=0.01):
    plt.figure(figsize=(10, 4))
    plt.plot(np.linspace(start, end, num=len(y[int(start * sr):int(end * sr)])), y[int(start * sr):int(end * sr)])
    plt.title(title)
    plt.xlabel('Time (s)')
    plt.ylabel('Amplitude')
    plt.show()
def wavelet_denoise(signal, wavelet='db1', level=1):
    coeff = pywt.wavedec(signal, wavelet, mode='symmetric')
    sigma = (1/0.6745) * np.median(np.abs(coeff[-level] - np.median(coeff[-level])))
    uthresh = sigma * np.sqrt(2 * np.log(len(signal)))
    coeff[1:] = [pywt.threshold(i, value=uthresh, mode='soft'for i in coeff[1:]]
    return pywt.waverec(coeff, wavelet, mode='symmetric')
def analyze_and_recover_key(signal, sr, frequencies):
    stft = np.abs(librosa.stft(signal))
    energy = np.sum(stft, axis=0)
    peak_bin = np.argmax(energy)
    actual_frequencies = np.fft.rfftfreq(stft.shape[0], 1/sr)
    recovered_frequency = actual_frequencies[peak_bin]
    closest_freq = min(frequencies, key=lambda x: abs(x - recovered_frequency))
    return closest_freq
def recover_keys_from_files(frequencies, sr=44100):
    recovered_keys = []
    for freq in frequencies:
        audio_file = f'audio_{freq}Hz_with_noise.wav'
        y, sr = load_audio(audio_file)
        denoised_signal = wavelet_denoise(y)
        recovered_frequency = analyze_and_recover_key(denoised_signal, sr, frequencies)
        recovered_keys.append(recovered_frequency)
        plot_waveform(denoised_signal, sr, title=f'Denoised Waveform of {audio_file} (first 10ms)', start=0, end=0.01)
        print(f'Recovered Frequency for {audio_file}: {recovered_frequency} Hz')
    return recovered_keys
frequencies = [440, 880, 1760]
recovered_keys = recover_keys_from_files(frequencies)
print(f'Recovered Keys: {recovered_keys}')

代码运行后结果

Loaded audio from audio_440Hz_with_noise.wav with sample rate 44100 and first 50 samples:
[ 0.15042114  0.05731201 -0.06021118  0.15203857  0.38406372  0.3039856
  0.2889099   0.19973755  0.16009521  0.18283081  0.31985474  0.27651978
  0.2255249   0.228302    0.3529663   0.43945312  0.5163574   0.69976807
  0.35098267  0.4104004   0.36032104  0.46240234  0.40423584  0.49279785
  0.5857544   0.51052856  0.6244507   0.4257202   0.24075317  0.44335938
  0.6197815   0.46533203  0.31411743  0.53671265  0.33151245  0.23080444
  0.2402649   0.67697144  0.6057129   0.32632446  0.23876953  0.34020996
  0.10458374  0.3340454   0.1510315   0.05712891  0.1312561   0.01828003
  0.01434326  0.21832275]
CTF密码学之侧信道攻击-声学攻击出题指南
Recovered Frequency for audio_440Hz_with_noise.wav: 440 Hz
Loaded audio from audio_880Hz_with_noise.wav with sample rate 44100 and first 50 samples:
[ 0.09951782  0.16055298 -0.03286743  0.28808594  0.13735962  0.16217041
  0.20391846  0.43624878  0.39215088  0.35794067  0.53689575  0.38580322
  0.25204468  0.5942688   0.44262695  0.5979614   0.3959961   0.571167
  0.33764648  0.29626465  0.11486816  0.0682373   0.18371582  0.17370605
  0.11203003 -0.04806519  0.07989502  0.01925659 -0.16955566 -0.23483276
 -0.42434692 -0.31582642 -0.44024658 -0.37139893 -0.46768188 -0.49224854
 -0.54293823 -0.51934814 -0.44473267 -0.4699707  -0.5070801  -0.41827393
 -0.44906616 -0.27890015 -0.37008667 -0.24526978 -0.15447998 -0.46411133
 -0.13684082 -0.06088257]
CTF密码学之侧信道攻击-声学攻击出题指南
Recovered Frequency for audio_880Hz_with_noise.wav: 1760 Hz
Loaded audio from audio_1760Hz_with_noise.wav with sample rate 44100 and first 50 samples:
[ 0.09475708  0.07492065  0.25045776  0.33016968  0.24935913  0.44799805
  0.6422119   0.3595276   0.3802185   0.29034424  0.32104492  0.02999878
 -0.06698608 -0.03421021 -0.32199097 -0.21948242 -0.36999512 -0.66137695
 -0.59417725 -0.5118103  -0.38842773 -0.3286438  -0.3425598  -0.1144104
 -0.24603271  0.13687134  0.21658325  0.05001831  0.4897461   0.4230652
  0.66156006  0.50009155  0.5922241   0.2772827   0.3095703   0.31723022
  0.1078186   0.09298706 -0.06057739 -0.02947998 -0.38687134 -0.31344604
 -0.62091064 -0.5957031  -0.5371399  -0.55288696 -0.51474    -0.21173096
 -0.35528564 -0.14685059]
CTF密码学之侧信道攻击-声学攻击出题指南
Recovered Frequency for audio_1760Hz_with_noise.wav: 1760 Hz
Recovered Keys: [440, 1760, 1760]
CTF密码学之侧信道攻击-声学攻击出题指南

2.CTF题目示例

2.1.简单的声学恢复flag

题目附件:

CTF密码学之侧信道攻击-声学攻击出题指南

2.1.1.出题思路

  • 生成基础音频:

创建一个10秒的白噪声音频,作为载体音频。

  • 转换flag:

将flag字符串转换为二进制数据,得到一串二进制位。

  • 嵌入数据:

选择音频的某一部分,在该部分内根据二进制位的值(0或1)调制音频信号。具体方法是将音频信号的小部分替换为特定的值(如0.01或-0.01),使之能在后续解析时区分出来。

保存音频:将修改后的音频数据保存为WAV文件。

2.1.2解题思路

使用音频处理工具或编程语言读取音频文件中的数据。

提取音频中的调制部分,通过分析这些部分来还原二进制数据。

将二进制数据转换回字节数据,最终还原为flag字符串。

2.1.3.解题代码

import numpy as np
from scipy.io import wavfile
sample_rate, audio = wavfile.read("complex_test_audio.wav")
audio = audio.astype(np.float32) / 32767  
start_index = len(audio) // 4  
flag_bin_length = 78 * 8  
flag_bin = []

for i in range(flag_bin_length):
    bit_val = '1' if audio[start_index + i] > 0 else '0'
    flag_bin.append(bit_val)

flag_bin = ''.join(flag_bin)

print("Recovered binary length:", len(flag_bin))  
flag_bytes = [int(flag_bin[i:i+8], 2) for i in range(0, len(flag_bin), 8)]
recovered_flag = bytes(flag_bytes).decode('utf-8', errors='ignore')
print("Recovered Flag:", recovered_flag)
Recovered binary length: 624
Recovered Flag: flag{To_be_both_a_speaker_of_words_and_a_doer_of_deeds_xuruihan_is_the_author}
CTF密码学之侧信道攻击-声学攻击出题指南

2.2.Easy_SM4

题目文件:

CTF密码学之侧信道攻击-声学攻击出题指南

附件内容:

2.2.1.出题思路

  • 生成SM4加密的flag:

使用GmSSL库的SM4算法将flag进行加密,确保数据的安全性和复杂性。

将加密后的数据转换为二进制比特流。

  • 将二进制比特流嵌入音频信号:

将二进制比特流中的每一位映射为音频信号中的一个样本值,其中1映射为1.0,0映射为-1.0。这样,整个比特流可以通过音频信号来表示。生成的音频信号可以形成一个音频文件。

  • 保存音频文件:

将生成的音频信号保存为WAV文件格式。

2.2.2.解题思路

  • 音频文件读取:

使用scipy.io.wavfile读取WAV音频文件,获取采样率和音频数据。

将音频数据转换为浮点数,以便进行后续处理。

  • 提取二进制数据:

遍历音频信号,将每个样本值转换为二进制比特。根据样本值的正负,将其对应为二进制的1或0。拼接所有二进制比特,形成完整的二进制字符串。将二进制字符串每8位一组转换为字节数组。

  • 解密数据:

使用GmSSL库的SM4算法进行解密。设置解密密钥,并使用ECB模式解密提取到的字节数据。

  • 还原flag:

将解密后的字节数据转换为字符串。打印恢复的flag。

2.2.3.解题代码

import numpy as np
from scipy.io import wavfile
from gmssl import sm4
def extract_encrypted_data_from_audio(filename):
    sample_rate, audio = wavfile.read(filename)
    audio = audio.astype(np.float32)

    flag_bin = []
    for sample in audio:
        if sample > 0:
            flag_bin.append('1')
        else:
            flag_bin.append('0')

    flag_bin = ''.join(flag_bin)
    flag_bytes = [int(flag_bin[i:i+8], 2) for i in range(0, len(flag_bin), 8)]
    return bytes(flag_bytes)
def decrypt_data(data, key):
    cipher = sm4.CryptSM4()
    cipher.set_key(key, sm4.SM4_DECRYPT)
    decrypted_data = cipher.crypt_ecb(data)
    return decrypted_data
def recover_flag_from_audio(filename, key):
    encrypted_data = extract_encrypted_data_from_audio(filename)
    decrypted_data = decrypt_data(encrypted_data, key)
    flag = decrypted_data.decode('utf-8', errors='ignore')
    return flag
filename = "SM4_secret_audio.wav"
key = bytes.fromhex('0123456789ABCDEFFEDCBA9876543210')
recovered_flag = recover_flag_from_audio(filename, key)
print(f"Recovered Flag: {recovered_flag}")

Recovered Flag: flag{To_be_both_a_speaker_of_words_and_a_doer_of_deeds_xuruihan_is_the_author}

CTF密码学之侧信道攻击-声学攻击出题指南

2.3.Easy_RSA

题目附件:

CTF密码学之侧信道攻击-声学攻击出题指南

2.3.1.出题思路

创建一个固定的flag。生成RSA密钥对。生成AES对称密钥。使用RSA公钥加密AES对称密钥。使用AES对称密钥加密固定的flag。将加密的AES对称密钥和加密的固定flag嵌入到音频文件中。保存私钥用于解密。

2.3.2.解题思路

读取并解析音频文件中的加密数据。使用私钥解密AES对称密钥。使用AES对称密钥解密固定的flag。动态生成当前时间戳,组合固定flag和时间戳生成新的字符串。计算该字符串的SHA-256哈希值。将哈希值格式化为flag{sha256}的形式,作为最终的动态flag。

2.3.3.解题代码

import numpy as np
from scipy.io import wavfile
from Crypto.Cipher import AES, PKCS1_OAEP
from Crypto.PublicKey import RSA
import time
import hashlib
def extract_encrypted_data_from_audio(filename):
    sample_rate, audio = wavfile.read(filename)
    audio = audio.astype(np.float32)

    flag_bin = []
    for sample in audio:
        if sample > 0:
            flag_bin.append('1')
        else:
            flag_bin.append('0')

    flag_bin = ''.join(flag_bin)
    flag_bytes = [int(flag_bin[i:i+8], 2) for i in range(0, len(flag_bin), 8)]
    return bytes(flag_bytes)
def decrypt_symmetric_key(encrypted_sym_key, private_key):
    rsa_key = RSA.import_key(private_key)
    cipher_rsa = PKCS1_OAEP.new(rsa_key)
    sym_key = cipher_rsa.decrypt(encrypted_sym_key)
    return sym_key
def decrypt_data(encrypted_data, sym_key):
    nonce = encrypted_data[:16]
    tag = encrypted_data[16:32]
    ciphertext = encrypted_data[32:]
    cipher = AES.new(sym_key, AES.MODE_EAX, nonce=nonce)
    data = cipher.decrypt_and_verify(ciphertext, tag)
    return data
def recover_fixed_flag_from_audio(filename, private_key):
    encrypted_data = extract_encrypted_data_from_audio(filename)
    encrypted_sym_key_len = 256  
    encrypted_sym_key = encrypted_data[:encrypted_sym_key_len]
    encrypted_flag = encrypted_data[encrypted_sym_key_len:]
    sym_key = decrypt_symmetric_key(encrypted_sym_key, private_key)
    decrypted_flag = decrypt_data(encrypted_flag, sym_key)
    flag = decrypted_flag.decode('utf-8', errors='ignore')
    return flag
def recover_dynamic_flag(filename, private_key):
    fixed_flag = recover_fixed_flag_from_audio(filename, private_key)
    timestamp = int(time.time())
    combined_flag = f"{fixed_flag}_{timestamp}"
    sha256_flag = hashlib.sha256(combined_flag.encode('utf-8')).hexdigest()
    dynamic_flag = f"flag{{{sha256_flag}}}"
    return dynamic_flag
filename = "rsa_1_encrypted_flag_audio.wav"
with open("rsa_1_private_key.pem""rb") as f:
    private_key = f.read()

recovered_flag = recover_dynamic_flag(filename, private_key)
print(f"Recovered Flag: {recovered_flag}")

Recovered Flag: flag{3411743885f43794ef03eb7028a3a7816ea488a202c2c3fd1d062011e199e804}

CTF密码学之侧信道攻击-声学攻击出题指南

3.总结

以3道题目为例讲解密码学的侧信道声学攻击,最后一道题目采用静态flag+时间戳SHA256的方式做了一个动态flag。本章出题严格来说应该归根在Misc的隐写题里,只是解法用了密码学当中的侧信道攻击方法以及密码学算法。

原文始发于微信公众号(攻防SRC):CTF密码学之侧信道攻击-声学攻击出题指南

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年7月3日23:11:22
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   CTF密码学之侧信道攻击-声学攻击出题指南https://cn-sec.com/archives/2915026.html

发表评论

匿名网友 填写信息