[2021 DASCTF July X CBCTF 4th]
just a gif
先用16进制编辑器打开看看有没有隐藏其他文件 打开后没发现其他文件
再用Stegsolve打开一帧一帧地看 发现一共451帧 有11帧是不同的 剩余的都以前11帧为一组循环
猜测相对应(图片内容基本相同)的2帧可能有些像素不同
先用脚本分离gif中的每一帧
#需要先安装pillow库
import os
from PIL import Image
gif=Image.open("E:/code/python-ctf/杂项/Just_a_GIF.gif")#gif路径
os.mkdir("./png")
for i in range(gif.n_frames):
gif.seek(i)
temp=Image.new("RGB",gif.size)
temp.paste(gif)
temp.save("./png/"+str(i)+".png")
然后再用脚本比较相对应(图片内容基本相同)的2帧
import os
from PIL import Image
p1=Image.open("./png/"+str(0)+".png")
a,b=p1.size
f=Image.new("RGB",p1.size,(255,255,255))
p2=Image.open("./png/"+str(11)+".png")
for x in range(0,a):
for y in range(0,b):
if p1.getpixel((x,y))!=p2.getpixel((x,y)):
f.putpixel((x,y), (0,0,0))
f.save("./flag/temp.png")
和猜测的一样
把后面所有图片都与相对应的第一帧比较
import os
from PIL import Image
os.mkdir("./flag")
for i in range(0,11):
p1=Image.open("./png/"+str(i)+".png")
a,b=p1.size
f=Image.new("RGB",p1.size,(255,255,255))
#f=Image.new("RGB",(83,83),(255,255,255)) 改尺寸把上一句删了 把这句前面的注释删了
for t in range(1,41):
p2=Image.open("./png/"+str(t*11+i)+".png")
for x in range(0,a):
for y in range(0,b):
if p1.getpixel((x,y))!=p2.getpixel((x,y)):
f.putpixel((x,y), (0,0,0))
f.save("./flag/"+str(i)+".png")
发现所有图片右边都是空白 说明图片的尺寸不对(应该为83*83) 把上面脚本改下
发现后面2张图应该是前几张图片的拼法(我的图片从0开始编号 出题人从1开始)
然后用脚本拼图
from PIL import Image
a=[7,1,6,9,3,4,5,2,8]
f=Image.new("RGB", (83*3,83*3))
for i in range(0,3):
for j in range(0,3):
path="./flag/"+str(a[i+j*3]-1)+".png"
x=Image.open(path)
f.paste(x,(i*83,j*83))
f.save("flag.png")
然后用barcode scanner(这个软件比较牛逼 谷歌商店有)扫码
完整脚本(从头到flag)
import os
from PIL import Image
#gif分离
gif=Image.open("E:/code/python-ctf/杂项/Just_a_GIF.gif")
os.mkdir("./png")
for i in range(gif.n_frames):
gif.seek(i)
temp=Image.new("RGB",gif.size)
temp.paste(gif)
temp.save("./png/"+str(i)+".png")
#图片对比
os.mkdir("./flag")
for i in range(0,11):
p1=Image.open("./png/"+str(i)+".png")
a,b=p1.size
f=Image.new("RGB",(83,83),(255,255,255))
for t in range(1,41):
p2=Image.open("./png/"+str(t*11+i)+".png")
for x in range(0,a):
for y in range(0,b):
if p1.getpixel((x,y))!=p2.getpixel((x,y)):
f.putpixel((x,y), (0,0,0))
f.save("./flag/"+str(i)+".png")
#图片拼接
a=[7,1,6,9,3,4,5,2,8]
f=Image.new("RGB", (83*3,83*3))
for i in range(0,3):
for j in range(0,3):
path="./flag/"+str(a[i+j*3]-1)+".png"
x=Image.open(path)
f.paste(x,(i*83,j*83))
f.save("flag.png")
nuclear wastewater
先扫描二维码 扫完后发现没啥用
然后用16进制编辑器打开看看有没有隐藏其他文件 打开后没发现其他文件
再用Stegsolve打开看看有没有lsb隐写 发现没有
仔细观察图片发现有一部分图片被污染了
猜测信息可能藏在被污染的部分
from PIL import Image
t = open("a.txt", "w", encoding="utf-8")
png = Image.open("Nuclear wastewater.png")
a, b = png.size
for x in range(0, a):#改成for x in range(0, a, 10):
for y in range(0, b):#改成for y in range(0, b, 10):
temp = png.getpixel((x, y))
if temp != (255, 255, 255) and temp != (0, 0, 0):
t.write(str(temp) + "\n")
t.close()
发现每个数据都重复10次 RGB颜色中都只有一位不为0
把上面循环的步长改成10再把这些不为0的数据提出来
from PIL import Image
t = open("a.txt", "w", encoding="utf-8")
png = Image.open("Nuclear wastewater.png")
a, b = png.size
for x in range(0, a, 10):
for y in range(0, b, 10):
temp = png.getpixel((x, y))
if temp != (255, 255, 255) and temp != (0, 0, 0):
R, G, B = temp
if R != 0:
t.write(str(R) + "\n")
elif G != 0:
t.write(str(G) + "\n")
else:
t.write(str(B) + "\n")
t.close()
RGB颜色的范围是(0,0,0)-(255,255,255) 尝试把数据转成ASCII字符
from PIL import Image
png = Image.open("Nuclear wastewater.png")
a, b = png.size
for x in range(0, a, 10):
for y in range(0, b, 10):
R, G, B = png.getpixel((x, y))
if 0 < R < 255:
print(chr(R), end="")
if 0 < G < 255:
print(chr(G), end="")
if 0 < B < 255:
print(chr(B), end="")
发现有好多重复出现的字符 去掉重复的试试
from PIL import Image
list=[]
png = Image.open("Nuclear wastewater.png")
a, b = png.size
for x in range(0, a, 10):
for y in range(0, b, 10):
R, G, B = png.getpixel((x, y))
if 0 < R < 255:
if chr(R) not in list:
list.append(chr(R))
if 0 < G < 255:
if chr(G) not in list:
list.append(chr(G))
if 0 < B < 255:
if chr(B) not in list:
list.append(chr(B))
for i in list:
print(i,end="")
可能应该按重复字符的个数排序
from PIL import Image
list = []
png = Image.open("Nuclear wastewater.png")
a, b = png.size
for x in range(0, a, 10):
for y in range(0, b, 10):
R, G, B = png.getpixel((x, y))
if 0 < R < 255:
list.append(chr(R))
if 0 < G < 255:
list.append(chr(G))
if 0 < B < 255:
list.append(chr(B))
data = {}
for i in list:
data[i] = data.get(i, 0) + 1
result = sorted(data.items(), key=lambda x: x[1], reverse=True)
for i in result:
print(i[0], end="")
密码到!结束 (因为后面词频为1 出题人肯定不会将1的放进去 不然就不知道顺序)
打开解压后的文件 发现第一行第二个字符不是第二列
应该是0宽字节隐写
vim打开发现0宽字节是200c 200d 200e
找个网站解码Unicode Steganography with Zero-Width Characters (330k.github.io)
解码前勾上200c 200d 200e
解码结果
是Citrix CTX1加密
用CyberChef梭哈一下(github上有该工具)
解密1次没出flag 再解密一次试试
ezSteganography
先用16进制编辑器打开看看有没有隐藏其他文件 打开后没发现其他文件
再用Stegsolve打开
在Red plane0 发现提示
看G plane的每一位是否藏了信息
在G plane的0位发现了png文件头
将数据导出
网上查找有关qim量化的资料QIM量化 - 努力奋斗的阿贝拉 - 博客园 (cnblogs.com)
from PIL import Image
from Crypto.Util import number
import random
import time
import numpy as np
import matplotlib.pyplot as plt
def extract(delta,y):
out=[]
for i in (delta/2-y%delta):
if i>0:
out.append(1)
else:
out.append(0)
out=np.array(out)
return out
p=np.array(Image.open("E:/code/python-ctf/杂项/ezSteganography-flag.png"))
R,G,B=p[:,:,0],p[:,:,1],p[:,:,2]
G=G.ravel()
te_out=extract(20,G)
plt.imshow(np.array(te_out).reshape(1440,2560))
plt.show()
得出另一半flag