news 2026/10/17 4:53:51

CTF MISC实战:Audacity频谱分析提取摩斯密码

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CTF MISC实战:Audacity频谱分析提取摩斯密码

取到青岑CTF MISC方向这道“美妙的音乐”时,我第一反应是赶紧戴上耳机完整听了一遍。前奏轻快,副歌也不跑调,甚至算得上比赛里少有的“好听”。但经验告诉我,MISC题目的背景音乐越正常,猫腻越藏在某个看不见的频段里。整道题从文件初检、Audacity频谱分析,到最后抄出一段摩斯密码并拼出flag,链路其实非常标准。这篇WriteUp就把完整过程、工具参数和我踩过的坑一起写清楚,给准备入门音频隐写的朋友一个可以直接照做的参考。

1. 开题三分钟:为什么“美妙的音乐”一听就是音频隐写题

1.1 题目命名里的暗示

CTF的MISC题目命名很少有随意的。“美妙的音乐”这五个字,基本把考点的范围圈定到了音频文件隐写。凡是题目里带“音乐”“声音”“耳机”“聆听”这类字眼的,大概率是把flag通过某种方式藏进了wav或mp3里。常见的藏法就那么几类:波形包络里画摩斯码、频谱图上画图案、音频反转、变速变调、WAV文件的LSB隐写、文件尾部附加压缩包或图片。

这道题叫“美妙的音乐”,没有出现“奇怪”“诡异”“倒放”之类的修饰词,说明它不会故意让你听出违和感。此时最优先要怀疑的,是频谱图上有东西被人为画了上去,或者音频数据的最低有效位里塞了额外数据。前者对应“眼睛能看见、耳朵未必听得见”的信号,后者对应完全隐藏的二进制信息。两者处理的路径完全不同,所以开局先别急着解,要有顺序地试探。

1.2 文件初检三连:file、xxd、binwalk

拿到附件之后,第一步永远是先看文件长什么样,而不是直接用播放器打开。题目给的是一个叫beautiful_music.wav的文件,体积4.6MB,播放时长大概4分钟多一点。在终端里依次执行三个命令:

$ ls -lh beautiful_music.wav -rw-r--r-- 1 user user 4.6M 6月 12 21:08 beautiful_music.wav $ file beautiful_music.wav beautiful_music.wav: RIFF (little-endian) data, WAVE audio, Microsoft PCM, 16 bit, mono 44100 Hz

file告诉我们这是标准PCM编码的WAV音频,16位采样深度、单声道、44100Hz采样率。这几个参数很关键:16位意味着每个采样点有16个比特位,最低位可以用来做LSB隐写而不容易被听出来;44100Hz是常见的CD音质采样率,没有异常拉伸或压缩;单声道则排除了一些“左右声道各藏一半信息”的多声道玩法,但也不能完全排除,得看了数据才知道。

接着用xxd快速查看文件头:

$ xxd beautiful_music.wav | head -n 5 00000000: 5249 4646 f8aa 4600 5741 5645 666d 7420 RIFF..F.WAVEfmt 00000010: 1000 0000 0100 0100 44ac 0000 88ac 0000 ........D....... 00000020: 0200 1000 6461 7461 d8aa 4600 0000 0000 ....data..F.....

RIFF头、WAVE标记、fmt块、data块都正常存在,没有在头部看到明显的额外文本信息。这时候习惯性跑一个strings看看有没有直接暴露的字符串或文件名:

$ strings beautiful_music.wav | grep -iE "flag|ctf|key|hint"

输出为空。说明出题人没有粗心到把flag明文留在文件头里,也没有把提示词塞进标签。接下来是容器层面的重点检查,用binwalk扫一遍:

$ binwalk beautiful_music.wav DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 0 0x0 RIFF little-endian data, WAVE audio, Microsoft PCM, 16 bit, mono 44100 Hz

扫描结果只有一个音频段,没有报出附加ZIP、JPEG、PNG之类的嵌套文件。这意味着文件尾部也没有藏压缩包或图片。到这里可以基本确定,猫腻不在“外面”,而在音频主数据区里。很多新手往往听完歌就开始猜,而这一步三连排查能直接省下大量无效时间。

1.3 先听一遍的正确姿势

虽然已经推测考点在音频内部,但我还是会把整首曲子听完,而且不止正常速度一遍。听的时候重点留意三件事:第一,旋律内容是否真的正常,有没有哪一段听起来像外语倒放或者机器人说话;第二,节奏有没有突然变调变速,有些题会在中间某一段改变播放速度来隐藏人声;第三,背景里有没有“嘶嘶”的电流声、高频“嘀嘀”声、类似电话按键的“嘟嘟”声。这些听感特征对应不同的隐写方式,比如倒放、SSTV、DTMF。

我还会把播放速度调到0.5倍或2倍,再快速扫一遍。倒放的内容在0.5倍速度下往往更容易听出语言轮廓,摩斯码的“滴答”节奏也会因为变速而变得更加明显。但必须承认,这道题的隐藏信号在正常播放时几乎听不出来,人耳会把一小段高频点划当成伴奏的叮当声。好在我接下来切换到频谱图之后,真相就立刻暴露了。

2. 藏着摩斯密码的频谱图:Audacity的看谱姿势很重要

2.1 为什么用眼睛找密码比用耳朵快

把信息藏在音频里,本质上是在时间轴上安排一段幅度变化。摩斯电码是一串矩形脉冲信号,短音是一个窄脉冲,长音是一个宽脉冲。这种脉冲如果以低音量混进正常的歌曲旋律,耳朵很难把它从伴奏里剥离出来,因为它和三角铁、沙锤这类高频打击乐的声音非常接近。但频谱图不一样,它把横轴设为时间、纵轴设为频率、颜色深浅代表能量强弱,人为画上去的脉冲会变成一条条边界清晰、排列规则的竖条。

这就是“听不出来,却看得一清二楚”的根本原因。耳朵处理的是混合后的声波叠加,而眼睛在频谱图上看的是时间和频率的展开。隐写信号只要在某个频段上出现,哪怕音量很低,只要能量比底噪高一点,就会在频谱图上显示为可辨识的图形。做音频隐写题,永远不要纠结自己的耳机好不好,把听觉问题转化成视觉问题,效率能提升一个档次。

2.2 频谱图参数怎么调才不容易看花眼

我用的是Audacity,免费开源,功能足够。导入beautiful_music.wav之后,先把音轨横向放大,用Ctrl加滚轮可以快速调整显示密度。然后点击音轨左侧控制面板上那个下拉箭头,在里面选择“频谱图”。这时候整条音轨会变成一张拉长的热力图。默认配色是彩虹色,颜色跳跃很大,容易把人看晕,所以我建议先改两个设置。

打开“查看”菜单里的“频谱图设置”,把窗口大小调到4096,窗口类型选“汉宁窗”或“Hamming”,颜色方案选“灰度”或“经典”。窗口大小决定了频率分辨率和时间分辨率的平衡,数值越大,频率颗粒越细,但竖条在时间方向会被拉宽;数值太小,比如256,整个频谱会糊成一片。4096对于看摩斯码这种周期性脉冲比较合适。灰度配色可以让能量高亮的部分变成白色或浅灰色,图形看起来更接近“条形码”,特别适合判断点划形状。

调完之后,从整轨的频谱图扫一遍。先把频率范围调到全频段,看看有没有某个频带明显比其他地方更“脏”。我当时注意到大约第40秒到第46秒,在1900Hz到2400Hz这个区间,有一条带状区域内嵌着一串整齐的竖条,短的有规律,长的也很有规律,像有人用画图软件在频谱上画了一行条形码。

接着用Audacity的“视图”放大这个区域。有一个细节很关键:确定可疑区域后,不要继续缩小放大来回切换,固定在一个缩放比例下观察。因为摩斯长短音的判断依赖横轴宽度,如果一会儿放大一会儿缩小,视觉上会严重误导你对信号持续时长的判断。把这个区域放大到占满屏幕宽度,就足够开始读数了。

2.3 在谱图上确认点、划、间隔

摩斯码的基本单位是“点”和“划”,点通常持续0.1秒到0.2秒,划持续0.5秒到1秒。在下图中,短竖条对应点,长竖条对应划,竖条之间的短间隔是字符内部间隔,中等间隔是字符间间隔,较长间隔是单词间间隔。用Audacity左侧工具栏的“选择工具”直接框选某一个竖条,底部的选区时长会精确显示持续时间。

我先用选区工具量了最短的竖条,大约是0.13秒,判定为点;又量了较长的竖条,大约是0.65秒,判定为划。然后量了两组竖条之间的空白:有的空白只有0.15秒左右,属于同一个字符内部的点划间隔;有的空白明显长一些,接近0.4秒,属于字符之间的间隔;还有两处空白达到了1秒以上,这个宽度基本可以认定是单词间隔。

通过这个方法,我把40秒到46秒的整段信号抄了出来,分成三组单词。抄录结果先不要急着翻译,先按规范格式写在纸上,然后交给脚本解。这里要特别说一句:很多同学看到频谱图里有竖条就兴奋,直接凭肉眼连蒙带猜地读,结果长短音判错、分组混乱,越解越乱。正确做法是固定比例、量宽度、再分组,宁可慢,不要错。

3. 手工抄报 + 脚本解码:把“条形码”变成flag

3.1 手工抄录的规范格式

从频谱图上抄摩斯码,我建议使用一套严格的书写规范:短竖条记作.,长竖条记作-;同一个字符内部的点划之间不额外留空格,直接连着写;字符之间用一个英文空格区分;单词之间用/分隔后再加空格。这套规范可以保证抄下来的内容能被解析脚本正确识别。

举一个最经典的例子:如果频谱图上依次出现短、短、短、短、短停顿、短、短,对应摩斯码就是.... .,其中前五个短音是一个整体,代表字母H,后面两个短音是另一个字母E,中间那一下停顿属于字符间隔;整段内容连起来是.... .,翻译过来就是HE。如果单词间隔明显更长,得写成.... . / .-.. .-.. ---,翻译成HE LLO,再合并成HELLO。

我在这道题的频谱图上抄出来的摩斯码是:

-.-- --- ..- / .- .-. . / ... -- .- .-. -

那一秒钟以上的长空白出现了两次,所以被分成了三组,每组对应一个单词。我这里还特意做一个对比说明:如果没意识到那是单词间隔,把整串连成-.-----..-.-...这种样子,就完全没法解码了。分组是摩斯解码里最容易出错的一环,一定要根据空白宽度而不是个人感觉来切分。

3.2 一段可复用的摩斯解码脚本

抄好之后,写一个简单的Python脚本一锤定音。我习惯在本地运行脚本,而不是依赖在线解码器,因为在线工具可能会对空格、斜杠、换行做额外处理,干扰你判断原始输入是否正确。下面这段脚本我直接贴出来,以后遇到摩斯题可以直接复用:

# -*- coding: utf-8 -*- MORSE_CODE_DICT = { '.-': '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', '.-.-.-': '.', '--..--': ',', '..--..': '?', } def decode_morse(morse_code: str) -> str: words = morse_code.strip().split(' / ') plain_words = [] for word in words: chars = word.split(' ') plain_words.append(''.join(MORSE_CODE_DICT.get(c, '#') for c in chars)) return ' '.join(plain_words) if __name__ == '__main__': code = "-.-- --- ..- / .- .-. . / ... -- .- .-. -" print(decode_morse(code))

运行结果非常干净:

YOU ARE SMART

脚本的逻辑一共三步:先按/把整段摩斯码拆成单词,再按空格把每个单词拆成单个摩斯字符,最后从字典里查表拼接成明文。如果字典里没有对应的摩斯字符,就返回一个#,这样能提醒自己抄录可能有误。这里我故意不给输入串做多余清洗,就是为了保留原始抄录格式,让错误更容易暴露。

3.3 从明文到提交格式的转换

摩斯码直接解出来的内容通常是大写英文,而且天然不分大小写,因为摩斯码本身就只有点划组合,没有大小写概念。解出YOU ARE SMART之后,还需要根据赛题的flag规则做转换。题目描述里的格式提示是常规的flag{}包裹、全小写、单词间用下划线,所以我把YOU ARE SMART先转成小写,再把空格替换成下划线,最终得到:

flag{you_are_smart}

这里有个细节值得单拎出来说:摩斯码里没有下划线字符,所以出题人如果想把flag中的下划线编码进去,通常会采取两种方案。一种是把下划线对应成摩斯专用符号,也就是..--.-;另一种是像这道题一样,在明文层面用空格代替单词分隔,答题时自己替换成下划线。我这次的输入串里是普通的单词间隔,所以选择第二种方案。如果解码结果里出现了..--.-,那就应该把它替换成_或者按题目提示处理。

提交前我还做了一件事,把flag{youaresmart}、flag{you_are_smart}、flag{YOUARESMART}这三种常见变体按优先级都试了一遍。按位倒推,这道题的正确答案就是第三种,因为题目对大小写敏感。很多题不是死在解不出来,而是死在明知道答案但格式错了,非常可惜。

4. 我在这道题上翻过的车:解码失败的最后几米

4.1 长音短音判反了

我第一次从频谱图上读这段信号的时候,把好几个长划读成了短点,结果脚本解码出来的前面一堆字符全是乱的。问题出在视图缩放比例上,我当时把信号局部放大得太大,一个本该横跨满屏的长音,看上去和短音差不多宽。

后来改用Audacity的选择工具,直接框选每一个竖条看选区时长,问题一下就解决了。短音的持续时间大约0.13秒,长音则普遍在0.6秒以上,两者差距明显,靠手感和视觉目测都不靠谱,必须用数据说话。我再分享一个辅助技巧:用选择工具选中某个竖条后,按空格键可以只播放这一段音频。摩斯电码听上去就是“滴”和“嗒”的差别,滴是短音,嗒是长音。视觉结合听觉双重判断,把长音判成短音的概率会大大降低。

4.2 字母间隔与单词间隔分不清

这是摩斯题翻车率最高的地方。按标准,摩斯码里一个点记为1个单位时长,一个划是3个单位时长;字符内部的点划间隔是1个单位,字符之间的间隔是3个单位,单词之间是7个单位。映射到频谱图上,字符间隔的空白大约是点的三倍宽,单词间隔更宽。可实际看图的时候,没有人会拿尺子一格一格数像素,全凭感觉就容易把单词间隔当成字符间隔。

我最初抄录时,一度把-.-- --- ..-这三个单词连在一起,读成了-.------..-,这串东西无论怎么切分组都解不出来。好在我在纸上手动标出那两条特别长的空白,接着用Audacity的选区工具测量了一下空白宽度,发现其中两条明显是其他间隔的三倍以上,才把单词切分纠正过来。这里有我的一个习惯:拿不准空格怎么切的时候,宁可多分一组。多分空白最多多出一个无效字符,少分则会把两个甚至三个字母糅在一起,彻底废掉。

4.3 MP3有损压缩带来的频谱毛刺

虽然这道题给的是WAV,但它让我想起以前遇到过的MP3变体,这里也一并写出来提醒大家。MP3是有损压缩格式,高频部分会被大幅削减,同时会产生大量压缩噪声。在Audacity的频谱图里,这些噪声表现为细密的毛刺和斑点,摩斯信号如果埋在4kHz以上,很有可能被压缩噪声掩盖,看起来模糊不清。

遇到MP3音频题,我一般会先做两步预处理。第一步,把频谱图窗口大小调大到4096甚至8192,提升频率分辨率,让信号竖条的轮廓更清楚;第二步,如果可疑信号集中在中低频段,可以加上一个低通滤波,把8kHz以上的无关毛刺压掉,再回来看频谱图。不过这个操作要非常克制,如果题目故意把信号埋在高频,你一刀滤过去就把答案滤没了。先全频段确认信号位置,再决定要不要滤波。

4.4 冷静核对提交格式

这道题让我印象最深的,不是频谱图里的摩斯码,而是最后那个提交格式的坑。解出YOU ARE SMART之后,我脑子一热,直接提交了flag{YOUARESMART}。平台提示错误,我才重新读了一遍题目说明。原来这场的规则要求flag内容一律小写,并且单词之间用下划线连接。改提交flag{you_are_smart}之后,一次通过。

所以无论解出什么内容,提交前必须习惯性做三件事:确认比赛规定的flag前缀,确认大小写要求,确认空格或下划线规则。很多MISC题最后拼的就是细心,一个格式错了,可能要多花几十分钟做无意义的检查。比赛现场很容易因为紧张而跳步,我建议把这三个检查写成固定流程,每次提交前过一遍。

5. 同类型题的花样与应对:再看到“音乐”题不慌

5.1 音频隐写的常见载体与识别特征

做过几道音频隐写题之后会发现,万变不离其宗。我把常见的音频隐写方式整理成了一张速查表,方便以后对着查:

隐写类型听感特征视觉特征或推荐工具
波形图摩斯歌曲中突然出现“滴滴答答”的节奏Audacity波形视图里出现明显的脉冲串,包络高低变化规则
频谱图摩斯或图案听起来像轻微杂音或者完全听不见频谱图上出现条形码、点划图形、二维码甚至文字,用Audacity频谱图查看
SSTV慢扫描电视尖锐的“吱啦、嘟——”刺耳声用RX-SSTV等工具解码,通常输出一张图片
DTMF双音多频类似电话按键的“嘟嘟”声分析和识别双频叠加,每两个频率对应一个数字
倒放旋律别扭、人声像含混外语使用Audacity的“效果-反向”后再听
WAV的LSB隐写听感几乎和原音频没区别用wavstego或自写脚本分析采样点最低位
MP3专用隐写MP3文件,音质略有改变使用MP3Stego工具,碰密码提示时需要先找密码

识别方法的核心还是先听、后看。先听有没有异常听感,比如嘶嘶声、按键声、倒放感;再切换频谱图看有没有人为图形。如果听觉视觉都没有发现,就要考虑LSB或者MP3Stego这类工具型隐写。此外,不要忘记一开始的strings命令,有些音频题的flag会藏在ID3标签、注释字段或文件末尾,甚至伪装成乱码字符串。

5.2 十分钟决策路径表

做音频题,我给自己的一个参考流程是控制在10分钟内完成初步定位。具体可以这样走:

  1. 第0到1分钟,执行file、strings、binwalk,确认容器和附加文件。
  2. 第1到3分钟,整曲听一遍,正常速度听完再变速扫一遍,记录直觉。
  3. 第3到6分钟,切到Audacity波形视图,快速扫描包络异常,重点看有没有突然出现的脉冲序列。
  4. 第6到9分钟,切到频谱图,先看全频段有没有偏亮的“图”,再局部放大可疑频段。
  5. 第9到10分钟,如果还无进展,按文件类型启用LSB、SSTV、DTMF、MP3Stego等专项工具。解出内容后先按明文格式直接提交,再按题目规定的变体提交。

这套流程不是标准答案,但它能避免你掉进“反复听歌”的流沙里。很多新手在第一步听歌上花半小时,这不是努力,是方向失误。真正有效的决策依据是文件结构、波形和频谱这三个看得见摸得着的东西。

5.3 建立自己的频谱图谱库

最后分享一个让我受益匪浅的习惯:每次遇到音频隐写题,我都会把频谱图上那个可疑区域的截图保存下来,并记录三行信息,分别是可疑信号的频率范围、信号图形长什么样、最终是通过什么方式解出答案的。积累多了以后,新题目的频谱图扫一眼,大脑会自动和过去见过的图比对,直接得出“这和上次那种条形码很像,先按摩斯试试”的判断。

比如我在这次“美妙的音乐”里看到1900Hz到2400Hz的点划序列,就想起之前遇到过把摩斯信号画到4kHz处的题目,除了习惯性放大到对应频率,其他流程几乎可以整段复用。这种抽象经验比死记硬背工具命令更有价值,因为它能帮你在面对没见过的题型时,快速找到最可能的切入点。把这套思维用在自己常做的方向上,做一道题的吸收效果会远超零散刷十道题。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/17 4:51:44

Flutter+OpenHarmony实战:逆向思维训练App的学习日历开发

最近一直在折腾一个念头:能不能把“逆向思维训练”这种偏认知训练的东西,做成一款真正能坚持用下去的App。我选的技术路线是Flutter OpenHarmony,最终落地了一个带学习日历的逆向思维训练应用。过程踩了不少坑,也积累了一些可以复…

作者头像 李华
网站建设 2026/10/17 4:51:24

Token成油:从数字黄金到数字石油的价值范式转移

先说结论:这个标题最吸引我的地方,不是“2026”这个时间点,也不是“替代比特币”这个略带冲突感的表述,而是“数字石油”这四个字。过去几年我们习惯了把比特币叫“数字黄金”,把以太坊的公链生态叫“链上世界”&#…

作者头像 李华
网站建设 2026/10/17 4:51:21

Java保险理赔系统源码解析:Spring Boot状态机与策略模式完整闭环

简介:一套面向保险业务场景的Java企业级项目源码,适合Java开发者、后端工程师及求职者学习理赔业务系统的完整实现。项目覆盖客户提交理赔申请、业务处理、审核到赔付的主要流程,代码中应用了Spring/Spring Boot、MyBatis、MVC架构、RESTful …

作者头像 李华
网站建设 2026/10/17 4:51:18

Superpowers 使用指南:安装配置、Java 集成与避坑实践

1. 从"superpowers"这个热词说起:它到底是什么第一次看到"superpowers"这个词,很多人会一头雾水。它既不是某个具体软件的名字,也不是某个框架的官方术语,但在开发者社区里,它却频繁出现在各种讨论…

作者头像 李华
网站建设 2026/10/17 4:51:14

eNSP DHCP服务实验:从协议原理到配置排障的完整指南

配网这件事,在真实项目里往往是被排到最后的环节,但每次出问题也最让人头疼:新办公区上线、几十台终端接入、访客网络临时开通,哪一个不是靠DHCP在几分钟内把IP、网关、DNS一次性发下去。可如果你刚学完静态路由,直接上…

作者头像 李华
网站建设 2026/10/17 4:49:53

HTML+CSS家乡网页模板:从结构拆解到响应式定制实战

简介:这是一套以“我的家乡”为主题的HTMLCSS网页制作模板,面向网页设计初学者与需要快速搭建静态站点的开发者,可用于个人故乡展示、地域文化介绍或课程作业等场景。资源包共73个文件,包含6个html页面、7个css样式表、56张jpg图片…

作者头像 李华