红帽杯2021 Misc
Posted H3rmesk1t
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了红帽杯2021 Misc相关的知识,希望对你有一定的参考价值。
红帽杯2021 Misc
签到
根据附件文件名EBCDIC,可知是编码问题,转换即可,这里可以采用 010 Editor
flag为flag{we1c0me_t0_redhat2021}
colorful code
压缩包解压后得到两个data文件,试了下找不到什么有用的东西,想到题目名字,发现文件data2用十六进制查看符合颜色的十六进制编码
这里补充一个使用颜色编写代码的知识点,该题就用到了这个点Piet
从图中可以看出在前面的十六进制中是没有规律可寻的,但是在后面的一段中,它却是一直递增的,这里我们没啥思路暂且先放着,看看文件data1中有什么可以用到的知识点嘛
发现文件data1中是0-19的数字,用空格分开,结合data2文件中前面无序后面有序,我们不妨先看看前面有些啥,将每一个字节的十六进制转换成RGB十进制,三个一组
from binascii import *
with open(r'D:\\Users\\86138\\Desktop\\RedHat\\misc\\colorful_code\\data2','rb') as f:
f = hexlify(f.read()).decode()
n = 0
color_list = []
for i in range(0,len(f),2):
i = f[i:i+2]
color_list.append(int(i,16))
n += 1
if n == 3:
print(tuple(color_list))
color_list = []
n = 0
else:
continue
提取结果:
(0, 0, 0)
(0, 0, 192)
(0, 255, 255)
(0, 255, 0)
(255, 192, 255)
(255, 192, 192)
(192, 192, 255)
(192, 192, 0)
(255, 0, 255)
(255, 0, 0)
(192, 0, 0)
(192, 0, 192)
(255, 255, 255)
(255, 255, 0)
(255, 255, 192)
(0, 192, 0)
(0, 192, 192)
(192, 255, 255)
(192, 255, 192)
(0, 0, 255)
(20, 20, 20)
(21, 21, 21)
(22, 22, 22)
......
(253, 253, 253)
(254, 254, 254)
(255, 255, 255)
我们发现前20组数据的RGB值是无规律的,后面每一个数据的R、G、B值都一样,且依次递增到256为止
并且0-19一共也是20个数字,联想到每一个数字对应这一个颜色,我们先统计一下一共有多少个像素点
def str2list():
with open(r'D:\\Users\\86138\\Desktop\\RedHat\\misc\\colorful_code\\data1') as f:
f = f.read()
index_list = f.split(' ')
return index_list
print(len(str2list()))
统计结果显示一共有7067个像素点,我们利用质因数分解,得到图片的宽高值:
质因素分解网站
根据得到的值我们尝试结合宽高值对每个像素点进行putpixel()
我们先假设宽为37px,高为191px
from PIL import Image
from binascii import *
def str2list():
with open(r'D:\\Users\\86138\\Desktop\\RedHat\\misc\\colorful_code\\data1') as f:
f = f.read()
index_list = f.split(' ')
index_list = index_list[:len(index_list)-1]# 这里转换的结果最后一个是空格我们将其过滤掉
return index_list
def num2color():
with open(r'D:\\Users\\86138\\Desktop\\RedHat\\misc\\colorful_code\\data2','rb') as f:
f = hexlify(f.read()).decode()
n = 0
idx = 0
color_dic = {}
color_list = []
for i in range(0,len(f),2):
i = f[i:i+2]
color_list.append(int(i,16))
n += 1
if n == 3:
color_dic[idx] = tuple(color_list)
color_list = []
n = 0
idx += 1
elif idx == 20:
break
return color_dic
def genimg():
width, height = 37, 191
img = Image.new("RGB",(width,height))
imgpixels = str2list()
colorlist = num2color()
pixlist = []
for pix in imgpixels:
pixlist.append(colorlist[int(pix)])
idx = 0
for w in range(width):
for h in range(height):
img.putpixel([w,h], pixlist[idx])
idx += 1
img.save(r'D:\\Users\\86138\\Desktop\\RedHat\\misc\\colorful_code\\flag.png')
if __name__ == '__main__':
genimg()
代码运行得到我们需要的flag图片
我们对得到图片进行piet解密,解密网站
得到最后的flag
flag为flag{88842f20-fb8c-45c9-ae8f-36135b6a0f11}
PicPic
压缩包打开后看到challenge就预测到了是个套娃题,我们先看看给的代码
import os
import cv2
import struct
import numpy as np
def mapping(data, down=0, up=255, tp=np.uint8):
data_max = data.max()
data_min = data.min()
interval = data_max - data_min
new_interval = up - down
new_data = (data - data_min) * new_interval / interval + down
new_data = new_data.astype(tp)
return new_data
def fft(img):
fft = np.fft.fft2(img)
fft = np.fft.fftshift(fft)
m = np.log(np.abs(fft))
p = np.angle(fft)
return m, p
if __name__ == '__main__':
os.mkdir('m')
os.mkdir('p')
os.mkdir('frame')
os.system('ffmpeg -i secret.mp4 frame/%03d.png') #视频拆分多张照片
files = os.listdir('frame')
r_file = open('r', 'wb')
for file in files:
img = cv2.imread(f'frame/{file}', cv2.IMREAD_GRAYSCALE) #读取所有帧
m, p = fft(img)
r_file.write(struct.pack('!ff', m.min(), m.max()))
new_img1 = mapping(m) #绘制
new_img2 = mapping(p) #绘制
cv2.imwrite(f'm/{file}', new_img1)
cv2.imwrite(f'p/{file}', new_img2)
r_file.close()
os.system('ffmpeg -i m/%03d.png -r 25 -vcodec png 1.mkv')
os.system('ffmpeg -i p/%03d.png -r 25 -vcodec png 2.mkv')
代码中把原视频做了提取帧,然后把数据接入r,把帧进行fft变换,最后合成视频,一个是频域一个是相位,结合题目给的视频,我们进行解密运算
import os
import cv2
import struct
from cv2 import data
import numpy as np
from pathlib import Path
from tqdm import trange
path = Path('.')
r = open(path/'r', 'rb')
def unmap(data, down, up):
data_max = 255
data_min = 0
interval = data_max - data_min
new_interval = up - down
new_data = (data - data_min) * new_interval / interval + down
return new_data
if __name__ == '__main__':
os.mkdir('m')
os.mkdir('p')
os.mkdir('frames')
os.system('ffmpeg -i 1.mkv m/%03d.png')
os.system('ffmpeg -i 2.mkv p/%03d.png')
for i in trange(200):
filename = "%03d" % (i+1)+'.png'
m_img = cv2.imread(str(path/'m'/filename), cv2.IMREAD_GRAYSCALE) # mod
p_img = cv2.imread(str(path/'p'/filename), cv2.IMREAD_GRAYSCALE) # angle
r_octet = r.read(8)
m_min, m_max = struct.unpack('!ff', r_octet)
# rev_mapping
interval = m_max-m_min
unmap_m = unmap(m_img,m_min,m_max)
unmap_p = unmap(p_img,-np.pi,np.pi)
unmap_m=np.exp(unmap_m)
#print(old_data)
fft = unmap_m*np.exp(1j*unmap_p)
fft = np.fft.ifftshift(fft)
orig_img = np.fft.ifft2(fft)
#rint(np.abs(orig_img))
cv2.imwrite(str(path/'frames'/filename), np.abs(orig_img))
将上述脚本放在题目文件夹下运行,得到解密后的图片
图片中的字符串就是压缩包next_challenge的密码:zs6hmdlq5ohav5l1
在压缩包中我们得到了challenge2和challenge3
在challenge2里面可以看见一个hint以及一个具有噪声的二维码和一个噪声,查看hint,内容为html的math标签,改后缀名为html,打开得到
这是相位进行了互换,幅值是不变的,所以套用公式再变换一下相位即可
import os
import cv2
import struct
import numpy as np
from PIL import Image
def fft(img):
fft = np.fft.fft2(img)
fft = np.fft.fftshift(fft)
m = np.abs(fft)
p = np.angle(fft)
return m, p
if __name__ == '__main__':
img = np.array(Image.open(r'mix1.png').convert('L'))
img2 = np.array(Image.open(r'mix2.png').convert('L'))
m1, p1 = fft(img)
m2, p2 = fft(img2)
fft = m1*np.exp(1j*p2) #相位转换
fft2 = m2*np.exp(1j*p1) #相位转换
new_img1 = np.abs(np.fft.ifft2(np.fft.ifftshift(fft))) #绘制
new_img2 = np.abs(np.fft.ifft2(np.fft.ifftshift(fft2))) #绘制
#print(m)
#print(p)
cv2.imwrite(f'1.png', new_img1)
cv2.imwrite(f'2.png', new_img2)
得到还原后的二维码图片
扫码得到一串字符串:0f88b8529ab6c0dd2b5ceefaa1c5151aa207da114831b371ddcafc74cf8701c1d3318468d50e4b1725179d1bc04b251f
应该是要让我们解密,但是缺少一些提示和东西,我们再对challenge3做类似的图像处理
import os
import cv2
import struct
import numpy as np
from PIL import Image
import math
def mapping(data, down=0, up=255, tp=np.uint8):
data_max = data.max()
data_min = data.min()
interval = data_max - data_min
new_interval = up - down
new_data = (data - data_min) * new_interval / interval + down
new_data = new_data.astype(tp)
return new_data
def fft(img):
fft = np.fft.fft2(img)
m = np.fft.fftshift(fft)
m = np.log(np.abs(fft))
return m
if __name__ == '__main__':
img = np.array(Image.open(r'phase.png').convert('L'))
m = mapping(img,-np.pi,np.pi,np.float64 )
fft = np.exp(m*1j)
p = np.fft.fftshift(fft)
new_img1 = mapping(np.abs(np.fft.ifft2(p)))
cv2.imwrite(f'key.png', new_img1)
得到关键词AES以及AESKEY:a8bms0v4qer3wgd67ofjhyxku5pi1czl
由于图片中只给出了key,故优先考虑ECB模式,解码得到flag
flag为flag{1ba48c8b-4eca-46aa-8216-d164538af310}
以上是关于红帽杯2021 Misc的主要内容,如果未能解决你的问题,请参考以下文章