☰
Kali下zsteg安装与使用:PNG图片隐写检测实战指南
2026/10/10 3:14:34 网站建设 项目流程

从第一次拿到一张需要检查隐写信息的 PNG 图片开始,zsteg 就一直是我在 Kali 环境里离不开的工具。简单说,zsteg 是一个专门用来检测 PNG 和 BMP 图片中隐藏数据的命令行工具,它能看到肉眼看不到的 LSB 隐写痕迹,也能识别很多藏在图片像素里的文件片段。如果你参与 CTF 的图片隐写题、或者在做数字取证时需要快速排查一张图片是否被做过手脚,那这篇关于 zsteg 的安装与使用记录,应该能让你省下不少折腾时间。我会从零开始,把我在 Kali 中安装 zsteg 的完整过程、常用参数、实战命令以及踩过的坑全部摊开来讲。

1. zsteg 是什么,能检测什么

1.1 从一道 CTF 题说起

记得有一次参加线下的内部赛,有一道隐写题给了一张风景照片,文件大小 2MB,分辨率正常,打开看也完全没有异常。很多人在 exiftool 里翻了半天,用 strings 搜了一圈也没有线索。后来有人跑了一下zsteg -a,几秒种就发现图片的蓝色通道最低位里藏了一段字符串,顺着那段字符串又找到了下一步的压缩包密码。那道题之后,我养成了一个习惯:凡是遇到图片,先交给 zsteg 扫一遍再说。

类似这种场景在很多取证和渗透测试里也会出现。攻击者经常会把一些文本、密钥、甚至恶意脚本藏进图片里,用来绕过内容检测。zsteg 这类工具就是用来对付这种手法的。它不需要知道隐藏信息的具体格式,只要图片被写入的方式属于它支持的隐写类别,很大概率能被它扫描出来。

1.2 zsteg 的工作原理

zsteg 的核心原理并不神秘。常见的图片隐写,最基础的一种是 LSB 隐写。PNG 和 BMP 这类无损图片,每个像素的颜色由红色、绿色、蓝色三个通道构成,有些还带透明度通道。每个通道的值是一个字节,比如红色从 0 到 255。理论上,如果我把某个像素红色值从 200 改成 201,肉眼几乎无法察觉,但二进制最低的一位发生了变化。LSB 就是 Least Significant Bit,最低有效位。把大量隐藏信息依次替换到这些最低位上,人眼看不出来,但程序完全可以读出来。

zsteg 做的就是扫描这些最低位,并且它比一般的脚本更聪明。它会自动尝试不同的通道组合,比如只取蓝色通道、同时取红绿蓝三个通道、或者把透明度通道也带上;也会尝试不同位顺序,LSB 是从低位向高位读,MSB 是从高位向低位读。它还会对提取出来的位流做常见编码分析,比如 ASCII 码、UTF-8、甚至压缩文件头或者图片文件头。也就是说,它不仅能告诉你“这里看起来有东西”,还能直接告诉你“这里藏的是一个 ZIP 文件”或者“这是一段可读字符串”。

1.3 zsteg 与同类工具的区别

经常有人把 zsteg 和 binwalk、steghide 混在一起用,但它们解决的问题完全不同。我整理过一个粗对比表,供你参考:

工具主要定位适用格式能干什么
zstegLSB 及其他位隐写检测PNG、BMP扫描并提取嵌入在像素低位的数据
binwalk文件结构和嵌入文件检测任意文件从文件尾部或中间嗅探签名,分离压缩包、固件等
steghide隐写加密写入与提取JPEG、BMP、WAV、AU需要密码,适用于已知用 steghide 隐藏的场景
exiftool元数据查看与修改几乎所有图片格式查看可编辑 EXIF 等元数据,不适合底层隐写
strings提取可打印字符任意只找文本,发现不了二进制隐藏信息

所以,当一张图片没有任何元数据异常、用 strings 也没看到奇怪字符串时,zsteg 是很有力的补充。它针对的是像素级别的隐写,而不是文件层面的拼凑。

2. Kali 环境下安装 zsteg 的三种方式

2.1 安装前确认基础环境

Kali 本身预装的 Ruby 环境比较完整,这对 zsteg 是个好消息,因为 zsteg 是基于 Ruby 的开源工具。在开始之前,我一般先执行两条命令确认 Ruby 和 gem 是否可用:

ruby -v gem -v

如果输出版本号,说明环境正常。如果提示找不到命令,则先安装 Ruby:

sudo apt update sudo apt install ruby-dev build-essential zlib1g-dev

ruby-dev 和构建工具非常重要,因为部分依赖需要编译本地扩展。我在一个精简版 Kali 上试过跳过这一步,结果 zsteg 安装时直接报编译错误。

2.2 方式一:gem 一行命令安装

zsteg 发布为 RubyGem,所以最直接的安装方式就是:

sudo gem install zsteg

让 gem 把 zsteg 及其依赖一起装好。这个命令会从 RubyGems 源拉取最新版本,安装完成后执行zsteg --help就能看到帮助信息。如果系统里已经有 zsteg,想升级到最新版,可以用:

sudo gem update zsteg

这里想提醒一件事:如果你使用了国内的 RubyGems 镜像源,有可能因为同步不及时导致安装失败或者版本落后。这时候可以先查看当前源:

gem sources

如果看到不是官方源,再考虑切回官方源,或者使用一家你信任且更新及时的镜像。怎么切换网上都有很多参考资料,核心原则是确保能拉到最新的 zsteg gem 包。

2.3 方式二:从源码编译安装

某些情况下,你可能需要修改 zsteg 源码,或者 gem 源一直拉不下来,那就可以直接从 Git 仓库拉源码编译。zsteg 的源码在代码托管平台上就能找到,大致操作如下:

git clone https://github.com/某仓库地址/zsteg.git cd zsteg sudo rake install

这里的“某仓库地址”需要你自行确认,我一般通过搜索“zsteg gem”就能找到。源码方式的好处是,你可以拿到最新开发版本,甚至直接在源码里加打印日志,方便自己理解它到底在扫描什么。缺点是需要手动安装依赖,比如ruby-zsteg依赖zsteg的底层 gem 包。如果缺依赖,rake install会报错,根据报错用 gem 安装缺失的依赖即可。

2.4 方式三:Docker 方式

如果你不想污染当前 Kali 环境,或者你用的是非 Kali 系统,也可以拉一个包含 Kali 工具的 Docker 镜像,在容器里运行 zsteg。比如:

docker run --rm -it -v $(pwd):/data kali:v1 bash apt update && apt install -y ruby-dev zlib1g-dev gem install zsteg cd /data zsteg -a your.png

这种方式适合需要临时取证或跨平台工作的场景。我个人在紧急比赛中用过一次,因为镜像没预装 zsteg,现场安装依然花了半分钟,但也还算顺利。

2.5 安装后的验证

无论用哪种方式,装完以后第一件事是执行:

zsteg --help

正常会输出一屏参数说明。如果提示找不到命令,先检查 gem 的 bin 目录是否在 PATH 中。执行gem environment可以查看 Ruby 的安装目录,比如 Ruby 2.x 的 bin 目录可能在/var/lib/gems/2.7.0/bin,需要将它加入 PATH。另一种验证方式是直接扫一张图,最简单的办法是自己生成一张纯色 PNG,然后运行zsteg -a 1.png,如果能跑完而不报错,说明核心功能正常。

3. zsteg 常用参数与使用姿势

3.1 最简单的命令

最基本的用法是:

zsteg image.png

这条命令会扫描默认通道,输出可能存在的隐藏数据。但实际场景中,我几乎不会只用默认参数,因为默认配置会漏掉一些特殊情况。比如有些题目会把信息藏在蓝色通道,而默认扫描可能不会把所有通道都覆盖到。要做到更全面,通常会用:

zsteg -a image.png

-a表示尝试所有已知的方法和通道,扫描范围更广,输出也会更详细。缺点是速度慢一些,但对单张图片来说几乎可以忽略不计。

3.2 常用参数速查表

我用得最多的参数都整理在这个表里了:

参数作用示例
-a用所有已知方法扫描zsteg -a image.png
-v输出详细调试信息zsteg -v image.png
-E从指定通道提取数据zsteg -E "b1,bgr,lsb" image.png
-c手动指定通道,如 r、g、b、azsteg -c b image.png
-o指定位顺序:lsb 或 msbzsteg -o msb image.png
-b指定从第几位开始读取zsteg -b 1 -o lsb image.png
-l限制最大提取字节数zsteg -l 64 image.png
-C禁用彩色输出,便于脚本解析zsteg -C image.png

其中-E是提取模式,后面跟的通道描述格式很重要。像b1,bgr,lsb的意思是:从 b 位开始读 1 个比特,按 bgr 通道顺序,采用 lsb 方式。如果对格式不熟,可以先跑zsteg -a,输出里会包含形如b1,bgr,lsb的提示,直接拿来放到-E后面提取即可。

3.3 不同场景下的参数组合

场景一:快速判断图片有没有问题。

zsteg -a suspect.png

场景二:扫描结果提示某个通道有异常,想只提取那个通道的内容。

zsteg -E "b1,bgr,msb" suspect.png

场景三:感觉图片颜色有些奇怪,怀疑是 MSB 隐写。

zsteg -o msb -c r suspect.png

场景四:只需要提取前几字节,判断隐藏数据是什么类型。

zsteg -l 16 -a suspect.png

这些命令看起来不长,但关键是要理解每个参数的含义。我的经验是:先无脑跑-a,再根据输出缩小范围,最后用-E提取具体数据。这也是最高效的流程。

4. 实战:用 zsteg 从 PNG 中提取隐藏 flag

4.1 准备一张测试图片

为了验证 zsteg 是否正常工作,我会自己构造一张带隐写的图片,而不使用网上现成的样例,这样我能完全知道隐藏内容是什么,从而判断工具输出是否正确。

我用 Python 的 PIL 库来生成一张纯白图片和一张有自然过渡色的小图:

from PIL import Image import random img = Image.new("RGB", (200, 200), (255, 255, 255)) img.save("test.png")

这是一张全白图片,理论上看起来什么都没有。但全白像素有一个特点:像素值都在 255,最低位全是 1。如果我在最低位写入数据,在颜色上会变成 254 或 255 的细微差别,肉眼完全看不出来。

4.2 手工嵌入 LSB 信息

接着我写一个简单的 LSB 嵌入脚本。为了贴近真实 CTF 场景,我在隐藏数据前加上一些标记字符串,比如模拟一个文本内容:

from PIL import Image img = Image.open("test.png") pixels = img.load() message = "flag{zsteg_install_usage_test}" binary = ''.join(format(ord(c), '08b') for c in message) binary = binary.replace('01', '10') # 为了演示稍微变换,不做特殊处理 idx = 0 for y in range(200): for x in range(200): if idx < len(binary): r, g, b = pixels[x, y] pixels[x, y] = (r & 0xFE | int(binary[idx]), g, b) idx += 1 else: break img.save("test.png")

这里我选择了把信息嵌入每个像素红色通道的最低位。实际嵌入过程可能使用多种通道,但总体思路一致:取一个字节,把最低位替换成隐藏信息的一个 bit。如果你的 Python 环境没有 PIL,先执行pip install pillow。

4.3 运行 zsteg 提取

保存图片后,进入 Kali 终端,先执行最普通的扫描:

zsteg test.png

由于默认扫描不会覆盖所有通道,这里可能看不到完整信息。接着执行:

zsteg -a test.png

输出中会看到类似这样的内容:

test.png b1,r,lsb,msb -> "flag{zsteg_install_usage_test}"

zsteg 会报告隐藏位置和提取出的字符串。如果你是第一次用,突然看到自己能读取自己藏进去的那串字符串,会非常有成就感。

4.4 结果分析与人工验证

如果 zsteg 已经输出了明文,那一切放心。但更常见的情况是,它输出了一堆看起来乱码的内容,比如二进制文件头或者 base64。这时候不要无脑复制,应该先分析输出的十六进制内容,判断它是什么文件类型。

比如输出是:

b1,bgr,lsb -> "\x50\x4B\x03\x04..."

看到\x50\x4B是PK,说明隐藏数据是一个 ZIP 压缩包。接下来就要用-E把这段数据提取出来,保存成文件再分析:

zsteg -E "b1,bgr,lsb" test.png > hidden.zip zipinfo hidden.zip

这个步骤是把 zsteg 从“检测工具”升级成“取证利器”的关键。所以我的实操流程永远是:先检测,定位通道;提取二进制流;根据文件头判断类型;再保存文件进一步处理。

5. 踩坑记录与常见问题排查

5.1 gem 安装失败的解决办法

我最初在某旧版本 Kali 上安装 zsteg 时,遇到了/usr/include/ruby-2.7/ruby.h not found之类的错误,原因是缺少 Ruby 开发头文件。解决办法很简单,先确保安装了:

sudo apt install ruby-dev

如果依然报错,再看是不是缺少 zlib:

sudo apt install zlib1g-dev

还有一类权限问题:如果不用 sudo 直接gem install zsteg,会被拒绝写入系统目录。我之前因为嫌 sudo 麻烦,试过gem install --user-install zsteg,但装完以后命令不在 PATH 里,反而更麻烦。所以老老实实用sudo gem install zsteg是最省心的。

5.2 图片明明有隐写却检测不出来

zsteg 只支持 PNG 和 BMP 两种无损格式图片。如果你拿到的是一张 JPEG,它大概率检测不出 LSB 信息,因为 JPEG 是有损压缩,像素在保存时已经被改过了,隐写数据很容易被破坏。所以遇到 JPG 图片时,先查元数据、先看文件尾部,再考虑用其他工具。

即使图片是 PNG,也可能检测不出来,原因大概率出在信息隐藏的位序和通道上。有些隐写工具会默认用 MSB,或者只把信息藏在某个特定通道。此时手动指定参数试试:

zsteg -a --msb channel.png

或者通过-c把所有通道轮流扫一遍:

for ch in r g b a; do zsteg -c $ch channel.png; done

如果还是没结果,可以怀疑这段隐写数据使用了加密或压缩,比如 stego 工具自带的加密机制。zsteg 对未经处理的明文数据最敏感,对高熵加密数据的识别率会明显下降。

5.3 内存不足与性能问题

zsteg 会把图片数据读取到内存里分析,超大图片或高分辨率图片可能导致内存占用过高。我处理过一张 12000×8000 的卫星图,直接跑zsteg -a时系统内存几乎被吃满。这种情况下可以先用图像处理软件缩小图片尺寸,或者先裁剪局部区域分析。另外,尽量在干净的 Kali 环境中运行,避免同时开太多重型应用。

5.4 误报一箩筐,如何判断真假

zsteg 的输出会有一些“看似有内容但实际是图片本身的噪声”。比如全白图片的 LSB 全是 1,分析出来的位流有可能被误判为可打印字符串。这时候不能只看有没有字符串,还要结合上下文判断。

我的校验方法是:把提取出的内容保存下来,用file命令看真实类型;如果是纯文本,就观察是不是连续可读;如果是文件头,就解压验证 CRC。如果只是几个零散 ASCII 字符,大概率是误报。还有一个技巧是:用 zsteg 扫描一张干净的、无隐写的同类图片作为基线,对比输出。如果两者都出现同样的“异常”,那基本可以断定是图片本身的结构特征,不是隐写。

6. 我的使用心得与扩展思路

6.1 使用习惯

现在我在 Kali 里做图片检查时,默认流程已经固定下来:先exiftool看元数据,再strings扒一次文本,然后立刻zsteg -a。如果 zsteg 报告隐藏数据,先用-E提取,再根据文件头判断下一步。这个过程熟练后,一张图不到一分钟就能完成初步排查。

另外我会把 zsteg 的输出重定向到文件,方便回看。比如:

zsteg -a image.png | tee zsteg_report.txt

这样做的好处是,当图片很多时,可以批量扫描后统一分析,而不是在终端里一屏一屏翻。批量扫描我一般配合一个简单的循环:

for img in *.png; do echo "=== $img ===" zsteg -a "$img" | grep -E -i "flag|cipher|txt|zip|rar|PNG|BMP" || true done

这只是一个粗糙的过滤,但很实用。它会突出显示含有关键字样的输出,减少人工排查时间。

6.2 和其他工具配合的完整流程

zsteg 不是万能的,很多隐藏数据需要多工具配合才能找到。我遇到的最大一个坑是图片里藏了一个压缩包,但 zsteg 只能检测出像素低位有数据,无法直接导出完整的压缩包。这时候需要把 zsteg 提取的内容与 binwalk 结合。

具体做法是先提取可疑数据到文件:

zsteg -E "b1,bgr,lsb" image.png > extracted_data file extracted_data binwalk extracted_data

如果 binwalk 发现了嵌套文件,就可以用binwalk -e自动分离。另外,如果图片携带了 EXIF 信息,exiftool 也能补充不少线索。还有 steghide 适用于已知密码的隐写场景,密码可能藏在图片文件名或题目描述里。这些工具配合起来,基本覆盖了绝大多数图片隐写的处理方式。

6.3 最后再分享一个小技巧

我个人在实际操作中有一个体会:zsteg 的-v参数看起来只是输出调试信息,但在图片扫描结果异常时非常有用。它会打印出正在尝试的每个通道和位顺序,帮你看懂它到底在做什么,甚至能根据调试信息自己推断新的提取思路。

比如有一段调试输出显示“trying bgr lsb...”,但最终没有输出任何内容。这时可以手动尝试-E "b1,bgr,msb",说不定能把隐藏数据翻出来。因为 zsteg 的自动扫描集合并不等于全部可能组合,手动调整参数往往能发现意外结果。

另外,如果你经常参加比赛或做取证分析,建议写一个小的自定义脚本,把 zsteg、binwalk、exiftool 串起来。我自己的做法是:传入一个图片路径,脚本自动跑完整流程,并把所有输出存到一个目录里。这样不仅方便复盘,也能在紧急场景下快速响应。工具不会每次都直接给你答案,但一套可靠的处理流程会。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询