第七届浙江省大学生网络与信息安全竞赛决赛 Misc方向全解
1587580082517977 发表于 浙江 CTF 155浏览 · 2024-11-28 06:51

第七届浙江省大学生网络与信息安全竞赛决赛 Misc方向全解

FinalSign

给了一个txt,全选可以很明显看到存在空白字符

考虑SNOW隐写(snow特征,有大量的2009

SNOW.EXE -C FinalSign.txt

得到xorkey:helloworld,那么很明显2c243f2f3b3114345d0a0909333f06100143023b2c55020912就是密文

法一:

利用pwntools的xor函数

from pwn import xor
from Crypto.Util.number import *
key = b'helloworld'
c=0x2c243f2f3b3114345d0a0909333f06100143023b2c55020912
print(xor(long_to_bytes(c),key))

法二:

用CyberChef也可以

法三:

a=bytes.fromhex('2c243f2f3b3114345d0a0909333f06100143023b2c55020912')
key=b'helloworld'
e=[]
for i in range(0,len(a)):
    e.append(a[i]^key[i%len(key)])
print(bytes(e))

#b'DASCTF{F1nal_Sign1n_D0ne}'

非黑即白

很明显是逆序的GIF

with open('非黑即白','rb') as f:
   with open('heibai.gif','wb') as g:
      g.write(f.read()[::-1])

GIF常见考点

  1. 拆分图片
  2. GIF时间间隔隐写

这题刚好都考察了

identify -format "%s %T \n" heibai.gif | head -n 20

可以看到前15张图的时间间隔与后面的完全不同,转字符

a=[118,106,69,74,48,98,83,117,77,79,86,65,90,103,101]
print(bytes(a))

#b'vjEJ0bSuMOVAZge'

即为压缩包密码

法一:

拆分工具有很多,都可以用

将黑色的图转为0,其他的转为1,得到一个加密的zip

from PIL import Image

flag = ''

for i in range(0, 1536):
    img = Image.open(str(i)+'.png')
    pixel = img.getpixel((0, 0))
    # 计算亮度
    brightness = 0.299 * pixel[0] + 0.587 * pixel[1] + 0.114 * pixel[2]
    # 根据亮度与阈值比较,使用公式 0.299 * R + 0.587 * G + 0.114 * B 计算亮度,这个公式是基于人眼对不同颜色的敏感度
    if brightness >= 128:
        flag += '1'
    else:
        flag += '0'
print(flag)

2进制转16进制,504b0304是压缩包的特征

存为文件

利用刚才的密码解压得到flag

DASCTF{H3r3_1s_C0L0rful_W0rld}

法二:

逐帧处理,不用拆分gif

from PIL import Image
a=Image.open("1.gif")
n=0
data=""
e=[]
while True:
    try:
        a.seek(n)   #逐帧处理
        d=a.copy().convert('1').getdata()   #转换为黑白图像(模式 '1'),然后获取其像素数据。
        if (d[0]==0):
            data+='0'
        else:
            data+='1'
    except:
        break;
    if (len(data)==8):
        e.append(int(data,2))
        data=''
    n+=1

f=open("data.zip",'wb')
f.write(bytes(e))
f.close()

注:黑白图片并不是纯的rgb(0,0,0)和rgb(255,255,255),存在(1,1,1)等情况,所以要设置阈值,不然会丢失精度影响输出结果

天命人

按照黑猴的章节名排序

火照黑云
风起黄昏
夜生白露
曲度紫鸳
日落红尘
未竟

没玩过没关系,观察字节即可

发现按照顺序取一个字节是50 4b 03 04 00 0a

f1 = open('火照黑云', 'rb').read()
f2 = open('风起黄昏', 'rb').read()
f3 = open('夜生白露', 'rb').read()
f4 = open('曲度紫鸳', 'rb').read()
f5 = open('日落红尘', 'rb').read()
f6 = open('未竟', 'rb').read()

with open('output.zip', 'wb') as fout:
    min_length = min(len(f1), len(f2), len(f3), len(f4), len(f5), len(f6))

    # 按字节逐个写入每个文件的数据
    for i in range(min_length):
        # 逐字节读取每个文件并转换为16进制
        hex_bytes = bytes([f1[i], f2[i], f3[i], f4[i], f5[i], f6[i]])
        # 将这些字节写入输出文件
        fout.write(hex_bytes)

拼接得到zip

4bytes的crc32碰撞,用曾哥的工具就行

python CRC32-Tools.py -4 根器.zip

+-------------对输出的CRC值进行碰撞-----------------+
[Success] 0x76899d01: C0M3
[Success] 0x8e036aa6: _4ND
[Success] 0x881d716a: _Get
[Success] 0x7f3d8e75: _S1X
[Success] 0x248d3c69: _R00
[Success] 0xcb27d2bd: TS!!
+-----------------CRC碰撞结束!!!-----------------+
读取成功,导出CRC列表为:[0x76899d01, 0x8e036aa6, 0x881d716a, 0x7f3d8e75, 0x248d3c69, 0xcb27d2bd]
CRC碰撞成功,结果为: C0M3_4ND_Get_S1X_R00TS!!

利用密码解开未竟.zip

提取金箍棒.png上的像素点,这里直接用B神的脚本(不能出现中文路径或文件名,在windows下运行)

python3 Get_Pixels.py -f 1.png -p 5x5+1915x1075 -n 10x10

在ps中按F8即可查看坐标

import os
import re
import cv2
import argparse
import itertools
import numpy as np

parser = argparse.ArgumentParser()
parser.add_argument('-f', type=str, default=None, required=True,
                    help='输入文件名称')
parser.add_argument('-p', type=str, default=None, required=True,
                    help='输入左上顶点和右下顶点坐标 (如:-p 220x344+3520x2150)')
parser.add_argument('-n', type=str, default=None, required=True,
                    help='输入宽度间隔和高度间隔 (如:-n 44x86)')
parser.add_argument('-size', type=str, default='1x1', required=False,
                    help='输入截取图像的大小 (如:-size 7x7)')
parser.add_argument('-resize', type=int, default=1, required=False,
                    help='输入截取图像放大倍数 (如:-resize 1)')
args  = parser.parse_args()

if __name__ == '__main__':
    if re.search(r"^\d{1,}x\d{1,}\+\d{1,}x\d{1,}$", args.p) and re.search(r"^\d{1,}x\d{1,}$", args.n) and re.search(r"^\d{1,}x\d{1,}$", args.size):
        x1, y1 = map(lambda x: int(x), args.p.split("+")[0].split("x"))
        x2, y2 = map(lambda x: int(x), args.p.split("+")[1].split("x"))
        width, height = map(lambda x: int(x), args.n.split("x"))
        width_size, height_size = map(lambda x: int(x), args.size.split("x"))

        img_path = os.path.abspath(args.f)
        file_name = img_path.split("\\")[-1]

        img = cv2.imread(img_path, cv2.IMREAD_COLOR)
        row, col = img.shape[:2]

        r, c = len(range(y1, y2 + 1, height)), len(range(x1, x2 + 1, width))
        new_img = np.zeros(shape=(r * height_size * args.resize, c * width_size * args.resize, 3))
        for y, x in itertools.product(range(r), range(c)):
            for y_size in range(height_size):
                for x_size in range(width_size):
                    # new_img[y * height_size + y_size, x * width_size + x_size] = img[y1 + y * height + y_size, x1 + x * width + x_size]
                    pt1 = ((x * width_size + x_size) * args.resize, (y * height_size + y_size) * args.resize)
                    pt2 = ((x * width_size + x_size) * args.resize + args.resize, (y * height_size + y_size) * args.resize + args.resize)
                    color = img[y1 + y * height + y_size, x1 + x * width + x_size].tolist()
                    cv2.rectangle(new_img, pt1=pt1, pt2=pt2, color=color, thickness=-1)


        cv2.imwrite(f"_{file_name}", new_img)
        print("已保存到运行目录中...")
    else:
        print("参数-p或参数-n或参数-size, 输入错误!")

或者

from PIL import Image

a = Image.open("金箍棒.png")
x, y = 5, 5
x_, y_ = 0, 0
w, h = a.size
b = Image.new(a.mode, (w // 10, h // 10))

for x in range(5, w, 10):
    for y in range(5, h, 10):
        print(x, y, x_, y_)
        b.putpixel((x_, y_), a.getpixel((x, y)))
        y_ += 1
    x_ += 1
    y_ = 0
b.save('1.png')

都能得到密码:jinggubang

也有非预期解法,其实缩放一下能看到有字母,翻翻通道多对比一下是能看出来的

还有一个紧箍咒,一眼加密磁盘

金箍棒.png是密钥文件,正常挂载后得到flag

0 条评论
某人
表情
可输入 255