snowww

点击此处获得更好的阅读体验


WriteUp来源

https://mp.weixin.qq.com/s/AzUrC5JD-bVb8mDL0JB4bQ

题目描述

It's really cold this winter, can you find what is hidden in snow {{{(>_<)}}} 附件下载 提取码(GAME)

题目考点

解题思路

官方WP

此题是根据大厂为了防止信息泄密,使用的屏幕拍摄溯源技术改来的。使用binwalk可以发现图片包含两部分,上部分为加了水印的图片,下部分为一个解码水印所需要的信息压缩包。

将后缀名修改为rar就可以用winrar打开了,得到的信息包括原始图像,信息分布矩阵和水印编码方法。

是在原始图像转换到频域中,并添加随机分布的信息再变换回时域。

这种在频域添加信息的技术可以很好的抵抗图片伸缩、对比度、亮度和一些其他修改,并且可以配合预设的分布矩阵做到神不知鬼不觉就在图片中增加了水印信息。

解码步骤则是将原始图像和水印图像进行频域变换后进行对比,根据编码时的分布矩阵拼回原始信息。

详细原理可以参考知乎文章《阿***公司根据截图查到泄露信息的具体员工的技术是什么?》最高赞@fuqiang liu 的回答

https://www.zhihu.com/question/50735753/answer/1480579261

得到藏在频域的信息

大佬WP by NanoApe

binwalk 之后看到里面有藏图 .m .mat 文件,然后逆向解密一下就行了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
clc;clear;close all;
load('encode.mat','M', 'N');
alpha = 80;
im = double(imread('original.jpg'))/255;
im2 = double(imread('snow.jpg'))/255;
imsize = size(im);
FA2=fft2(im2);
FA=fft2(im);
G=(FA2-FA)/alpha;
GG=G;
for i=1:imsize(1)*0.5
for j=1:imsize(2)
GG(M(i),N(j),:)=G(i,j,:);
end
end
for i=1:imsize(1)*0.5
for j=1:imsize(2)
GG(imsize(1)+1-i,imsize(2)+1-j,:)=GG(i,j,:);
end
end
imwrite(GG,'output5.jpg');

大佬WP by ThTsOd

图片文件末尾存放 Rar 文件,打开后存放 matlab 代码和数据,经查是 FFT 隐写(https://www.zhihu.com/question/50735753)

没有安装 matlab,解析 matlab 数据,打开 encode.mat 发现里面有两份 78 9c 开头的 zlib压缩数据,解压。

观察数据,结合隐写代码,发现这是图片长、宽序号的随机分布数据。 按照知乎上的 matlab 代码重写 Python 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
import struct
M=[]
N=[]
f=open('data1.dat','rb')
f.seek(0x34)
length=struct.unpack("I",f.read(4))[0]
print(length)
for i in range(length//2):
M.append(struct.unpack("H",f.read(2))[0])

f.close()
f=open('data2.dat','rb')
f.seek(0x34)
length=struct.unpack("I",f.read(4))[0]
print(length)
for i in range(length//2):
N.append(struct.unpack("H",f.read(2))[0])
f.close()
img = cv.imread('./snow.jpg', 0)/255.0
width=1920
height=1080
ori = cv.imread('./original.jpg', 0)/255.0
FAO = np.fft.fft2(img)
FA = np.fft.fft2(ori)
alpha=80
G=(FAO-FA)/alpha
GG=(FAO-FA)/alpha
for i in range(height//2):
for j in range(width):
GG[M[i]-1][N[j]-1]=G[i][j]

for i in range(height//2):
for j in range(width):
GG[height-i-1][width-j-1]=GG[i][j]
print(GG)
GGG=20*(np.real(GG))
plt.imsave('s1.jpg',GGG)

解出图片

大佬WP by nsigma

先对 snow.jpg 进行 foremost, 得到一个压缩包, 里面有 encode.m, encode.mat, original.jpg.

打开encode.m, 这是一个 matlab 脚本, 可以看出是将 watermark.png 和 original.jpg 进行了混合. 具体的混合方式是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
%% Run on Matlab2012b
clc;clear;close all;
alpha = 80;
%% 读入图片, 将rgb值从 [0, 255] 约化至 [0, 1], 从之后的步骤可以看出两张图片的分辨率为
%% original.jpg: 1920x1080
%% watermark.png: 1920x540
im = double(imread('original.jpg'))/255;
mark = double(imread('watermark.png'))/255;
imsize = size(im);
TH=zeros(imsize(1)*0.5,imsize(2),imsize(3));
TH1 = TH;
%% 将 watermark.png 拷贝到 TH1 上
TH1(1:size(mark,1),1:size(mark,2),:) = mark;
%% 将 TH1 的分量进行一个随机的置换, (M(i), N(j)) 挪到 (i, j), 并将映射保存在 encode.mat中
M=randperm(0.5*imsize(1));
N=randperm(imsize(2));
save('encode.mat','M','N');
for i=1:imsize(1)*0.5
for j=1:imsize(2)
TH(i,j,:)=TH1(M(i),N(j),:);
end
end
%% mark_ 的上半部分就是 TH, 下半部分是中心对称
mark_ = zeros(imsize(1),imsize(2),imsize(3));
mark_(1:imsize(1)*0.5,1:imsize(2),:)=TH;
for i=1:imsize(1)*0.5
for j=1:imsize(2)
mark_(imsize(1)+1-i,imsize(2)+1-j,:)=TH(i,j,:);
end
end
%% 进行 2d-Fourier, 然后按照一个简单的方式叠加, 存在 snow.jpg, 也就是我们最开始获得的图片中
FA=fft2(im);
FB=FA+alpha*double(mark_);
FAO=ifft2(FB);
imwrite(FAO,'snow.jpg');

由此得到逆向操作的脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
clc;clear;
alpha = 80;
load("encode.mat", "M", "N");
im = double(imread("original.jpg"))/255;
snow = double(imread("snow.jpg"))/255;
FB = fft2(snow);
FA = fft2(im);
mark_ = (FB-FA) / alpha;
%% 这里只读取 mark_ 的上半部分
TH = zeros(540, 1920, 3);
TH(1:540, :, :) = mark_(1:540, :, :);
%% 做置换的逆变换
TH1 = zeros(540, 1920, 3);
for i=1:540
for j=1:1920
TH1(M(i), N(j), :) = TH(i, j, :);
end
end
imwrite(abs(TH1), "./tmp.png");

最后得到一张图片, 稍微调整一下图片的对比度亮度之类的值, 可以看到flag的内容。

Flag

1
flag{c93fd2a3-103f-4539-9a51-ad5a6437daa1}