目录

CTF 隐写术全解析:从图片到音频的 “藏 flag” 技巧

一、图片隐写:像素与文件结构中的 “秘密”

1. PNG 隐写:从 LSB 到 tEXt 块的多层隐藏

(1)LSB 隐写:像素的 “最低位密码”

(2)PNG 块隐藏:tEXt 块与附加数据

(3)CRC 校验爆破:修改图片内容后的 “数据修复”

2. JPG 隐写:DCT 系数与注释中的 “漏洞”

(1)JPG 注释与 EXIF 信息

(2)DCT 系数隐写:在压缩数据中藏信息

3. GIF 隐写:帧动画与透明色的 “陷阱”

(1)多帧信息拼接

(2)透明色通道隐写

二、音频隐写:从频谱到波形的 “声音密码”

1. 频谱图分析:“看得见” 的声音信息

2. LSB 隐写:音频采样点的 “最低位”

3. MP3 ID3 标签:伪装成 “元数据” 的 flag

三、文档与压缩包隐写:从 PDF 到 ZIP 的 “伪装术”

1. PDF 隐写:隐藏图层与注释

2. ZIP 伪加密:修改标志位的 “障眼法”

四、隐写术通用工具与自动化脚本

1. 必备工具清单

2. 自动化脚本示例

(1)批量提取图片中的隐藏文件

(2)LSB 手动提取脚本(PNG)

五、实战总结:隐写术解题 “黄金流程”


在 CTF 的 Misc 题型中,隐写术(Steganography)是将信息隐藏在普通文件(图片、音频、文档等)中而不被察觉的技术。与密码学通过加密保护信息不同,隐写术的核心是 “隐藏信息的存在”。解题的关键在于 ——找到信息的隐藏位置:可能是图片像素的最低位、音频频谱的间隙、文档的隐藏图层,甚至是压缩包的伪加密标志位。本文将系统梳理 CTF 中主流载体的隐写方法,结合工具使用与实战案例,带你从 “观察异常” 到 “提取数据”,完成隐写术的完整破解流程。

一、图片隐写:像素与文件结构中的 “秘密”

图片是隐写术最常用的载体,PNG、JPG、GIF 等格式因结构特性不同,隐藏信息的方式也大相径庭。

1. PNG 隐写:从 LSB 到 tEXt 块的多层隐藏

PNG 格式因无损压缩、支持透明通道等特性,成为 CTF 隐写的 “常客”。其隐写技巧主要集中在像素最低位(LSB)图像块(Chunk) 和CRC 校验三个层面。

(1)LSB 隐写:像素的 “最低位密码”

原理:PNG 图像的每个像素由 RGB 三通道组成(如每个通道 8 位,取值 0-255)。修改通道值的最低 1-2 位(LSB)不会影响视觉效果,但可用来存储二进制数据(0/1)。例如,将像素红色通道值从10101101改为10101100,人眼无法分辨,但可记录 1 位信息。

实战步骤

  1. 工具选择:用Stegsolve(图形化工具)或zsteg(命令行工具,支持 PNG/JPG)提取 LSB 数据。

    • Stegsolve操作
      打开图片→AnalyzeData Extract→勾选Red 0(红色通道最低位)、Green 0Blue 0→观察右侧输出是否出现二进制 / 文本数据。
    • zsteg命令

      zsteg -a secret.png  # 自动检测所有可能的LSB组合
      zsteg secret.png -e b1,r,lsb,xy  # 提取指定通道(b1=1位,r=红色通道,lsb=最低位)
      
  2. 案例:某 PNG 图片通过 LSB 隐藏 flag,用zsteg提取:

    zsteg secret.png | grep "flag"  # 过滤含flag的结果
    # 输出:b1,g,lsb,xy.. text: "flag{lsb_steganography_is_easy}"
    
(2)PNG 块隐藏:tEXt 块与附加数据

原理:PNG 文件由多个块(Chunk)组成,包括IHDR(图像头)、IDAT(数据)、IEND(结束)等。除标准块外,可添加tEXt(文本注释)、zTXt(压缩文本)等块隐藏信息,这些块不会影响图片显示。

实战步骤

  1. pngcheck分析块结构

    pngcheck -v secret.png  # 详细输出所有块
    # 若出现tEXt块,会显示:tEXt  123  "comment" (contains text data)
    
  2. 提取 tEXt 块数据
    • foremost分离块数据:

      foremost secret.png -o output  # 在output目录生成png文件和附加数据
      
    • 直接用文本编辑器打开 PNG 文件,搜索tEXt关键字,其后的 ASCII 数据可能为 flag。
(3)CRC 校验爆破:修改图片内容后的 “数据修复”

原理:PNG 每个块的CRC字段(4 字节)是对块内容的校验值。若修改图片像素(如隐藏信息)但未更新 CRC,会导致校验失败。通过爆破 CRC 可反推原始像素数据或提取隐藏信息。

案例:某 PNG 图片被修改了 1 个像素,导致 CRC 错误,需爆破原始像素值:

  1. pngcheck定位错误块

    pngcheck secret.png  # 输出:secret.png: CRC error in chunk IDAT (computed 0x12345678, expected 0x87654321)
    
  2. 编写 Python 脚本爆破
    假设错误块为IDAT,修改区域为 1x1 像素(3 字节 RGB),爆破可能的像素值使 CRC 匹配:

    import zlib
    import struct
    
    # 已知块数据(省略部分字节,仅保留修改区域)
    block_data = b'\x00\x00\x00...'  # 块内容(不含CRC)
    expected_crc = 0x87654321  # 预期CRC
    
    # 爆破RGB值(0-255)
    for r in range(256):
        for g in range(256):
            for b in range(256):
                modified = block_data[:10] + bytes([r, g, b]) + block_data[13:]
                crc = zlib.crc32(modified) & 0xFFFFFFFF
                if crc == expected_crc:
                    print(f"找到原始像素:R={r}, G={g}, B={b}")
    

    爆破得到的像素值可能对应 ASCII 字符(如r=102→'f',g=108→'l'),拼接成 flag。

2. JPG 隐写:DCT 系数与注释中的 “漏洞”

JPG 是有损压缩格式,隐写方式与 PNG 不同,主要利用DCT 系数篡改注释字段

(1)JPG 注释与 EXIF 信息

原理:JPG 文件的 EXIF 元数据(如作者、注释、GPS 坐标)可存储文本信息,用exiftool即可读取。

实战命令

exiftool secret.jpg  # 查看所有元数据
exiftool secret.jpg | grep "Comment"  # 过滤注释字段
# 示例输出:Comment                         : flag{exif_comment_here}
(2)DCT 系数隐写:在压缩数据中藏信息

JPG 压缩过程会将图像分成 8x8 像素块,通过离散余弦变换(DCT)将像素值转换为频率系数,再量化压缩。隐写时可修改非关键频率的 DCT 系数(不影响视觉)存储信息。

工具与案例

  • jsteg提取:

    jsteg reveal secret.jpg  # 提取DCT系数中隐藏的数据
    
  • 案例:某 JPG 图片通过 DCT 系数隐藏flag.zip,提取后解压得到 flag。

3. GIF 隐写:帧动画与透明色的 “陷阱”

GIF 支持多帧动画和透明色,可通过帧间隙藏数据透明通道隐写

(1)多帧信息拼接

原理:GIF 的每一帧可隐藏少量数据,将所有帧的隐藏信息拼接即可还原完整 flag。

实战步骤

  1. GIMP(图像编辑工具)打开 GIF→WindowsAnimation Playback→查看所有帧。
  2. convert(ImageMagick 工具)提取所有帧:

    convert secret.gif frame_%d.png  # 将GIF拆分为帧图片
    
  3. 检查每帧的像素差异,或用Stegsolve对比帧数据,拼接隐藏的字符。
(2)透明色通道隐写

GIF 的透明色(指定某颜色为透明)可用来标记特殊区域,隐藏二进制数据。例如,透明像素记为 0,非透明记为 1,组合成字节。

二、音频隐写:从频谱到波形的 “声音密码”

音频隐写主要利用频谱图波形间隙ID3 标签,常见格式为 WAV(无损)和 MP3(有损)。

1. 频谱图分析:“看得见” 的声音信息

原理:音频的频谱图(横轴时间,纵轴频率)可直观显示不同频率的声音强度。若在特定频率绘制图案(如文字),人耳难以察觉,但频谱图中清晰可见。

实战步骤

  1. 工具:用Audacity(音频编辑工具)查看频谱图。
  2. 操作
    打开音频→效果频谱图频谱图设置(选择 “对数频率”,调整分辨率)→观察频谱图中是否有文字(如flag{...})。

案例:某 WAV 文件在 10kHz 频率处用短脉冲绘制flag{spectrum_hide},频谱图中可直接读取。

2. LSB 隐写:音频采样点的 “最低位”

与图片 LSB 类似,音频的每个采样点(如 16 位采样,取值范围 - 32768~32767)的最低 1-2 位可存储二进制数据。

工具与命令

  • audacity配合Nyquist插件提取,或steghide(支持音频 / 图片):

    bash

    steghide extract -sf secret.wav  # 若有密码,需爆破(用stegcracker)
    stegcracker secret.wav /usr/share/wordlists/rockyou.txt  # 字典爆破密码
    

3. MP3 ID3 标签:伪装成 “元数据” 的 flag

MP3 的 ID3v1/v2 标签可存储标题、歌手、注释等信息,直接用exiftoolid3v2读取:

id3v2 -l secret.mp3  # 列出ID3标签
# 示例输出:COMM: flag{id3_tag_secret}

三、文档与压缩包隐写:从 PDF 到 ZIP 的 “伪装术”

1. PDF 隐写:隐藏图层与注释

PDF 支持多层内容和注释,可通过隐藏图层(设置图层不可见)或注释字段藏数据。

实战步骤

  1. pdfinfo查看 PDF 属性:

    pdfinfo secret.pdf  # 检查是否有异常的页数、大小
    
  2. pdftk提取元数据和附件:

    pdftk secret.pdf dump_data  # 查看文档元数据
    pdftk secret.pdf unpack_files  # 提取嵌入的附件(如flag.txt)
    
  3. Adobe Acrobat打开 PDF→视图导航面板图层,勾选隐藏图层查看内容。

2. ZIP 伪加密:修改标志位的 “障眼法”

原理:ZIP 文件头的全局加密标志位(2 字节)若被恶意修改,会导致解压工具误判为加密(需密码),但实际数据未加密。通过修改标志位可去除 “伪加密”。

实战步骤

  1. 010 Editor(十六进制编辑器)打开 ZIP 文件,定位文件头:
    • 本地文件头格式:50 4B 03 04 + 2 字节版本 + 2 字节加密标志位(00 00 = 未加密,01 00 = 加密)。
  2. 将加密标志位从01 00改为00 00,保存后即可正常解压。
  3. 自动化工具:用zipinfo检查加密状态,fcrackzip爆破真加密(伪加密无需爆破):

    bash

    zipinfo secret.zip  # 查看是否加密
    fcrackzip -u -D -p /usr/share/wordlists/rockyou.txt secret.zip  # 真加密时爆破
    

四、隐写术通用工具与自动化脚本

1. 必备工具清单

工具用途 工具名称 核心功能
图片隐写提取 Stegsolve 可视化提取 LSB、对比通道、分析帧数据
命令行 LSB 分析 zsteg 自动检测 PNG/GIF 的 LSB 隐藏数据
元数据查看 exiftool 读取图片、音频的 EXIF/ID3 元数据
文件分离 binwalk/foremost 从文件中提取嵌入式文件(如图片中的 ZIP)
音频频谱分析 Audacity 查看音频频谱图,提取可视化信息
压缩包处理 pdftk/zipinfo 处理 PDF 附件、检测 ZIP 伪加密

2. 自动化脚本示例

(1)批量提取图片中的隐藏文件
import os
import binwalk

def extract_hidden_files(input_dir):
    for file in os.listdir(input_dir):
        if file.endswith(('.png', '.jpg', '.gif')):
            print(f"Processing {file}...")
            binwalk.scan(
                os.path.join(input_dir, file),
                extract=True,  # 自动提取
                quiet=True,
                outdir=f"extracted_{file}"
            )

extract_hidden_files("./images")  # 处理images目录下的图片
(2)LSB 手动提取脚本(PNG)

from PIL import Image

def extract_lsb(image_path):
    img = Image.open(image_path)
    pixels = img.load()
    width, height = img.size
    data = []
    for y in range(height):
        for x in range(width):
            r, g, b = pixels[x, y]
            # 提取每个通道的最低位(共3位/像素)
            data.append(str(r & 1))
            data.append(str(g & 1))
            data.append(str(b & 1))
    # 将二进制数据转为字节(每8位一组)
    bits = ''.join(data)
    bytes_data = bytes([int(bits[i:i+8], 2) for i in range(0, len(bits), 8)])
    return bytes_data

# 提取并保存数据
with open("lsb_extracted.bin", "wb") as f:
    f.write(extract_lsb("secret.png"))

五、实战总结:隐写术解题 “黄金流程”

  1. 初步检查
    file命令确认文件类型(防止文件后缀欺骗,如.jpg实际是zip):

    file secret.jpg  # 输出:secret.jpg: Zip archive data, at least v2.0 to extract
    
  2. 元数据与注释
    exiftoolexifread读取所有元数据,检查是否有异常字段(如FlagComment)。

  3. 文件分离
    binwalk -e自动提取嵌入式文件(如图片中的 ZIP、PDF 中的 TXT)。

  4. 载体特性分析

    • 图片:用Stegsolve/zsteg查 LSB,pngcheck分析块结构。
    • 音频:用Audacity看频谱,steghide提取 LSB。
    • 压缩包:检查伪加密(改标志位),爆破真加密密码。
  5. 人工验证
    对提取的二进制数据尝试转文本(strings命令)、解密(Base64、XOR),或作为压缩包 / 图片打开。

隐写术的核心是 “逆向思维”—— 站在出题者角度思考 “如何隐藏信息而不被发现”,结合工具逐个排除可能的隐藏位置。随着 CTF 难度提升,隐写术常与加密结合(如隐藏的是加密后的 flag,需先找到密钥),但万变不离其宗:先找到信息,再破解信息。下一篇将聚焦 CTF 脚本编写,带你用代码自动化解决复杂题型。

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐