PatriotCTF 2025 Misc & OSINT & Forensics -- writeup
被带飞太爽了 😋🤓
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 g
import 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 block
text = """0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000
0011000011001111101111001010000000000110000000100100011100011100000001000000000000000000011000110010000000001000110000011001000001110010100
0100100100100010001000001000000000001010000000101010100010100010000010100000000000000000100101001010000000001001001000101001000010001000100
0100100100100010001000001000100010010010011100100010100000000010000000100111100000001100100101001010000000111001000000101001110010001000100
0100100100000010001110010000100010100010100010100010111000011100000000101000000000010010100101001010000001001001110001001001001001110000010
0111000100100010001000001000010100111110100000100010100000000010000000100111000000010000100101001010000001001001001001111001001010001000100
0100000100100010001000001000010100000010100000100010100000100010111000100000101110010010100101001010111101001001001000001001001010001000100
0100000011000010001000001010001000000010100000100010100000011100000000101111000000001100011000110010000000111000110000001001110001110010100
0000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"""
# Parse lines
lines = text.strip().split("\n")
height = len(lines)
width = len(lines[0])
# scale factor
scale = 8
img = 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 image
path = "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中
评论