开个玩笑

遇到拼图不要慌,PS打开慢慢贴。

典型题目1 – 仓鼠的窝

以“青少年CTF平台”中仓鼠的窝题目为例:

下载附件后,得到一张原图.jpg和一个png.zip

png.zip中,包含了被分割的图片。

分析题目

解压后发现5184个项目,也就是分割出了5184个文件。

每一个图片为35×11像素,宽度35,高度11。

原图为1920*1080

那么1920*1080,计算有多少图片应该就是:

sage: width = 1920
sage: height = 1080
sage: w = 35
sage: h = 11
# 宽度应该有几张图片? width / w = 384/7 大约54
# 高度应该有几张图片? height / 11 = 1080/11 大约98

所以高度、宽度不全等,目前得出结论是:这个图片有混淆!

得到这种情况可能有两种原因:

1.出题人故意而为

2.出题人分割脚本有误

3.排序方法不精确或排序方法的根本问题

但是不管哪种情况,你用正常的拼图脚本得到的结果应该是像下面这样的:

from PIL import Image
import os

def auto_puzzle(original_path, png_dir, output_name):
    # 读取原图尺寸
    original = Image.open(original_path)
    orig_width, orig_height = original.size

    # 获取碎片文件并按时间排序
    files = [os.path.join(png_dir, f) for f in os.listdir(png_dir) if f.endswith('.png')]
    files.sort(key=lambda x: os.path.getmtime(x))
    images = [Image.open(f) for f in files]

    # 校验碎片尺寸一致性
    first_img = images[0]
    tile_width, tile_height = first_img.size
    if any(img.size != (tile_width, tile_height) for img in images):
        raise ValueError('碎片图片尺寸不统一')

    # 计算行列数(两种模式)
    cols_horizontal = orig_width // tile_width  # 横向优先的列数
    rows_vertical = orig_height // tile_height  # 纵向优先的行数

    # 自动选择最优布局(优先横向填充)
    if len(images) % cols_horizontal == 0:
        rows = len(images) // cols_horizontal
        cols = cols_horizontal
    else:
        cols = int((orig_width / tile_width) + 0.5)
        rows = len(images) // cols + 1

    # 创建画布
【CTF技战法】Misc中的拼图题目
    canvas = Image.new('RGB', (orig_width, orig_height))

    # 网格填充
    for index, img in enumerate(images):
        x = (index % cols) * tile_width
        y = (index // cols) * tile_height
        canvas.paste(img, (x, y))

    canvas.save(output_name)
    return canvas

# 执行拼图
auto_puzzle('../原图.jpg''../png''auto_puzzle.jpg')

解决题目(方法1)

因为已经可以看到图片中有明显的字符串的痕迹,挑选出包含字符串的图片,然后拼接成新的图片。

解决题目(方法2)

因为图片数量较多,截止文章编写时,仍未解出正常的图片,故不推荐。

安装前置工具

我的Kali中是已经安装过的,如果没有安装的话可以参考命令去安装一下。

但是没gaps的话就很鸡肋了

所以还需要安装一下gaps(注意一下Python版本,3.12以上可能无法正常使用)

git clone https://github.com/nemanja-m/gaps.git
cd gaps
sudo apt update
sudo apt install python3-poetry
poetry install
pip install .
附(Python3.11安装)
sudo apt update
sudo apt install -y build-essential zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev curl tk-dev
wget https://www./ftp/python/3.11.5/Python-3.11.5.tgz
tar -xzf Python-3.11.5.tgz
cd Python-3.11.5
./configure --enable-optimizations
make -j4
sudo make altinstall
python3.11 --version
python3.11 -m pip install . # 继续上面的执行

注意:如果不跳出上面这个目录,就会进入gaps目录里。

这里我们已经安装成功了。

使用montage和gaps解题
montage ./png/*.png -geometry +0+0 flag.png  
gaps run ./flag.png newflag.png --population=5184 --size=35

解密时间巨长

但是听说没办法按照这个方式拼图成功…

我先试试看,如果不行明天就不更新文章了(逃…)

典型题目2 – 西安加油

以“青少年CTF平台”中西安加油题目为例:

下载附件后,得到secret.pcap文件

分析题目

使用Wireshark导出HTTP对象列表到文件,之后按照文件大小倒序排序。

将secret.txt中的base64提取,转为文件

发现是ZIP文件,将ZIP文件保存,得到:

解决题目

因为图片数量比较少,真正使用拼图的人也比较多,也比较简单,这里着重说明使用montage和gaps解题。

montage ./chips/*.png -geometry +0+0 flag.png

将图片拼合成新的图片

gaps run ./flag.png newflag.png --population=48 --size=100

使用gaps进行识别拼图

这样就已经能得到正确的FLAG了。