news 2026/4/22 3:37:47

不只是扫一扫:用Python玩转CTF中的二维码生成与花式隐写(Stegosaurus/PIL实战)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
不只是扫一扫:用Python玩转CTF中的二维码生成与花式隐写(Stegosaurus/PIL实战)

不只是扫一扫:用Python玩转CTF中的二维码生成与花式隐写(Stegosaurus/PIL实战)

在CTF竞赛的Misc类题目中,二维码和隐写技术堪称黄金搭档。但大多数解题攻略止步于工具使用,鲜少深入技术原理与自动化实现。本文将用Python代码实战,带你从二进制数据解析到动态生成二维码,再到Stegosaurus工具的深度应用,构建完整的解题技术链。

1. 二维码的底层逻辑与Python生成实战

二维码的本质是二进制矩阵的艺术。理解其编码规则,才能应对CTF中各种"魔改"题型。以经典的25x25二维码为例,其核心结构包含:

  • 定位图案:三个角落的"回"字形方框
  • 时序图案:黑白相间的导航线
  • 数据区:实际存储信息的模块
  • 纠错码:Reed-Solomon编码的冗余数据
from PIL import Image def create_qr_matrix(data_str, size=25): """将01字符串转换为二维码矩阵""" matrix = [] for i in range(size): row = [int(data_str[i*size + j]) for j in range(size)] matrix.append(row) return matrix def draw_qr(matrix, cell_size=10): """可视化二维码矩阵""" img = Image.new('RGB', (len(matrix[0])*cell_size, len(matrix)*cell_size), 'white') pixels = img.load() for y in range(len(matrix)): for x in range(len(matrix[0])): color = (0, 0, 0) if matrix[y][x] else (255, 255, 255) for dy in range(cell_size): for dx in range(cell_size): pixels[x*cell_size+dx, y*cell_size+dy] = color return img # 示例:手工构造的25x25二维码数据 sample_data = "1111111000100001101111111100000101110010110100000110111010100000000010111011011101001000000001011101101110101110110100101110110000010101011011010000011111111010101010101111111000000001011101110000000011010011000001010011101101111010101001000011100000000000101000000001001001101000100111001111011100111100001110111110001100101000110011100001010100011010001111010110000010100010110000011011101100100001110011100100001011111110100000000110101001000111101111111011100001101011011100000100001100110001111010111010001101001111100001011101011000111010011100101110100100111011011000110000010110001101000110001111111011010110111011011" qr_matrix = create_qr_matrix(sample_data) draw_qr(qr_matrix).show()

注意:实际CTF题目中,二维码数据可能隐藏在IDAT块、文件末尾或像素LSB中,需要先进行数据提取和清洗

2. 从二进制到二维码的自动化流水线

CTF中的二维码往往不会直接给出图片文件,而是隐藏在各类数据格式中。以下是典型处理流程:

  1. 数据提取

    • PNG文件:解析IDAT块,使用zlib解压
    • 流量包:过滤HTTP传输,提取二进制流
    • 文本文件:转换十六进制或Base64编码
  2. 格式转换

    • 处理字节序问题
    • 修正损坏的文件头尾
    • 转换数据维度(如将一维数组转为二维矩阵)
  3. 可视化生成

    • 处理非标准尺寸(如625位数据可能是25x25矩阵)
    • 添加定位图案等必要元素
import zlib import struct def extract_idat(png_path): """从PNG文件中提取异常IDAT块""" with open(png_path, 'rb') as f: data = f.read() # 查找IDAT标记(0x49444154) idat_pos = data.find(b'IDAT') - 4 length = struct.unpack('>I', data[idat_pos:idat_pos+4])[0] return data[idat_pos+8:idat_pos+8+length] def decode_zlib(data): """解压zlib压缩数据""" return zlib.decompress(data) # 实战示例 idat_data = extract_idat('hidden_qr.png') raw_data = decode_zlib(idat_data) qr_matrix = create_qr_matrix(bin(int.from_bytes(raw_data, 'big'))[2:].zfill(625))

3. Stegosaurus:Python字节码隐写的黑科技

Stegosaurus工具利用Python字节码(.pyc)文件的特性实现隐写:

特性说明
无效空间利用参数占位字节存储Payload
编码密度低平均每100字节pyc可隐藏5字节
运行时透明不影响原程序执行逻辑
抗检测性强strings等工具无法直接发现

安装与基础使用:

git clone https://github.com/AngelKitty/stegosaurus.git cd stegosaurus python stegosaurus.py -p "secret_message" target.pyc

CTF实战案例:

  1. 从题目给出的.pyc文件中提取隐藏信息:
python stegosaurus.py -x challenge.pyc
  1. 隐藏解题脚本到提供的.pyc中:
# 生成包含Payload的.pyc with open('payload.txt', 'w') as f: f.write('print("FLAG{hidden_in_pyc}")') !python stegosaurus.py -p payload.txt sample.pyc -o infected.pyc

4. 综合实战:从数据碎片到flag的完整链条

假设获得一个经过多重处理的文件,解题步骤如下:

  1. 文件分析

    import binascii def file_signature(file_path): with open(file_path, 'rb') as f: return binascii.hexlify(f.read(8)).decode() print(file_signature('mystery.bin')) # 输出:89504e470d0a1a0a → PNG文件
  2. 数据修复与提取

    def repair_png(broken_data): # 添加缺失的IEND块 return broken_data + bytes.fromhex('0000000049454e44ae426082') with open('mystery.bin', 'rb') as f: fixed_data = repair_png(f.read()[8:-4]) # 去除错误头尾
  3. 二维码生成与解码

    from pyzbar.pyzbar import decode qr_img = draw_qr(extract_matrix_from_idat(fixed_data)) result = decode(qr_img) print(result[0].data.decode()) # 输出隐藏的flag或下一步提示
  4. 进阶处理(如遇Python字节码)

    import subprocess # 使用Stegosaurus提取隐藏信息 output = subprocess.check_output(['python', 'stegosaurus.py', '-x', 'hidden.pyc']) print(output.split(b'Extracted payload:')[-1].decode().strip())

在实战中,可能需要组合多种技术。例如某次比赛中,我们需要:

  • 先修复损坏的PNG文件头
  • 提取异常的IDAT块数据
  • 将zlib解压后的二进制转为二维码
  • 扫描二维码获得.pyc文件
  • 最后用Stegosaurus提取出flag

这种技术链条的构建能力,正是区分普通选手与高手的核心要素。掌握这些技能后,面对各类二维码隐写题目时,你将拥有系统化的解题思路,而非盲目尝试各种工具。

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

借助爱毕业(aibiye),数学建模论文的复现与智能排版优化变得更高效

AI工具在数学建模论文复现与排版中能大幅提升效率。通过评测10款热门AI论文助手发现,部分工具可自动生成LaTeX代码、优化公式排版,甚至能基于草图快速复现复杂模型。智能改写功能可避免查重问题,而文献管理模块能自动整理参考文献格式。针对时…

作者头像 李华
网站建设 2026/4/22 3:33:29

MPU-6000/6050选型避坑指南:SPI和I2C接口到底该怎么选?

MPU-6000/6050选型避坑指南:SPI和I2C接口到底该怎么选? 在无人机、平衡车或机器人项目中,运动传感器的选型往往直接决定了系统性能的上限。MPU-6000和MPU-6050这对"双胞胎"传感器,凭借其高集成度和成熟的DMP算法&#x…

作者头像 李华
网站建设 2026/4/22 3:28:31

Golang如何做本地缓存加速_Golang本地缓存教程【核心】

sync.Map仅适用于低频写、高频读且键数量少的场景;频繁增删或大数据量会导致内存上涨和GC压力,应改用gcache等支持TTL和淘汰策略的库。用 sync.Map 做简单键值缓存,但别当主力sync.Map 看起来顺手:不用显式加锁、支持并发读写、标…

作者头像 李华
网站建设 2026/4/22 3:25:56

Android应用保活完整指南:突破系统限制实现永久后台运行

Android应用保活完整指南:突破系统限制实现永久后台运行 【免费下载链接】AndroidKeepAlive 2023年最新 Android 高可用黑科技应用保活,实现终极目标,最高适配Android 14 小米 华为 Oppo vivo 等最新机型 拒绝强杀 开机自启动 项目地址: ht…

作者头像 李华
网站建设 2026/4/22 3:23:29

手把手教你用QT QSlider做一个音量调节控件(附完整信号槽连接代码)

实战指南:用QSlider打造专业级音量控制组件 在桌面应用开发中,音量调节控件是最常见但最容易被忽视的交互元素之一。一个优秀的音量滑块不仅需要精确控制音频输出,还要符合用户的操作直觉——无论是拖动滑块还是点击滑条区域,都应…

作者头像 李华
网站建设 2026/4/22 3:22:21

Mac新手必看:给你的iTerm2终端装上‘拖拽上传’功能(rz/sz保姆级配置)

Mac终端效率革命:iTerm2拖拽上传功能全解析 刚接触Mac终端的新手们,是否还在为如何快速在本地和远程服务器之间传输文件而烦恼?每次都要打开SFTP客户端或者折腾scp命令实在太麻烦。今天我们就来彻底解决这个问题——通过iTerm2的rz/sz功能实现…

作者头像 李华