前两天刚听说“隐写术”这个词,听着挺像火影忍者里的招数哇??
趁着好奇,边学边做了张“隐写术图片”,后面会一步一步分享做的过程。初次尝试,有丢丢激动。
据说CTF里常用隐写术,不过作为未接触CTF的人,还请各路大神轻喷。
目测依旧是比较啰嗦的一篇,所以不想看全文的同学可以根据目录挑着看呀。
那,我们一起来做一张隐写图片吧~
/***** 这里是目录******/
一、隐写术?
- 载体有哪些
- 如何隐藏
- 如何发现有隐藏信息
- 如何提取隐藏信息
二、工具、环境
三、制作基础图种
四、来骗骗binwalk呀
五、制作小混合隐写图片
六、总结
/***** 这里是分割线******/
一、隐写术?
隐写术,就是在载体里隐藏信息,使非目标接收者无法找到隐藏的信息,最好的状态当然是无法感知有隐藏的信息。
这就涉及到且不限于以下几个方面:
1、载体有哪些
2、如何隐藏
3、如何发现有隐藏信息
4、如何提取隐藏信息
1、载体有哪些
贴一张从其他地方找来的图片(做学习笔记的时候没记录下链接,后续有发现来源再贴上出处)
作为初学者,感觉隐写术是片海,所以先挑着学呗,先学个“图像隐写术”。本帖子涉及的内容,也仅限在这范围内。“抛砖引玉”,“举一反三”(咋这么像我中学老师呢。。)
2、如何隐藏
(1)图种
百度百科解释:
“一种采用特殊方式将图片文件(如jpg格式)与压缩文件结合起来的文件。该文件一般输出为jpg图片文件,可以正常预览图片。”
我的个人理解:
图片具有“图片结束符”,利用“图片查看器会直接忽略图片结束符后面的数据”,将欲隐藏的信息藏于图片结束符后面,即可达到“骗过图片查看器”从而使人察觉不到数据隐藏的目的。
隐藏方式:追加数据。
检测工具:binwalk等。
(2)LSB:
LSB解释:https://www.jianshu.com/p/5d2b3f0edff1
即Least Significant Bit,修改图片像素中三原色之一的颜色(如红色)所属的8bit中的最低有效位,将待隐藏的数据转化成二进制形式并写入,从而进行信息的隐藏。由于每个像素中改动的不多,人眼并无法区分出来“颜色差”,故无法察觉“信息隐藏”。
隐藏方式:修改数据。
检测工具:Stegsolv.e等。
(3)更多:等待学习中。。。
如何发现有隐藏信息 + 如何提取隐藏信息,那就得具体情况具体分析了。隐写术的方法很多,对应的发现/提取的操作也不一样,这里就不多说啦(作为初学者,也多说不出来哇。)
/***** 这里是分割线******/
二、工具、环境
电脑:windows 10
实现隐写:“copy /b”命令,010Editor工具等。
发现隐写:binwalk
隐写提取:010Editor(十六进制分析器)
附:binwalk的下载链接为https://github.com/ReFirmLabs/binwalk.git,需实现安装python,并在binwalk的下载目录下利用“python setup.py install”命令来进行binwalk安装,随后可在python安装路径下的Script文件夹下发现binwalk文件。
/***** 这里是分割线******/
三、制作基础图种
1、学习链接:https://zhuanlan.zhihu.com/p/30539398
该链接里介绍了多种隐写术操作,挺适合萌新的。
2、事前准备
载体照片,即可被别人看见的照片,将其命名为:originOne.jpg
待隐藏数据,我采用的依旧是一张照片,即我要隐藏的是一张照,将其命名为:forHide.jpg
3、预期效果
利用隐写术,将forHide.jpg与originOne.jpg进行融合得到output.jpg文件,使别人(即图片查看器)在查看output.jpg图片时仅能查看到originOne.jpg图片,而无法发觉forHide.jpg的存在。
4、进行隐写
用命令“copy /b originOne.jpg+forHide.jpg output.jpg”来实现“从二进制层面进行两个文件的拼接”。加号“+”后面的文件为要隐藏的数据。拼接后的文件大小等于两个原始文件的大小总和。
5、图片查看器查看结果
利用图片查看器“画图”打开原始文件originOne.jpg与拼接后的文件output.jpg,无法看出两者的区别:
6、从十六进制层面看结果
在010Editor工具打开output.jpg,搜索jpg结束符FFD9,可找到3个不同的位置。在知道2张原始文件均为jpg文件的情况下,是可以直接定位到originOne.jpg的文件结束符在第二张图片(因为forHide.jpg的文件开始符为FFD8),forHide.jpg的文件结束符在第三张图片:
7、从检测工具看结果
将output.jpg文件拷贝到binwalk的运行环境 xx\python\Scripts\目录中,执行命令“python binwalk output.jpg”,可以看出,output.jpg中包含了2张jpeg格式文件,两个文件的起始位置分别为0x0与0x30FE73,故并隐藏起来的图片forHide.jpg的起始位置应该为0x30FE73。
8、定位
在010Editor工具中,定位到output.jpg的0x30FE73位置,在此位置可以找到jpg文件的开始符FFD8:
9、结果验证
在010Editor工具中,将0x30FE73位置前的所有数据删除,并另存为extract.jpg文件,与原始的forHide.jpg相比,两者看起来一样,且哈希一致,说明已提取成功。
10、最基础的图种就做出来啦。撒花~
/***** 这里是分割线******/
四、来骗骗binwalk呀
1、目的
上一步仅能“骗过图片查看器”,binwalk一下子就能发现output.jpg里是有两张图片的呀,那这里就看下如何骗过binwalk吧。
2、怎么骗呀
从binwalk的输出结果来看,大胆猜测其工作原理之一为:从二进制数据层面,寻找普通文件的文件符(如jpg的文件开始符FFD8,结束符FFD9),从而判断是否存在该类型文件并对其进行定位。
3、实施操作
在010Editor工具中,打开output.jpg文件,删除0x30FE73处的FFD8(jpg文件开始符),为了达到隐藏的目的则“保留”文件最尾部的FFD9(jpg文件结束符),即用forHide.jpg的文件结束符伪装成originOne.jpg的文件结束符,生成文件noStartFlags.jpg。对比处理前的output.jpg与去除开始符的noStartFlags.jpg,两者从图片查看器上一致,但两者的哈希不同,且后者比前者少了2个字节(开始符2个字节):
4、查看初步结果 将noStartFlags.jpg放置到binwalk运行文件同目录\python\Scripts下,利用binwalk查看noStartFlags.jpg与output.jpg文件结构,前者显示仅有一个JPEG数据,后者显示有两个JPEG数据,但两者均有2个TIFF image data提示。可以得出两个结论:刚刚的猜测问题不大;还没成功骗过binwalk:
5、去除TIFF提示
在010Editor工具中,将noStartFlags.jpg中forHide.jpg文件的APP0段(以FFE0为标识,共18个字节)与APP1段(以FFE1为标识,共18个字节)的数据删除,生成noAPPx.jpg文件:
6、查看结果 将noAPPx.jpg、output.jpg、originOne.jpg的对比如下,此时已无法使用binwalk工具来发现noAPPx.jpg文件比originOne.jpg文件多隐藏了一份文件,即此时隐写术已骗过binwalk与图片查看器:
7、稍作处理的图种已经能骗过binwalk跟图片查看器啦。撒花~
欲提取的话,只要把forHide.jpg的头部填充回去就可以了哇。
/***** 这里是分割线******/
五、制作小混合隐写图片
1、目的
若近有noAPPx.jpg文件,而不知道forHide.jpg的头部,那也无法重新将forHide.jpg复原提取(如果大神们有其他方法的话,欢迎指教呀),故此阶段将forHide.jpg作为待隐藏的数据,一同防止在最终图片final.jpg中(此时还未制作出final.jpg图片)。
2、思路
从final.jpg中复原forHide.jpg图片<---- 需要从final.jpg中提取到forHide.jpg头部信息<------- 故需提前在final.jpg中隐藏forHide.jpg头部信息。
“在final.jpg中隐藏forHide.jpg头部信息”,目前有两个想法:
(1)在noAPPx.jpg图片中originOne.jpg的Exif位置写入forHide.jpg头部信息,从而得到final.jpg文件;
但该方法容易被发现,即只要点击final.jpg文件,右键查看属性就能发现啦。
(2)将forHide.jpg头部信息藏于一张新的不相关图片third.png中,再将third.png拼接到noAPPx.jpg后,从而得到final.jpg文件。
使用该方法,还能将third.png伪装成“目标文件”,让人误以为它就是被隐藏的文件,从而没发现真正被隐藏的forHide.jpg文件。(自我觉得是这样,哈哈哈哈哈哈哈哈)
在这里,我采用的是(2)这个方法,先剧透一下步骤:
使用一个可推测出来的KEY作为密钥,加密forHide.jpg头部信息并利用LSB保存到third.png图片从而生成withKEY2.png图片;以KEY为密钥,加密KEY本身并保存到output.jpg中forHide.jpg的头部从而生成withKEY.jpg图片;将withKEY.jpg与withKEY2.jpg进行拼接并达到隐藏withKEY2.png的目的,生成final.jpg问津。
3、实施操作
(1)KEY值的确定
KEY值采用固定格式:“firstFileis”+第一个文件格式
即,当目标接收者拿到final.jpg文件时,他能知道KEY值为:firstFileisJPG
(2)加密forHide.jpg头部信息
forHide.jpg头部信息为:文件开始符(2个字节) + APP0段(18个字节) + APP1段(18个字节),共38个字节。
使用AES加密,加密算法为CBC,密钥为KEY,加密结果采用base64编码,从而得到加密后的数据位“P2y8vkjd5K5na4hOnxIaIoPpOokXhutio0uOnndKg5D6YzBngWtQkevsvkbXZlPgAwzw8MZvYyZnf5HzgQFFaZ3nuXaq0KLP45C17uFU7htR1Ajm0VnIynouo+XpYWOw”,记为KEY2:
(3)保存KEY2
LSB的python脚本:https://www.jianshu.com/p/0875b388428f
使用LSB脚本,将KEY2写入third.PNG照片并生成withKEY2.png,两者的哈希不同,但从图片查看器的角度无差别。
(4)加密KEY值并保存
对KEY使用AES加密,加密算法为CBC,密钥为KEY本身,加密结果采用base64编码,从而得到“5M6ezC8G7w140LyOKlPJ3w==”。将其放置在output.jpg中forHide.jpg文件的文件开始符+APP0段+APP1段的数据(共38个字节)替换成所得的“5M6ezC8G7w140LyOKlPJ3w==”,剩余位置用00补齐,生成文件withKEY.jpg:
(4)生成final.jpg
利用“copy /b withKEY.jpg+withKEY2.pngfinal.jpg”,生成最终的图片final.jpg。此时,binwalk仅发现final.jpg藏有2张照片(originOne.jpg与third.png),而未发现隐藏图片forHide.jpg。且图片查看器依旧发现不了originOne.jpg与final.jpg的区别,但看两者哈希是完全不一样的。
/***** 这里是分割线******/
六、总结
final.jpg的生成过程
(1)隐藏文件为forHide.JPG,显示文件为originOne.jpg,迷惑文件为third.PNG。
(2)将originOne.jpg与forHide.JPG以二进制形式进行拼接,得到output.jpg;
(3)设置指定格式的加密密钥KEY,对forHide.JPG头38个字节用AES加密,并利用LSB将其保存到withKEY2.png文件,即隐藏在third.PNG后面;
(4)以KEY为密钥,对KEY本身进行AES加密,将其保存在output.jpg中属于forHide.JPG头38个字节的位置处,用00补足,生成文件withKEY.jpg;
(5)将withKEY.jpg与withKEY2.png进行拼接,得到final.jpg(此时final.jpg真实含有3张图片,但binwalk仅可发现2张)。
(写完才自己发现,其实没必要对KEY再加密了呢,不过个人感觉问题不大,反正这次的目的是学习“隐写”~)
|