[CISCN 2023 初赛]puzzle 解析

news/2024/12/27 11:06:21/

打开文件包给了一堆拼图碎片,由于文件数量高达2880张,这里不考虑gaps的方式进行修正拼图

(因为跑了也只会把gaps跑冒烟)

tmp类型的拼图,因为tmp文件特性在文件头的位置会有其在原图片上的位置坐标

 

 于是,我们可以通过坐标+图片分辨率的方式(在得到最后一块拼图的坐标后,将其与它的分辨率大小相加)就能得到原图片的大小

*方便我们创建同等大小的画布

于是我们书写脚本对其进行处理(参考大佬的wpNSSCTF | 在线CTF平台)

import os
files = os.listdir('C:\\Users\\Lenovo\\Desktop\\puzzle\\tmp4\\')
size = []
for file in files:with open('C:\\Users\\Lenovo\\Desktop\\puzzle\\tmp4\\'+file,'rb') as fr:data = fr.read()x = int.from_bytes(data[6:8],'little') #读入tmp文件的自带坐标y = int.from_bytes(data[8:10],'little')#little意思为小数据类型,即储存数据时前面的数据储存在高位width = int.from_bytes(data[0x12:0x16],'little') #读入图片宽度height = 100size.append([(y,x),(height,width)]) #以(文件坐标位置)(文件像素大小)为一组数据写入size数组中
sorted_size = sorted(size,key=lambda x:x[0]) #按照第一位进行排序,即(y,x)排序
img_height = sorted_size[-1][0][0] + sorted_size[-1][1][0] #对最后一张图片的像素和坐标进行相加处理,得到最终拼图的宽和高
img_width = sorted_size[-1][0][1] + sorted_size[-1][1][1]
print(img_height,img_width)

然后我们得到原本图片大小

4000 7200

 得到原本图片之后我们就可以选择对图片进行拼接,脚本如下

from PIL import Image,ImageOps
import os
exp = Image.open('C:\\Users\\Lenovo\\Desktop\\puzzle\\tmp4\\99765296563.bmp')
image = Image.new(exp.mode,(7200, 4000)) #mode函数保留原本图片文件的色彩格式
files = os.listdir('C:\\Users\\Lenovo\\Desktop\\puzzle\\tmp4\\')
for file in files:with open('C:\\Users\\Lenovo\\Desktop\\puzzle\\tmp4\\'+file,'rb') as fr:data = fr.read()x = int.from_bytes(data[6:8],'little')#读取tmp坐标y = int.from_bytes(data[8:10],'little')height=int.from_bytes(data[0x16:0x1A],'little',signed=True) # signed:选True、Flase表示是否要区分二进制的正负数含义。即是否要对原二进制数进行原码反码 补码操作img = Image.open("C:\\Users\\Lenovo\\Desktop\\puzzle\\tmp4\\" + file)if height < 0:img=ImageOps.flip(img)print('已翻转:',file)image.paste(img,(x,y))
image.save('C:\\Users\\Lenovo\\Desktop\\flag.bmp')

 需要注意的是,部分图片给的高度参数是负数,这样会导致拼出来的图片会颠倒过来

我们对其进行反转处理后即可得到原本图片

 之后对分成3部分的flag进行分别解析

1.lsb解密

        打开stegsolve,选择lsb除alpha外的0位,得到第一部分flag

2.二进制

        猜测部分图片的高度被修改与出题人的意图有关。因为有着高度正负的区别,猜想是二进制。于是对图片输入的高度进行提取,并按照拼图的顺序进行排列

import os
from Crypto.Util.number import long_to_bytes
files = os.listdir('C:\\Users\\Lenovo\\Desktop\\puzzle\\tmp4\\')
s=[]
for file in files:with open('C:\\Users\\Lenovo\\Desktop\\puzzle\\tmp4\\'+file,'rb') as fr:data = fr.read()x = int.from_bytes(data[6:8],'little')#读取tmp坐标y = int.from_bytes(data[8:10],'little')height=int.from_bytes(data[0x16:0x1A],'little',signed=True)bindata='0' if height<0 else '1' #将高度数据转换为二进制的0,1s.append([(y,x),bindata])
s=sorted(s,key=lambda x:x[0])#存入数据组,按坐标进行排序
b_flag=''
for i in s:b_flag+=i[1]#读入二进制数据
print(long_to_bytes(int(b_flag,2)))#输出第二部分flag

 最终得到

b'          2nd_paRT_15_reVeRSe_bMp_         .--. .- -..\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'

除去第二部分flag外,我们还得到第3部分flag的摩斯密码提示

 pad一般指pad()函数,即填充函数

考虑到bmp文件特性,bmp是按⾏绘制的,每⾏数据都需要为4的倍数,当像素数据不满⾜这个条件时,会⾃动填充相应字节的0。而在这道题中出题人很明显修改了这个填充的值,我们需要把这个值按照拼图的排列方式提取出来。

import os
files = os.listdir('C:\\Users\\Lenovo\\Desktop\\puzzle\\tmp4')
my_data = []
for file in files:with open('C:\\Users\\Lenovo\\Desktop\\puzzle\\tmp4\\'+file,'rb') as fr:data = fr.read()x = int.from_bytes(data[6:8],'little')y = int.from_bytes(data[8:10],'little')width = int.from_bytes(data[0x12:0x16],'little',signed=True)padding_size = 0 if 4- 3*width%4 == 4 else 4- 3*width%4 #计算填充字节img_data_size = 3*width#计算数据字节length = len(data[54:])#⽂件头占54字节img_data = data[54:]padding_data = b''#声明是二进制字符串for i in range(img_data_size,length,padding_size+img_data_size):padding_data += img_data[i:i+padding_size]my_data.append([(y,x),padding_data])#先排横坐标,再排纵坐标
sorted_data = sorted(my_data,key=lambda x:x[0])#按拼图顺序排序
padding_msg = b''
for v in sorted_data:padding_msg += v[1]
with open('C:\\Users\\Lenovo\\Desktop\\c_flag.jpg','wb') as fw:fw.write(padding_msg)

最后输出的16进制数开头为ffd8,是一个jpg文件,于是我们直接输出为一个jpg文件即可

得到

 3rd_parT_1s_paddINGINGING}

将3部分flag进行拼接得到最终flag

flag{f1R5T_part_1s_LSB_sTeG0_2nd_paRT_15_reVeRSe_bMp_3rd_parT_
1s_paddINGINGING}

 此题结束

(感谢大佬的wpNSSCTF | 在线CTF平台让我大开眼界。同样也吃了没有见过bmp拼图这种类型题目的亏,这次算是长见识了)


http://www.ppmy.cn/news/423380.html

相关文章

Java JDK 8 32位下载

java 32位JDK8下载地址 百度网盘地址 点击跳转链接 提取码&#xff1a;895e 失效了请联系我&#xff01;

win10操作系统官网如何下载ios境像文件安装操作系统

1.打开官网 2.立即下载工具 3.正在准备进行工作 4.接收条款 5.根据需求选择安装合适的位置 6.等待创建成功 7.右键选择装载 8.双击安装setup.exe文件 8 使用微Pe安装过程中发现需要联网更新解决 winR 然后cmd 输入 OOBE\BYPASSNRO 9 或者关闭此进程 电脑不要插网线&#xff…

eplan p8详细安装步骤文库_Win10系统安装Eplan Electric P8详细步骤

导读&#xff1a;(Win10系统安装Eplan Electric P8 2.7教程)相关电脑教程分享。 eplanelectricp8是一款功能强大的电气工程设计软件&#xff0c;很多朋友可能工作和学习上会使用到它&#xff0c;今天小编要分享下Win10系统下安装Eplan Electric P8 2.7教程&#xff0c;有兴趣的…

电脑W7系统怎样安装鸿蒙系统,真正纯净版的win7系统

真正纯净版的win7系统很多的小伙伴都非常的想要下载,很想试试这个版本的win7吧,win是目前兼容性比较高的一个系统,也是很多用户选择的一个版本,喜欢的用户赶紧下载试试吧。 真正纯净版的win7系统特色 人性化的设计师资源保证所有的非系统都保存在磁盘上,不会再次丢失。 系…

驰为hi8pro 刷win10单系统

因为手贱&#xff0c;在win10里面用磁盘管理工具把Android分区删除了&#xff0c;不仅Android用不了&#xff0c;而且win10也不能系统还原。这就影响了基本的使用&#xff0c;于是决定把双系统刷成单win10系统。 先来一张刷成功的照片 准备&#xff1a; 1、Type-C转接头&#…

win10 Linux双系统教程,win10+ubuntu双系统超详细教程(亲测可用)

1、先安装windows10系统 注意:若原有的win10系统没有损坏,则能够省略这一步。html 关于Windows10系统重装,您须要准备一个8G以上容量u盘和一台能够正常上网的电脑,并按照如下步骤操做: 1 备份电脑和U盘中本身的重要数据,并格式化u盘 ubuntu 2 在电脑上打开如下连接,点击…

JDK8官网下载和安装详细说明(Windows10系统)

目录 前言一、环境说明二、JDK官网下载1.进入官网2.找到Downloads入口3.找到Java JDK4.进入JDK下载页面5.进入JDK8下载页面6.选择下载的版本 三、JDK安装1.运行exe文件2.点击下一步3.定制安装4.安装公共JRE5.安装中6.安装完成 四、环境变量配置1.点击属性2.点击高级系统设置3.点…

deepin linux 换回WIN7,deepin ghost win7系统安装方法

Deepin 是一个基于 Linux 的操作系统&#xff0c;专注于使用者对日常办公、学习、生活和娱乐的操作体验的极致&#xff0c;适合笔记本、桌面计算机和一体机。非常的适合小白用户的使用&#xff0c;但是deepin ghost win7系统安装方法是什么呢?下面就让win7之家小编为大家介绍d…