PatriotCTF 2025 Misc & OSINT & Forensics -- writeup
/ 7 min read
Table of Contents
被带飞太爽了 😋🤓
Misc
Reverse Metadata Part 1
exiftool CVE
https://github.com/UNICORDev/exploit-CVE-2021-22204
反弹shell回来就行 flag在 /flags
Reverse Metadata Part 2
同上 flag在 /proc 删除的文件 grep找就可以
Half-Eaten Metapixels
打开mc文件 是Golly https://golly.sourceforge.io/
Golly 是一款开源的跨平台应用程序,用于探索康威生命游戏和许多其他类型的元胞自动机。

经过一段时间的迭代后 我们得到

到这里陷入了僵局 因为可以发现 flag是不完全的 而且这个迭代的速度是非常缓慢
我到这里大概跑了一个小时 于是开始尝试观察
整个系统由n个小方块组成 我们暂称每个小方块为区块
在初始的Generation=1时,

观察到每个区块的左下角 有类似电路板的结构
而有活细胞区块的这部分与无活细胞区块的这部分结构不同
每个应该有东西的区块 左下的ON OFF 区域的 B1-8是ON
没有东西的区块是OFF 并且这个规律与目前迭代出来的都对应上了
我们以其中一个变化的位置作为标志位采样 编写脚本提取全部信息
Golly内置python脚本环境 https://golly.sourceforge.io/Help/python.html
编写脚本来提取标志位
import golly as gimport os
def export_01_grid(): x_start = 138 x_end = 282762 x_step = 2048
y_start = 1496 y_end = 21976 y_step = 2048
desktop = os.path.join(os.path.expanduser("~"), "Desktop") filepath = os.path.join(desktop, "output.txt")
with open(filepath, "w") as f: y = y_start while y <= y_end: line_bits = []
x = x_start while x <= x_end: state = g.getcell(x, y) line_bits.append("1" if state == 1 else "0") x += x_step
f.write("".join(line_bits) + "\n")
y += y_step
g.show("Done.")
export_01_grid()然后将得到的二进制字符串转换为图像
from PIL import Image
# Provided text blocktext = """00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000001100001100111110111100101000000000011000000010010001110001110000000100000000000000000001100011001000000000100011000001100100000111001010001001001001000100010000010000000000010100000001010101000101000100000101000000000000000001001010010100000000010010010001010010000100010001000100100100100010001000001000100010010010011100100010100000000010000000100111100000001100100101001010000000111001000000101001110010001000100010010010000001000111001000010001010001010001010001011100001110000000010100000000001001010010100101000000100100111000100100100100111000001001110001001000100010000010000101001111101000001000101000000000100000001001110000000100001001010010100000010010010010011110010010100010001000100000100100010001000001000010100000010100000100010100000100010111000100000101110010010100101001010111101001001001000001001001010001000100010000001100001000100000101000100000001010000010001010000001110000000010111100000000110001100011001000000011100011000000100111000111001010000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"""
# Parse lineslines = text.strip().split("\n")height = len(lines)width = len(lines[0])
# scale factorscale = 8img = Image.new("RGB", (width * scale, height * scale), "white")pixels = img.load()
for y, line in enumerate(lines): for x, c in enumerate(line): color = 0 if c == '1' else 255 # fill 4x4 block for dy in range(scale): for dx in range(scale): pixels[x*scale+dx, y*scale+dy] = (color, color, color)
# Save imagepath = "C:\\Users\\Mnzn\\Desktop\\output_image.png"img.save(path)我们就得到了flag图 O(∩_∩)O
Mysterious XOR
观察报文,发现存在大量字符 g
结合题目描述 One byte is all you ever need. 和题目的 XOR
提取出原始字节流 与字符 ‘g’ 进行异或 得到ELF文件

接下来是对ELF文件的逆向分析

写exp
import socket
from datetime import datetime, timezone
def cur_dt_bytes():
""" cur_dt: "YYYYMMDDTHHMMZ" (UTC) """ now_utc = datetime.now(timezone.utc) s = now_utc.strftime("%Y%m%dT%H%MZ") return s.encode()
def build_v8():
""" v8 = "/tmp/" + cur_dt(...) """
base = b"/tmp/" dt = cur_dt_bytes() v8 = base + dt return v8
def build_v11():
""" xsp(v8, "1337", v11) - v11[0..18] = v8[i] XOR key[i] - v11[19] = '\n' """ v8 = build_v8() key = b"1337" + b" " * (19 - 4) # "1337" + 15 个空格
out = bytearray(20) for i in range(19): out[i] = v8[i] ^ key[i] out[19] = 0x0A # '\n' return bytes(out)
payload = build_v11()Forensics
Word Sea Adventures
解压docx 得到三张图片

steghide提取出三段信息
Mr Crabs heard that his cashier may be hiding some money and maybe a flag somewhere.
Spongebob is so chill! Why would he be hiding any flags?
I guess you found handsome squidward… even his looks can’t hide the flag.
pctf{w0rD_f1le5_ar3_als0_z1p
We Go Gym
此题为TTL
统计出所有交互ip 次数最多的ip的TTL经过ascii解码后为flag
from scapy.all import rdpcap, IP
from collections import Counter, defaultdict
pcap_file = "wegogym.pcap"
packets = rdpcap(pcap_file)
ttl_per_src = defaultdict(Counter)
src_counter = Counter()
for pkt in packets:
if IP in pkt:
src = pkt[IP].src
ttl = pkt[IP].ttl
ttl_per_src[src][ttl] += 1
src_counter[src] += 1
# 自动选择出现最多包的源 IP
target_src, _ = src_counter.most_common(1)[0]
print("Selected source IP:", target_src)
# 选择该源IP中出现次数最多的 TTL 作为 base_ttl
ttl_counter = ttl_per_src[target_src]
base_ttl, _ = ttl_counter.most_common(1)[0]
print("Base TTL:", base_ttl)
# 提取异常 TTL
raw_ttls = [pkt[IP].ttl for pkt in packets
if IP in pkt and pkt[IP].src == target_src and pkt[IP].ttl != base_ttl]
# 去重
clean_ttls = []
for t in raw_ttls:
if not clean_ttls or clean_ttls[-1] != t:
clean_ttls.append(t)
# 转 ASCII
flag = ''.join(chr(t) for t in clean_ttls)
print("Decoded:", flag)Burger King
给了一个svg文件和zip

看到算法是 ZipCrypto Store就可以锁定明文攻击了
.svg内容为 <svg xmlns="http://www.w3.org/2000/svg"
是svg文件对应的类似魔数的声明 就 <!DOCTYPE HTML> 一样
bkcrack撞一下就出了


在Hole.svg中

OSINT
Where’s Legally
整个系列都是常规的图寻 从谷歌地球里面翻GMU校园就都能找到了 很好找
Waldo’s Nignt Out
给了三套图 分别对应三个地点
也算是常规图寻 主要是看题目说的 Virginia 全都在弗吉尼亚
附件不在了只能陈述回忆了
location 1 是废弃的Skyzone,可以找到相关废弃地点探险的帖子
location 2 识图到的
location 3 有一张图片有两个电话号码 能通过其他图片推断出是酒店
带着下面的电话号码和hotel就能搜到了
Kittiez!!!
题目给了一个 hash
拿到hint 和 malware有关
上x搜kitty malware 能搜到一个组织

https://vx-underground.org/
在他的主页 有一个网盘 archive 里有很多猫猫图片 下载下来遍历 md5 找到对应图片就可以
图片在压缩包3中