3

NKCTF 2024 1z_F0r3ns1c5 Writeup

 2 months ago
source link: https://5ime.cn/nkctf-2024.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
NKCTF 2024 1z_F0r3ns1c5 Writeup

NKCTF 2024 1z_F0r3ns1c5 Writeup

整体出题思路是前两个为常规取证点,最后一个稍微套了一下,上上强度(赛方要求,不过后期上了 hint)。原本打算该题弄成三个 flag 来着,后来考虑到一血有定制礼品不好计算只好作罢,最后就变成一个 flag

另外今年貌似参赛选手不太热衷取证,取证题型三道题均攻克率不高

HackMyCQL - 2解
1z_F0r3ns1c5 - 2解
cain_is_hacker - 3 解

1z_F0r3ns1c5

本鼠鼠正在Coding,突然一声OPEN THE DOOR!本鼠鼠直接鼠躯一颤就双手抱头蹲下了,果然本鼠鼠只适合生活在阴暗的下水道
被黑猫警长抓走的时候本鼠鼠还想辩解一下,但是他们拿出你的照片的时候,本鼠鼠认罪了
昨晚和其他鼠鼠聊天的时候其他鼠鼠问本鼠鼠:“你到底喜欢她什么啊?”
“喜欢一个人不需要理由”
本鼠鼠很快敲完了键盘,刚要按下回车的时候突然愣住了。
真的不需要理由吗?
请找到鼠鼠的答案吧。

下载附件后,总共会得到三个东西:内存镜像、描述文件和压缩包 (加密容器、马赛克图片)

本鼠鼠的flag总共分为三段捏,flag为nkctf{uuid}形式,另外鼠鼠最喜欢等宽字体了,快快去找吧。

flag01

.\volatility.exe -f .\1.raw --profile=Win7SP1x64 envars | Select-String 'n0wayback'
image-20240324154714864

可以发现一个键名为 n0wayback 的环境变量

n0wayback	HPahXR4NvAnZXB16tNK6hAaNVNU++

直接 XXencode随波逐流 一键解码即可

HPahXR4NvAnZXB16tNK6hAaNVNU
// nkctf{39c429eb-2faf

flag02

通过查询进程(pslist)或获取屏幕截图(screenshot,但是比较抽象)可以看到当前正在运行 mspaintcmdcode

.\volatility.exe -f .\1.raw --profile=Win7SP1x64 pslist

0xfffffa8001a022a0 mspaint.exe 2052 1028 6 120 1 0 2024-03-04 05:50:22 UTC+0000

0xfffffa8003c68a80 cmd.exe 4188 1028 3 111 1 0 2024-03-04 05:50:26 UTC+0000

0xfffffa800418c060 Code.exe 888 1028 31 696 1 0 2024-03-04 05:52:52 UTC+0000
image-20240324154726984

既然存在 mspaint 进程,我们直接通过 memdump 导出后,使用 Gimp 进行还原即可

.\volatility.exe -f .\1.raw --profile=Win7SP1x64 memdump -p 2052 -D ./

宽高可以尝试使用常见的显示屏分辨率,诸如 1920*10241024*768 之类的,这里没有标准的值,大差不差即可。

随后就是不断地进行偏移量的调整即可

-49a0-bd24-
image-20240324154449926

flag03

.\volatility.exe -f .\1.raw --profile=Win7SP1x64 consoles
image-20240324154739326

通过 consoles 发现通过 git clone 下载了一份源码

git clone https://github.com/5ime/Secret_Generator.git

我们直接访问该地址,首先写明需要 Docker 启动,同时让我们找到源码代码在哪

Compilable with Dockerfile or Python 3.7.2 only.

Hey, hold on a second... Where's my source code?

我们在 Commits 中看到了源代码,直接手动 git clone 后,通过 git reset 即可得到源代码

image-20240324154749015

根据 README 中要求,我们通过 Docker 对其进行部署

image-20240324154953798

访问 8080 端口,得到一个 Secret Generator,要求我们输入 加密文字上传字体

image-20240324143415899

结合最初 描述文件 中提到 鼠鼠最喜欢等宽字体了,以及题目描述开头提到 本鼠鼠正在Coding,联想到进程中的 Vscode

直接百度搜索其配置文件默认路径即可得到 Vscode 中所使用的等宽字体

// C:\Users\moe\AppData\Roaming\Code\User\Settings.json
{
"editor.fontFamily": "'Fira Code', Consolas, 'Comrier New', monospace",
"window.zoomLevel": 1,
"security.workspace.trust.untrustedFiles": "open"
}

我们直接下载 Fira Code 即可,注意下载后会存在多个粗细的字体,默认情况下直接使用 Regular 即可

image-20240315122909273

剩下的解题方法基本和 CISCN 2023 国粹 一题类似,唯一的区别就是我们需要手动生成一张表(这也是前面需要找到字体的原因)

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
image-20240324145041345

我们发现通过指定字母表进行生成图片时,后端代码对我们进行了字符串拼接,多出来了 pass[空格] 这五个字符

secret = 'pass ' + secret

for i in range(5, len(secret)-1):
mosaic_img(canvas, W*i, 0, W*i+W, H//2)
mosaic_img(canvas, W*i, H//2, W*i+W, H)

这里提供两种方法,字母表前面加个 AAAAA 字符,以及在末尾多加一个 9,原因在于前五位和最后一位不加密,且前五位为固定的 pass[空格],当我们添加 AAAAA 时在切割的时候,前五个字符会直接被覆盖(文件命名时不允许存在同名文件)

另外一种方法,直接稍微改一下代码逻辑即可

# 可改为如下形式
# 注释掉 secret 变量的字符串拼接,以及 range 范围从 0 开始
# secret = 'pass ' + secret

for i in range(len(secret)):
mosaic_img(canvas, W*i, 0, W*i+W, H//2)
mosaic_img(canvas, W*i, H//2, W*i+W, H)
image-20240324143801054

下面,我们直接通过 Python 的 PIL 库对每个字符进行裁剪,所以需要知道每个字的宽高,代码中也写明了宽高

另外,你也可以通过 图片宽度 / 字符数量 计算得到每个字符所占宽度

H = 60
W = 30

下面直接人工写代码或 PUA AI 帮你写代码即可,话术如下

我有一张 xxx.png 图片,宽高为 1086*60 ,请通过 Python 的 PIL 库将它裁剪为 30*60 的图片,切割出来的图片保存到 dict 文件夹中,另外切割出的图片命名规则根据如下命名表

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789

最后,如果文件名为大写字母则 文件名-大写.png

这里我加了一个判断,如果是大写字母则 文件名-大写.png,原因在于 WindowsA.pnga.png 不能共存,Linux 无此烦恼。

下面的代码来源于 ChatGPT 3.5 (当然,自己写也行),分别对我们自行生成 dict.png 和附件提供的 pass.png 进行切割

from PIL import Image
import os

# 打开图片
img = Image.open("dict.png")
# img = Image.open("pass.png")

# 获取图片尺寸
width, height = img.size

# 定义切割尺寸
tile_width = 30
tile_height = 60

# 确保切割后的图片尺寸可以被整除
assert width % tile_width == 0 and height % tile_height == 0

# 创建 dict 文件夹
if not os.path.exists("dict"):
os.makedirs("dict")
# if not os.path.exists("pass"):
# os.makedirs("pass")

# 定义命名规则
char_set = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"

# 切割图片并保存
for i in range(width // tile_width):
for j in range(height // tile_height):
tile = img.crop((i * tile_width, j * tile_height, (i + 1) * tile_width, (j + 1) * tile_height))
index = i * (height // tile_height) + j
filename = f"dict/{char_set[index]}"
# filename = f"pass/{char_set[index]}"

# 如果文件名为大写字母,则添加 '-大写' 后缀
if char_set[index].isupper():
filename += "-大写"

filename += ".png"

tile.save(filename)

print("切割完成")

切完图后,我们进行比对一下即可得到最终内容,这里可以用 np.sumsha256md5 之类的均可,只要能代表唯一。防止有人不会写代码,接着用 AI

通过 Python 读取 dict 文件夹中的所有文件,获取该文件的 md5,输出形式为字典,格式为 文件名:md5值,将其存到 dict 字典中,pass 文件夹进行相同的操作,将其存到 pass 字典中

pass 字典中的 valuedict字典中的 value 进行比对,如果两个 value 相等,则输出dictkey

这里生成的代码就有些许误差了,但是大部分逻辑是没问题的,自己手动改改即可

import os
import hashlib

def calculate_md5(filename):
"""计算文件的 MD5 值"""
hasher = hashlib.md5()
with open(filename, 'rb') as f:
for chunk in iter(lambda: f.read(4096), b""):
hasher.update(chunk)
return hasher.hexdigest()

def get_file_md5(folder):
"""获取文件夹中所有文件的 MD5 值"""
file_md5_dict = {}
for file_name in os.listdir(folder):
file_path = os.path.join(folder, file_name)
if os.path.isfile(file_path):
file_md5_dict[file_name] = calculate_md5(file_path)
return file_md5_dict

# 读取 dict 文件夹中的所有文件的 MD5 值并存储到字典中
dict_folder = "dict"
dict_md5 = get_file_md5(dict_folder)

# 读取 pass 文件夹中的所有文件的 MD5 值并存储到字典中
pass_folder = "pass"
pass_md5 = get_file_md5(pass_folder)

# 找到 pass 文件夹中与 dict 文件夹中 MD5 值相同的文件名对应的 dict 中的 key
common_keys = [key for key, value in pass_md5.items() if value in dict_md5.values()]

print("Pass 文件夹中与 Dict 文件夹中 MD5 值相同的文件名:")

flag = ''
for key in common_keys:
matching_keys = [k for k, v in dict_md5.items() if v == pass_md5[key]]
for matching_key in matching_keys:
flag += matching_key.split('.png')[0]

print(flag + '3')

运行后即可得到马赛克隐藏的 VeraCrypt 容器密码

b143a6268e2a233

VeraCrypt 挂载后即可得到 flag3,最终 flag 如下

nkctf{39c429eb-2faf-49a0-bd24-c4f222879312}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK