从0开始学杂项 第三期:隐写分析(2) PNG 图片隐写

2023-12-17 10:10

本文主要是介绍从0开始学杂项 第三期:隐写分析(2) PNG 图片隐写,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Misc 学习(三) - 隐写分析:PNG 图片隐写

在上一期,我主要讲了讲自己对于隐写分析信息搜集直接附加的一些浅薄理解,这一期我们继续对隐写分析的学习,开始讲隐写分析最喜欢考的一项——图片隐写,我们首先学习的是图片隐写中最基础的 PNG 图片隐写。(此文并非教学,我只是在这里记下我的笔记、我的心得、我的体会,请辩证看待、理性思考,不要全都当成真理)

图片隐写的方式有很多种。广义上,只要通过某种方式将信息隐藏到图片中而难以通过普通方式发现,就可以称为图片隐写。由于我太菜,本系列只对一些常见的图片隐写方式进行简单介绍,其它进阶技巧请大家自行尝试。

这篇文章部分来自于我为了科学之光冬令营20号下午的讲课所准备的大纲。

一. PNG 文件结构

一个 PNG 文件格式为:

文件头(89 50 4E 47 0D 0A 1A 0A) + 数据块 + 数据块 + 数据块…… + 文件尾(00 00 00 00 49 45 4E 44 AE 42 60 82)

PNG 定义了两种类型的数据块,一种是称为关键数据块,这是标准的数据块,另一种叫做辅助数据块,这是可选的数据块。关键数据块定义了4个标准数据块,每个 PNG 文件都必须包含它们。

每个数据块都有着统一的结构,由 4 个部分组成:

其中CRC域中的值是对数据块类型码和数据进行计算得到的,CRC具体算法定义在ISO 3309和ITU-T V.42中,其值按CRC码生成多项式进行计算

我们可以用 pngcheck 去查看PNG文件数据块信息。 PS:结构什么的看看就行,最好能掌握,掌握不了也没关系,咱可以做中学

IHDR(文件头数据块)

第一块是文件头数据块IHDR),它由第11——32字节组成(从0开始),包含有 PNG 文件中存储的图像数据的基本信息,数据从第 16字节开始,有13个字节,其前8字节分别用4个字节规定了图片的宽和高(十六进制,以像素为单位)。

IDAT(图像数据块)

它存储实际的数据,在数据流中可包含多个连续顺序图像数据块。它采用 LZ77 算法的派生算法进行压缩,可以用 zlib 解压缩。

二. IHDR 篡改图片宽高

IHDR 的前8字节规定了图片的宽和高,我们可以用十六进位文件编辑器更改它们以使得这张图片显示不完整,从而达到隐藏信息的目的。此时它的图片数据并没有变,在Windows图片查看器中超过规定的图片宽高的部分只是不显示了。

细心的同学会发现在 Kali Linux 中是打不开这张图片的,会提示 IHDR CRC error,这是因为在每个数据块的最后4字节都有CRC(循环冗余检测)用来检测是否有错误和被篡改。聪明的同学自然就想到是不是可以用CRC反推图片原来的宽和高,答案是肯定的,我们可以利用 python 脚本反推图片原宽高,然后用十六进制编辑器打开图片修改图片宽高得到原图片。

#使用 python [脚本文件名] [图片文件名]
import zlib
import struct
import sysfilename = sys.argv[1]
with open(filename, 'rb') as f:all_b = f.read()crc32key = int(all_b[29:33].hex(),16)data = bytearray(all_b[12:29])n = 4095for w in range(n): width = bytearray(struct.pack('>i', w))for h in range(n):height = bytearray(struct.pack('>i', h))for x in range(4):data[x+4] = width[x]data[x+8] = height[x]crc32result = zlib.crc32(data)if crc32result == crc32key:print("宽为:",end="")print(width)print("高为:",end="")print(height)exit(0)

三. LSB 隐写

PNG 文件中的图像像数一般是由 RGB 三原色(红绿蓝)组成(有的图片还包含A通道表示透明度),每一种颜色占用8位,取值范围为0x00至0xFF。LSB 隐写就是修改 RGB 颜色分量的最低二进制位(LSB),它修改了每个像数颜色的最低的1 bit,而人类的眼睛不会注意到这前后的变化,这样每个像素可以携带3比特的信息。

如果是要寻找这种 LSB 隐藏痕迹的话,有一个工具 Stegsolve 是个神器,可以来辅助我们进行分析。通过下方的按钮观察每个通道的信息,我们可以捕捉异常点,抓住 LSB 隐写的蛛丝马迹(这玩意儿很难说,一般就是一看就感觉奇怪的n行或n列颜色块),进而利用 Stegsolve --> Analyse --> Data Extract 功能指定通道进行提取。

对于PNG和BMP文件中的 LSB 等常见的隐写方式,我们也可以使用 **zsteg **工具直接进行自动化的识别和提取。

四. IDAT 隐写

IDAT 块只有当上一个块充满(正常length最大65524)时,才会继续一个新的块。程序读取图像的时候也会在第一个未满的块停止(查了下W3C标准,其实是PNG图片在压缩的时候会在最后一个块的标记位标明这是最后一个数据块)。所以如果某一块没有满但后面却还有 IDAT 块则说明后面的块是“假”的。

我们可以用 pngcheck -v [文件名] 去查看PNG文件数据块信息,然后利用 python zlib 解压多余IDAT块的内容,此时注意剔除长度数据块类型及末尾的CRC校验值

import zlib
import binascii
IDAT = " ".decode('hex')	#双引号中填IDAT数据
result = binascii.hexlify(zlib.decompress(IDAT))
print(result)

例题

找了半天没找齐合适的例题,自己写了一个,大家凑合做

例题链接:https://pan.baidu.com/s/15xDrjIPRX06ygRxhPZiA8Q 提取码:6666

大家可以自己先尝试一下,一共有4个flag(有两个flag1,我打错了),如果有困难再去看下面的题解。

题解

日常先打开编辑器看一下,没发现明显问题。枚举一波,先试试 LSB 隐写,打开 Stegsolve,查看不同轨道,发现在Red/Green/Blue plane 0的上方均有明显隐写痕迹(那一条奇怪的黑白码)。

打开 Stegsolve --> Analyse --> Data Extract ,选中那三个有痕迹的轨道,先点 Preview,确实有PNG文件藏在里面,点击 Sava Bin 保存文件为 1.png。( Stegsolve 具体怎么用可能有缘写~,现在就这样用也差不多)

打开 1.png,是个二维码,用 QR Reserch 扫描得到 Flag1。

还剩下3个 flag,把图片扔到 Kali Linux 里,发现图片无法查看,说明 IHDR 被篡改,用上面的脚本爆破 IHDR 得到宽高。

用 Winhex 打开,找到 IHDR 中的宽高,更改一下(上面的“\x00”代表一个字节,第四个是符号是因为他刚好属于可打印字节,把它打到右边就行),保存,确定更新。

打开图片,看到 flag1(其实是 flag3 ,打错了)。

还有两个 flag,我们把更改过的图片扔到 Kali Linux 里,惊奇地发现(真的很惊奇,以前没见过没这种情况)还是没有预览,但是在图片查看器里可以正常显示,在火狐浏览器中无法显示却不报错,用 binwalk 分析一下,有个 zlib 文件,只能说很正常,没啥问题,再用 pngcheck 检查一下,发现异常,第二个 IDAT 块只有9895的长度,在没有满的情况一般来说是不会出现下一个块的,说明最后一个块是“假块”(那个 CRC ERROR 请忽略,只是我出题时懒得算CRC而已,真正做题是不会给你留这个 bug 的)。

我们重新用 Winhex 打开图片,搜索“IDAT”找到最后一个 IDAT 块,把里面的数据(只要数据,不要长度位、“IDAT”和那4位 CRC )复制到新文件里(CRC 是我瞎写的,所以上面会报错),保存成1.txt(没错,为了偷懒我压根没压缩成 zlib,你用 binwalk 是分离不出来的)。

得到一串奇葩文字,搜索得知这是与佛论禅加密

打开在线解密工具,解密得到 flag4。

最后还剩一个 flag,还记得我们扫出 flag1 的那个二维码吗?我们用 binwalk -e 扫描提取,发现能检测到 zip 尾,但是提取不出来。。。改用 foremost 提取,得到一个 zip 文件,打开看到里面有一个名字乱码的文本文件(无语),打开又是一堆迷惑代码。

这回是符号所以不太好搜索,只能靠经验得知这是 Brainfuck 代码,利用在线解密工具“Brainfuck to text”解密得到 flag2。

顺便说一下为什么“我们刚才用 binwalk -e 扫描提取,发现能检测到 zip 尾,但是却提取不出来”,用 WinHex 打开,发现在PNG文件尾与ZIP文件尾之间有“脏东西”,导致 binwalk 找不到文件头提取失败。(说实话,这个地方还能再出个 flag,我上一期说的两个同类型文件 夹在一块也是这种情况,如果你们遇到类似的情况也要注意看一下头尾之间有没有藏信息)

补充题:[BUUCTF] Flag (不是很明显,需要仔细看)

本期就先说到这里,主要讲了讲隐写分析中的 PNG 图片隐写,写的不太好的地方还请包涵并提出您宝贵的建议,我们下期再见。(顺便说一下,我发现在Winhex 里,“粘贴”是插入,“写入”是覆盖后面的)

参考资料

[1] CTF WIKI:https://ctf-wiki.org/misc/introduction/

[2] GAMERES:https://dev.gameres.com/Program/Visual/Other/PNGFormat.htm

[3] W3C 规范:https://www.w3.org/TR/2003/REC-PNG-20031110/

以上内容仅供参考,水平不高,大佬见笑。

上一期:隐写分析(1):直接附加

下一期:隐写分析(3):GIF 图片隐写

作者:CHTXRT

出处:https://blog.csdn.net/CHTXRT

本文使用「CC BY-ND 4.0」创作共享协议,转载请在文章明显位置注明作者及出处。

这篇关于从0开始学杂项 第三期:隐写分析(2) PNG 图片隐写的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/504001

相关文章

MySQL 内存使用率常用分析语句

《MySQL内存使用率常用分析语句》用户整理了MySQL内存占用过高的分析方法,涵盖操作系统层确认及数据库层bufferpool、内存模块差值、线程状态、performance_schema性能数据... 目录一、 OS层二、 DB层1. 全局情况2. 内存占js用详情最近连续遇到mysql内存占用过高导致

深度解析Nginx日志分析与499状态码问题解决

《深度解析Nginx日志分析与499状态码问题解决》在Web服务器运维和性能优化过程中,Nginx日志是排查问题的重要依据,本文将围绕Nginx日志分析、499状态码的成因、排查方法及解决方案展开讨论... 目录前言1. Nginx日志基础1.1 Nginx日志存放位置1.2 Nginx日志格式2. 499

Olingo分析和实践之EDM 辅助序列化器详解(最佳实践)

《Olingo分析和实践之EDM辅助序列化器详解(最佳实践)》EDM辅助序列化器是ApacheOlingoOData框架中无需完整EDM模型的智能序列化工具,通过运行时类型推断实现灵活数据转换,适用... 目录概念与定义什么是 EDM 辅助序列化器?核心概念设计目标核心特点1. EDM 信息可选2. 智能类

Olingo分析和实践之OData框架核心组件初始化(关键步骤)

《Olingo分析和实践之OData框架核心组件初始化(关键步骤)》ODataSpringBootService通过初始化OData实例和服务元数据,构建框架核心能力与数据模型结构,实现序列化、URI... 目录概述第一步:OData实例创建1.1 OData.newInstance() 详细分析1.1.1

Olingo分析和实践之ODataImpl详细分析(重要方法详解)

《Olingo分析和实践之ODataImpl详细分析(重要方法详解)》ODataImpl.java是ApacheOlingoOData框架的核心工厂类,负责创建序列化器、反序列化器和处理器等组件,... 目录概述主要职责类结构与继承关系核心功能分析1. 序列化器管理2. 反序列化器管理3. 处理器管理重要方

SpringBoot中六种批量更新Mysql的方式效率对比分析

《SpringBoot中六种批量更新Mysql的方式效率对比分析》文章比较了MySQL大数据量批量更新的多种方法,指出REPLACEINTO和ONDUPLICATEKEY效率最高但存在数据风险,MyB... 目录效率比较测试结构数据库初始化测试数据批量修改方案第一种 for第二种 case when第三种

解决1093 - You can‘t specify target table报错问题及原因分析

《解决1093-Youcan‘tspecifytargettable报错问题及原因分析》MySQL1093错误因UPDATE/DELETE语句的FROM子句直接引用目标表或嵌套子查询导致,... 目录报js错原因分析具体原因解决办法方法一:使用临时表方法二:使用JOIN方法三:使用EXISTS示例总结报错原

MySQL中的LENGTH()函数用法详解与实例分析

《MySQL中的LENGTH()函数用法详解与实例分析》MySQLLENGTH()函数用于计算字符串的字节长度,区别于CHAR_LENGTH()的字符长度,适用于多字节字符集(如UTF-8)的数据验证... 目录1. LENGTH()函数的基本语法2. LENGTH()函数的返回值2.1 示例1:计算字符串

Android kotlin中 Channel 和 Flow 的区别和选择使用场景分析

《Androidkotlin中Channel和Flow的区别和选择使用场景分析》Kotlin协程中,Flow是冷数据流,按需触发,适合响应式数据处理;Channel是热数据流,持续发送,支持... 目录一、基本概念界定FlowChannel二、核心特性对比数据生产触发条件生产与消费的关系背压处理机制生命周期

基于Python实现一个图片拆分工具

《基于Python实现一个图片拆分工具》这篇文章主要为大家详细介绍了如何基于Python实现一个图片拆分工具,可以根据需要的行数和列数进行拆分,感兴趣的小伙伴可以跟随小编一起学习一下... 简单介绍先自己选择输入的图片,默认是输出到项目文件夹中,可以自己选择其他的文件夹,选择需要拆分的行数和列数,可以通过