您现在的位置是:首页 >其他 >网络空间安全---隐写术网站首页其他
网络空间安全---隐写术
-----XyLinzc
隐藏信息探索
- 从靶机服务器的FTP上下载文件,找出隐写文件夹1中的文件,将文件中的隐藏信息作为Flag值提交;
那到图片的第一时间就要想起将它往WinHex里面托,看看其信息
在ASCII这列发现类似于base64编码的东西
知识普及:
Base64编码的特征:
- 一定是4的倍数
- 结尾一般为”=”(以等号”=”结尾)
- 一共由64个字符(26个大写字母,26个小写字母,10个数字[0-9],2个其它字符(”+“,”=”),一般都是”=”号)
在Winhex里面看ASCII码字符看不清,有其它乱码混淆,我们就要用到kali专门用于打印可见字符串的工具命令strings
在虚拟机中可以直接把物理机的东西拖进终端
Strings : 用于打印文件中可见的字符(后面直接接文件路径)
我们发现此处就一个base64的编码,那我们进行解码
解码:exho 密文 | base64 -d
分别解出后发现是半个flag值,那我们把它合并后解密的出flag
Flag{ U5e_3x1ftoo1 }
- 找出隐写文件夹2中的文件,将文件中的隐藏信息作为Flag值提交;
老样子拖进Winhex看看
一般看流量分析与隐写的十六进制分析时,先看头,再看尾,在看看中间有没有可疑的字符串
发现文件头没什么可疑的地方,在看看文件尾,噢,发现GNP, 这说明什么,说明图片的数据是反的,那我们用Python进行修正
Python源码:
with open("flag2.jpg","rb") as img: #"rb"以二进制的形式打开并读取
temp = img.read()[::-1] #读取文件后反序
with open("flag.jpg","wb") as new_img: #创建一个二进制图像文件,并格式化
new_img.write(temp) #写入反序后的文件类容
因为在Python中字符串也能进行切片操作,所以我们用[::-1]将读取到的二进制文件信息取反后写入新文件
得到Flag
Flag{ Mirrer_R3f3ct1on_H1dd3n_f14g }
- 找出隐写文件夹3中的文件,将文件中的隐藏信息作为Flag值提交;
文件是一个正在闪烁的gif, 可以隐约的发现图片中间有字
那么我们就可以采用Python中PIL库自带的函数Image来进行图像处理,也就是gif文件分离
Python源码:
#隐写术第3题Python解法
from PIL import Image #PIL库是开源的图像处理库,Image为PIL中最基本的图像处理模块
picture = [] #创建一个空列表,用于存储文件打开的状态
with Image.open("flag3.gif") as img: #打开文件
for frame in range(0,img.n_frames): #将gif文件变为一帧一帧的图片,n_frames是求图片的总帧数
img.seek(frame) #seek定位图片的帧数,图片的索引一般都是0开头
img.save(f"{frame}.png") #save保存图片
picture.append(Image.open(f"{frame}.png")) #将打开的png图片的状态存入列表,方便下次使用
i = Image.new("RGB",(img.n_frames*img.width,img.height)) #创建一块新画布,颜色模式为RGB,图像大小为:画布的宽度=原本的gif图像的宽度width*图像分离出的的帧数,画布的高度=原本gif图像的高度height
locate = 0 #locate用于定位粘贴的位置
for state in picture: #打开每一张png图像
i.paste(state,(locate,0)) #将打开的图像粘贴到画布上,(locate,0)为粘贴的位置(左上角)
locate += img.width #每一次粘贴后,重新都需要移动粘贴的坐标,这样才能将图片完美的合在一张图上,locate += img.width每次定位的坐标要在x轴上依次加上原本图像的宽度
i.show() #展示图片
得到Flag
Flag{ Bliss by Charles O'Rear }
- 找出隐写文件夹4中的文件,将文件中的隐藏信息作为Flag值提交;
发现有104张黑白不一的图片
那么我们就要想到 白0黑1 的原则
这样就达到了104位二进制,将它们依次分为13个字节(一个字节8位),然后将每一个字节转为十进制后在用chr转ASCII码即可
但手动输入太麻烦了,我们就借助Python中PIL库中的Image函数中的getpixel((x,y))去获取图像的像素点,
纯黑的RGB代码是: 00000000
纯白的RGB代码是: FFFFFFFF
所以计算它是否为
黑就是让R==0 or G==0 or B==0
白就是让R==255 or G==255 or B==255
但在这个文件中除了黑就只有白了,所以判断它是不是黑就行了
Python源码:
import re
from PIL import Image #导入图像处理库
#解题思路: 白0黑1, 将104张黑白图片根据白0黑1的规则转为104位二进制数(切记图像的顺序不能打乱)
strs = "" # 然后将104位二进制分为13组字节(也就是一组8位二进制)
# 在将每一组二进制转化成十进制, 在化为ASCII码依次输出即可
for img in range(104):
i = Image.open(f"{img}.jpg") #用循环依次打开104张图片
r,g,b = i.getpixel((0,0)) #在左上角取一个像素,分析红对应的色数,绿对于的色数,蓝对应的色数,并分别赋予r,g,b
if r==0 or g==0 or b==0: #判断是否为黑色(00000000)
strs += "1" #是黑色就添加一个 "1"
else: #因为在此相册中只有黑白两色,所以除了黑色以外就只有白色了
strs += "0" #是白色就添加一个 "0"
locate = 0 #用于定位每一组字节的结尾也就是下一组的开头
byte = [] #用于分组
# byte = re.findall(r".{8}", strs) #正则表达式 .表示任意字符 {8}表示每次找8位 用正则表达式找出的东西会自动整理成列表输出
for n in range(len(strs)+1): #将104位二进制分组为13组字节
if n % 8 == 0 and n != 0: #一个字节8位
byte.append(strs[locate:n]) #将每一组字节存入列表,方便查找
locate = n #定位每一组字节的结尾也就是下一组的开头(因为切片取值是顾头不顾尾)
flag = "" #用于存取flag值
for bits in byte: #取出字节
sum = 0 #用于求和, 也用于重置
cf = 7 #次方, 因为8位二进制转十进制的次方范围是: 2的0次方-2的7次方
for bit in bits: #取出字节的每一位
sum += int(bit)*pow(2,cf) #转为十进制, 因为字符串取值是从左往右,而二转十是从右往左, 所以次方需要依次递减, 又因为从字符串取出后还是字符, 所以需要转为int
cf -=1 #次方递减, 因为是逆序
flag += str(chr(sum)) #将十进制转为ACSII码存入字符串
print(flag) #打印flag
Flag{ FuN_giF }
- 找出隐写文件夹5中的文件,将文件中的隐藏信息作为Flag值提交。
是一个gif的文件打开后出现错误
拖进Winhex看看它的文件头与后缀名能不能对上
发现是一个不存在的文件头,大概率是出题人将文件头改了,那我们改回它原先的GIF文件头 ==> 47 49 46 38 39 61
GIF的文件头(47 49 46 38 39 61)一定要记住,这都是常考的
它的真面目浮出了水面
看起来和普通的静态图片是一样的,那这张图片就不正常了,说明这张图的闪烁频率特别快,想到频率,你会不会联想到摩斯密码,以GIF文件闪烁的时间间隔当做一串二进制数,然后再解密
那么解密的思想就来了,先记录GIF文件每一帧的闪烁频率,然后看GIF文件的总帧数是不是8的倍数,如果是就转二进制,如果不是,那就找规律把它变成8的倍数,然后按照规律将他的每一帧的间隔看成0或1,按顺序摆出来,在和上一题样,分组成字节,在转换为十进制后转ASCII依次输出即可
发现有306个数据,可它不是8的倍数,然后往下看,找到了2个不同的数据,306-2=304,正好304是8的倍数,所以我们可以方心的将这两个不一样的数据删除了,然后观察剩余的100和200,我们知道二进制就只有0和1两个值,所以就可以明摆的说这200就是0,反之100就是1,因为你想想在这里是不是只有100上能薅到1,所以200就只能是0了
Python源码:
from PIL import Image #从PIL库中导入图像处理函数Image
duration = [] #用于存储每一帧的帧率
with Image.open("flag5.gif") as img: #打开GIF文件
for frame in range(0,img.n_frames): #查询所有帧
img.seek(frame) #定位帧
duration.append(img.info["duration"]) # duration : 持续时间 ==> 也就是帧率 #在info中的信息都是存在字典里的,所有要用查字典的方法获取帧率
while 660 in duration: # while 条件 in 可迭代对象 ==> 判断条件在迭代对象中出现了几次,出现几次就执行几次循环
duration.remove(660) # remove : 删除列表中指定的元素
for loc in range(len(duration)): #获取duration列表中全部的下标
if duration[loc] == 100: #判读下标所对应的值是否等于100
duration[loc] = 1 #若是100,则将值替换成1
else: #在这个列表中除了100后就只有200了,所以不用在写一个elif
duration[loc] = 0 #若是200,则将值替换成0
flag = "" #用于存储flag值
value = "" #用于存储字节(一个字节8位二进制)
for key in duration: #依次取出duration中的二进制值
value += str(key) #将值依次存入value中
if len(value) == 8: #当value中的值满8位,也就是刚好到一个字节
sums = 0 #用于存储8位二进制转为十进制后的值
cf = 7 #用于存储次方
for bit in value: #将一个字节分为8位二进制
sums += int(bit) * pow(2,cf) #二进制转十进制
cf -= 1 #因为Python读取文件是从左往右,而我们算二转十是从右往左,所以要逆序
flag += chr(sums) #将化为十进制后的值转为ASCII
value = "" #用于清空使用后字节,方便下次使用冲突
print(flag) #打印flag值
Flag { 96575beed4dea18ded4735643aecfa35 }
各题Flag值
- Flag{ U5e_3x1ftoo1 }0
- Flag{ Mirrer_R3f3ct1on_H1dd3n_f14g }
3.Flag{ Bliss by Charles O'Rear }
4.Flag{ FuN_giF }
5.Flag { 96575beed4dea18ded4735643aecfa35 }
完