2021-RedHat-CTF-WP【MISC】
目录
MISC
1.签到题:EBCDIC编码
1.1 方法1:010Editor工具转换
1.2 方法2:python转换
2.colorful code:RGB隐写+Piet
2.1 前期分析
2.2 RGB转图片
2.3 Piet解码
3.PicPic:你想成为CV大师嘛
3.1 前期分析
3.2 challenge1:傅里叶反变化原理
3.3 challenge2:傅里叶反变化原理
3.4 challenge3:傅里叶反变化原理
MISC
1.签到题:EBCDIC编码
文件名已经告知采用的是EBCDIC编码。EBCSIC(基于广义二进制的十进制交换码)是一种用于表示字母和数字字符的二进制编码方案,在IBM为其更大规模的操作系统开发并推广这一技术基础
当我启动该程序时遇到了乱码问题,请检查计算机系统的编码设置是否正确。
啌亣捆咇凁攨mpm檯剤仯蝠蝰?
AI助手
所以最好还是使用010editor打开。

afei
1.1 方法1:010Editor工具转换
在软件界面中导航至[工具]菜单—>切换或设置—>选择对应的编码类型或选项(经过操作后未检测到预期标志,请确认参数设置是否正确;如有必要可使用快捷键Ctrl+Z回滚至上一步)。

afei
成功拿到flag :flag{we1c0me_t0_redhat2021}
1.2 方法2:python转换
ebcdic = open(r"C:\Users\Administrator\Desktop\EBCDIC\EBCDIC.txt", "r", encoding="cp500")
print(ebcdic.readline())
AI助手

afei
2.colorful code:RGB隐写+Piet
2.1 前期分析

拿到压缩包,解压得到data1和data2,010开的两个文件如下:

afei

afei
眨眼一看,啥玩意儿吗?先看一下文件类型吧。

afei
这个题目看起来挺有意思的嘛。这个杂项确实让人脑洞大开。在数据集data1中仅包含数值范围为0至19的数据。通过查阅相关资料得知,在数据集data2中与RGB相关的属性占主导地位。该研究采用了一种独特的转换策略:将每个字节分解为两个十六进制字符,并将其与RGB颜色通道进行一一对应。
2.2 RGB转图片
hexTranRGB_misc.py:
#!/usr/bin/python
# Env: python3
# Author: mochu7
# Write by afei_0and1
# -*- coding: utf8 -*-
from binascii import *
import argparse
def hexTranRGB(file):
with open(file, "rb") as fw:
fw = hexlify(fw.read()).decode() #格式化成16进制
n = 0
res_RGB = []
for i in range(0, len(fw), 2): #步长为2
#为什么是i+2取出,因为i+4后面还剩了两个字符,所以应该是i+2
i = fw[i:i+2]
res_RGB.append(int(i, 16))
n += 1
if n==3:
print(tuple(res_RGB)) #以元组格式输出RGB
res_RGB = []
n = 0
else:
continue
if (__name__ == '__main__'):
parser = argparse.ArgumentParser(description="Hex transtation RGB Script for 2021-Redhat-CTF")
parser.add_argument(
'-f', '--file', type=str,
help='Please input need transtation file path'
)
args = parser.parse_args()
if args.file:
hexTranRGB(args.file)
AI助手

afei
经过打印结果的分析后发现仅有前20组数据与其余部分存在差异;其余部分的RGB值完全一致;这使得我们能够联想到data1中的数字范围(0至19)正好覆盖了这里的前20组数据;因为对图片不熟悉程度较低;CTF题目练习不足;参考大神们的解题思路:我们可以将这20组RGB值按照data1中的序列依次进行赋值;最终通过PIL.putpixel()方法生成完整的图片;其中隐藏的信息即为flag所在位置
这里生成flag图片的条件:
(1)需要知道总像素。直接计算data1中0-19的数字总数即可;
(2)图片的宽和高。拿到总像素因式分解得到。
通过调用data1进行总像素统计;特别提示:在调用前,请确保data1末尾无多余空格;建议操作完成后及时清理数据以避免潜在的问题。
count_data1.py:
#!/usr/bin/python
# Env: python3
# Author: mochu7
# Write by afei_0and1
# -*- coding: utf8 -*-
def count_data1():
with open(r"C:\Users\Administrator\Desktop\colorful_code\data1", "r") as fr:
#source_data = str(fr.read()).split("'")[1]
#data = "".join(source_data.split(" "))
data = fr.read().split(" ")
#print(data)
return data
#print(count_data1()
print(len(count_data1()))
'''
Output result:
7067
'''
AI助手
计算得出总数量为:7,067;访问百度搜索平台获取在线因式分解工具http://tools.jb51.net/jisuanqi/factor_calc;通过因数分解获得图像尺寸参数分别为宽度与高度:37×191;基于获取的宽度与高度参数,即可进行图像重建与合成。
#!/usr/bin/python
# Env: python3
# Author: mochu7
# Write by afei_0and1
# -*- coding: utf8 -*-
from PIL import Image
from binascii import *
#计算data1的0-19个数,即:总像素
def count_data1():
with open(r"C:\Users\Administrator\Desktop\colorful_code\data1", "r") as fr:
data = fr.read().split(" ")
return data
#获取data2前20个RBG像素
def getRGB():
with open(r"C:\Users\Administrator\Desktop\colorful_code\data2", "rb") as fw:
fw = hexlify(fw.read()).decode() #格式化成16进制
n = 0
res_RGB = []
resRGB_dic = {}
count = 0
for i in range(0, len(fw), 2): #步长为2
#为什么是i+2取出,因为i+4后面还剩了两个字符,所以应该是i+2
i = fw[i:i+2]
res_RGB.append(int(i, 16))
n += 1
if n==3:
resRGB_dic[count] = tuple(res_RGB) #以元组格式输出RGB
res_RGB = []
n = 0
count += 1
elif count == 20:
break
return resRGB_dic
#根据分解的宽和高合成图片,宽:37,高:191
def getimg():
img = Image.new('RGB', (37, 191))
img_pixel = count_data1()
img_rgb = getRGB()
res_pixel = []
for pix in img_pixel:
res_pixel.append(img_rgb[int(pix)])
idx = 0
for l in range(37):
for h in range(191):
img.putpixel([l, h], res_pixel[idx])
idx += 1
return img.save("flag.png")
if(__name__ == '__main__'):
getimg()
AI助手

afei
执行该脚本生成上述图像至此,那些不懂的人都倾向于沿着隐写的技术方向进行深入探讨.实际上,这张图片呈现出类似于电波的一种编程语言——Piet.Piet 是一种极具复杂性的编程语言,在其中巧妙地运用色彩来编码信息
Piet官网 :http://progopedia.com/language/piet/
2.3 Piet解码
参加CTF竞赛需要积极进行针对性训练。通过持续练习和积累经验,逐渐形成解决复杂问题的能力。无需复杂的配置或额外操作,在线提交后就能快速获取目标信息。
NPIET项目:其执行过程需借助该在线工具进行验证

afei
成功拿到flag:flag{88842f20-fb8c-45c9-ae8f-36135b6a0f11}
3.PicPic:你想成为CV大师嘛
3.1 前期分析
这个题目中的附件体积较大,在处理时需要特别注意其较大的文件占用空间。建议在完成当前步骤后进行解压操作,在此过程中你将会获得两个关键项( challenge ),其中一个是加密包装档需要特别处理。推测可以通过第一个挑战获取解压密码进而解开第二个挑战文件,并从中提取 flag 。 flag 可能是在第二个挑战文件中被提取出来的。

afei
在Challenge1中包含了一些内容。发现了两组视频无法打开的情况。r文件出现乱码问题。使用hexdump和strings工具未找到相关线索。通过hexdump和strings分析未获取到有用信息。进一步分析后确认其中包含了加密文本内容。
└─# strings r
?E{KA
(?-0
65?K
:~?e
=A>W
?9wPA
ML?g
L}?=
N4?D
N??H
?3xSA
PY?G
/O?Y
/I??
0l?O
09?5a
2V?4
cR?#q
d,>a
d&?3
g3?
,@?A
AI助手
要想完全看懂create.py还需要一些努力才行。对于用Python处理视频这块儿我之前完全没有接触过里面运用了numpy库.create.py代码解析如下:以下是对create.py代码的具体解析内容。
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
'''
FFT(快速傅立叶变换)是指通过在计算项中使用对称性可以有效地计算离散傅立叶变换(DFT)的方法。当n为2的幂时,对称性最高,因此,对于这些大小,变换效率最高。
'''
def fft(img):
fft = np.fft.fft2(img) #二维FFT
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')
AI助手
numpy fft 作为参考资料:https//www.numpy.orgdocstablereferencegenerated numpy fft fft html
傅里叶反变化原理:

参考文章:https://zhuanlan.zhihu.com/p/265188110
https://zhuanlan.zhihu.com/p/358227350
该代码的主要功能是实现对MP4视频文件的逐帧分离,并生成幅度图和相位图。随后将这些图像重新组合以形成mkv格式视频文件。利用ffmpeg工具能够输出对应的图像文件。
3.2 challenge1:傅里叶反变化原理
首先安装ffmpeg:
使用sudo指令安装ffmpeg工具
运行Python脚本create.py时,请注意该操作可能导致错误
建议您在进行此操作之前先创建必要的文件夹
使用ffmpeg工具将mkv格式视频1.mkv转换成png格式的帧图像
同样地,在处理mkv格式视频2.mkv时,请将其转换成相应的png格式帧图像
最终会在m和p文件夹中生成各200张图片。
MP4和mkv的区别 :https://www.zhihu.com/question/29188635?sort=created
ffmpeg工具用法参考 :https://www.jianshu.com/p/ddafe46827b7
通过分析图像的源代码结构进行解密研究。参考专家文章内容可知,在打包后的数据文件中通常存储着最大幅值与最小幅值信息。对于相位信息而言,则其最大幅度为π而最小幅度则为-π。基于傅里叶变换理论,在复数域中表示相位信息时,余弦函数对应实部而正弦函数对应虚部。具体解密过程解析如下:
mkvTrans_images_for_challenge1.py:
#!/usr/bin/python
# Env: python3
# Author: FzWjScJ
# Write by afei_0and1
# -*- coding: utf8 -*-
#Resources:http://www.fzwjscj.xyz/index.php/archives/44/#picpic
import os, struct
import numpy as np
from PIL import Image
#mapping()函数生成新的图片
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
fuzhi = open(r"C:\Users\Administrator\Desktop\2021RedHat-CTF\MISC\PicPic\challenge 1\r", "rb")
#获取文件夹的图片名
files = os.listdir(r"C:\Users\Administrator\Desktop\2021RedHat-CTF\MISC\PicPic\challenge 1\m")
for file in files:
'''
Image.convert()方法有9种模式: 1,L,P,RGB,RGBA,CMYK,YCbCr,I,F
Image.convert("L")为灰度图像,每个像素用8个bit表示,0表示黑,255表示白,其他数字表示不同的灰度。
转换公式:L = R * 299/1000 + G * 587/1000+ B * 114/1000。
'''
#获取灰度图像像素值,因为通过生成的图片可以看出都是灰度图像
m = np.array(Image.open(r"C:\Users\Administrator\Desktop\2021RedHat-CTF\MISC\PicPic\challenge 1\m\ " + file).convert("L"))
p = np.array(Image.open(r"C:\Users\Administrator\Desktop\2021RedHat-CTF\MISC\PicPic\challenge 1\p\ " + file).convert("L"))
r = struct.unpack("!ff", fuzhi.read(8)) #解包,每8各bits读取幅值
min_fuzhi = float(r[0])
max_fuzhi = float(r[1])
#astype()强转为64位浮点数
m = m.astype(np.float64)
p = p.astype(np.float64)
m = mapping(m, min_fuzhi, max_fuzhi, np.float64)
p = mapping(p, -np.pi, np.pi, np.float64) #python的Π的表示有:math.pi == np.pi == scipy.pi
m = np.exp(m) #返回e的幂次方,即:e^m
fft = (m*np.cos(p)) + (m * np.sin(p) * 1j) #该公式具体还得参考:傅里叶反变化原理
fft = np.fft.ifftshift(fft)
img = mapping(np.fft.ifft2(fft))
img = Image.fromarray(img).save(r"C:\Users\Administrator\Desktop\2021RedHat-CTF\MISC\PicPic\challenge 1\frame\ " + file)
AI助手
运行脚本时,请注意尽管mapping函数返回的结果new_data出现了错误情况(即映射结果未能正确解析),但这并不会影响图像生成过程。经过处理后总共生成了200个图像样本;其中密码被巧妙地隐藏在图像中,并以傅里叶反变换原理为基础进行编码处理。特别值得注意的是,在最后几个图像中通过应用傅里叶反变换技术能够清晰提取出解压密码信息,并且具体的解压指令为zs6hmdlq5ohav5l1。

3.3 challenge2:傅里叶反变化原理
通过获取nextChallenge的破解密码来解压文件。在成功解压后发现文件夹内包含了另一个挑战(challenge2)以及最终挑战(final challenge)。无需推测,在最终挑战中必定隐藏着flag。
打开名为challenge2的项目发现了一份TXT格式的提示信息文件以及两张图片(类似于二维码)。这些文件内部似乎包含了一个数学公式编码段。上网搜索了一下相关内容后发现了一款适合编辑此类代码的在线工具:http://www.ewebeditor.net/math/

afei
转换后得到公式 :{Acos(mx+n)Bcos(px+q)⟶{Acos(px+q)Bcos(mx+n)
研习高人的工作流程文档中有一个转换式。其含义在于实现图像与相位间的转换。依照高人思路构建生成二维码的脚本
getenQR_for_challenge2.py:
#!/usr/bin/python
# Env: python3
# Author: FzWjScJ
# Write by afei_0and1
# -*- coding: utf8 -*-
#Resources:http://www.fzwjscj.xyz/index.php/archives/44/#picpic
import numpy as np
from PIL import Image
#mapping()函数生成新的图片
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.abs(fft) #numpy.abs()方法获取绝对值
p = np.angle(fft) #numpy.angle()计算复数的辐角主值
m_res = m.astype(np.float64)
p_res = p.astype(np.float64)
return m_res, p_res
def geterQR():
#获取灰度图像像素值
pic1 = np.array(Image.open(r"C:\Users\Administrator\Desktop\2021RedHat-CTF\MISC\PicPic\next_challenge\challenge 2\mix1.png").convert("L"))
pic2 = np.array(Image.open(r"C:\Users\Administrator\Desktop\2021RedHat-CTF\MISC\PicPic\next_challenge\challenge 2\mix2.png").convert("L"))
m1, p1 = fft(pic1)
m2, p2 = fft(pic2)
fft1 = m1 * np.cos(p2) + m1 * np.sin(p2) * 1j #这里的1j是complex复数类型
fft2 = m2 * np.cos(p1) + m2 * np.sin(p1) * 1j
np1 = mapping(np.abs(np.fft.ifft2(fft1)))
np2 = mapping(np.abs(np.fft.ifft2(fft2)))
get_QR1 = Image.fromarray(np1).save(r"C:\Users\Administrator\Desktop\2021RedHat-CTF\MISC\PicPic\next_challenge\challenge 2\res1.png")
get_QR2 = Image.fromarray(np2).save(r"C:\Users\Administrator\Desktop\2021RedHat-CTF\MISC\PicPic\next_challenge\challenge 2\res2.png")
return get_QR1, get_QR2
geterQR()
AI助手
执行脚本后生成res1.png为二维码图档,res2.png暂不理会其用途,使用QR码进行扫码获取到的一串16进制字符串

afei
0f88b8529ab6c0dd2b5ceefaa1c5151aa207da114831b371ddcafc74cf8701c1d3318468d50e4b1725179d1bc04b251f
已经到这了,接着看最后一个挑战。
3.4 challenge3:傅里叶反变化原理
位于/final challenge/目录中的仅有一张phase.png文件为灰度图像。其音译结果等同于阶段与相位两个概念。从技术见解的角度分析,则该图像应被视为纯粹的相位图。依据傅里叶变换的基本原理可知:幅值反映的是图像亮度或对比度的信息;而相位图则能够完整地保存图像的基本轮廓特征。因此,在处理过程中只需关注轮廓特征即可;幅值的变化则无需特别考虑。据此可编写相关脚本完成处理流程
getenImg_for_finalChallenge.py:
#!/usr/bin/python
# Env: python3
# Author: FzWjScJ
# Write by afei_0and1
# -*- coding: utf8 -*-
#Resources:http://www.fzwjscj.xyz/index.php/archives/44/#picpic
import numpy as np
from PIL import Image
#mapping()函数生成新的图片
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 getImg():
pic = np.array(Image.open(r"C:\Users\Administrator\Desktop\2021RedHat-CTF\MISC\PicPic\next_challenge\final challenge\phase.png").convert("L"))
p = mapping(pic, -np.pi, np.pi, np.float64)
fft = np.exp(p * 1j)
p = np.fft.fftshift(fft)
img = mapping(np.abs(np.fft.ifft2(p)))
img = Image.fromarray(img).save(r"C:\Users\Administrator\Desktop\2021RedHat-CTF\MISC\PicPic\next_challenge\final challenge\flag.png")
return img
getImg()
AI助手
运行脚本得到的是ase的密钥:a8bms0v4qer3wgd67ofjhyxku5pi1czl

afei
现在已经很清楚了。这一串十六进制字符串经过AES算法进行加密处理后得到了ASE密文与相应的密钥。这些密钥与密文都已经获取并具备解密能力。通过CyberChef工具首先将十六进制数据解析为ASCII字符,并随后将其进行Base64编码处理以完成整个解码过程。

afei
D4i4Upq2wN0rXO76ocUVGqIH2hFIMbNx3cr8dM+HAcHTMYRo1Q5LFyUXnRvASyUf
最后在使用在线ASE解密输入密文和密钥,解密拿到flag。

afei
成功拿到flag :flag{1ba48c8b-4eca-46aa-8216-d164538af310}
参考文章 :
