NCTF 2024 Minecraft内存取证 [2025/03/25]

这次是一道Minecraft内存取证题目,先简单用R-Stdio看了一下,发现是在Linux上装的mcsm面板,使用Vol分析banner去制作符号表

image-20250322181447577

1
2
3
4
5
6
7
8
9
10
C:\Users\YY>D:\Software\LovelyMem\Tools\python3\python.exe D:\Software\LovelyMem\Tools\volatility3\vol.py -f E:\BaiduNetdiskDownload\1.mem banners.Banners
Volatility 3 Framework 2.8.0
Progress: 100.00 PDB scanning finished
Offset Banner

0x213a001a0 Linux version 5.4.0-205-generic (buildd@lcy02-amd64-055) (gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.2)) #225-Ubuntu SMP Fri Jan 10 22:23:35 UTC 2025 (Ubuntu 5.4.0-205.225-generic 5.4.284)
0x2155a0e54 Linux version 5.4.0-205-generic (buildd@lcy02-amd64-055) (gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.2)) #225-Ubuntu SMP Fri Jan 10 22:23:35 UTC 2025 (Ubuntu 5.4.0-205.225-generic 5.4.284)
0x23fec9390 Linux version 5.4.0-205-generic (buildd@lcy02-amd64-055) (gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.2)) #225-Ubuntu SMP Fri Jan 10 22:23:35 UTC 2025 (Ubuntu 5.4.0-205.225-generic 5.4.284)

C:\Users\YY>

Vol3制作过程,或直接使用leludo84/vol3-linux-profiles: Volatility3 Linux profiles (github.com)

1
2
3
4
5
6
7
8
9
10
11
wget https://github.com/volatilityfoundation/dwarf2json/releases/download/v0.9.0/dwarf2json-linux-amd64
docker pull ubuntu 20.04
# https://launchpad.net/ubuntu/+source/linux/5.4.0-208.228
wget https://launchpadlibrarian.net/769817990/linux-image-unsigned-5.4.0-205-generic-dbgsym_5.4.0-205.225_amd64.ddeb
docker run -it --rm -v $PWD:/volatility ubuntu:20.04 /bin/bash
cd volatility
dpkg -i linux-image-unsigned-5.4.0-205-generic-dbgsym_5.4.0-205.225_amd64.ddeb
./dwarf2json-linux-amd64 linux --elf /usr/lib/debug/boot/vmlinux-5.4.0-205-generic > linu
x-image-5.4.0-205-generic.json
exit
cp linux-image-5.4.0-205-generic.json /mnt/d/Software/LovelyMem/Tools/volatility3/volatility3/framework/symbols/linux

vol2使用CTF-Archives/profile-builder: A demo for automatically build dwarf file for volatility2 (github.com)进行制作(Ubuntu Debian)[需要Docker Desktop]

参考

http://www.s1mh0.cn/blog/index.php/2023/12/20/linux_ncqz/

Misc-Forensics - ⚡Lunatic BLOG⚡ (goodlunatic.github.io)

1
2
3
4
5
6
# http://www.s1mh0.cn/blog/index.php/2023/12/20/linux_ncqz/
docker run -it --name lin_vol_make ubuntu:20.04 /bin/bash
apt update
apt install linux-image-5.4.0-205-generic linux-headers-5.4.0-205-generic -y
docker restart lin_vol_make
docker exec -it lin_vol_make /bin/bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
FROM ubuntu:20.04

ENV TZ=Asia/Shanghai
ENV DEBIAN_FRONTEND=noninteractive
ENV UBUNTU_FRONTEND=noninteractive

COPY ./service/docker-entrypoint.sh /docker-entrypoint.sh
COPY ./src/ /src/

RUN sed -i 's/archive.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list \
&& sed -i 's/security.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list \
&& apt update --no-install-recommends\
&& apt install -y openssh-server gcc-10 dwarfdump build-essential unzip wget\
&& chmod +x /docker-entrypoint.sh \
&& mkdir /app \
&& sed -i 's/\#PermitRootLogin prohibit-password/PermitRootLogin yes/g' /etc/ssh/sshd_config \
&& sed -i 's/\#PasswordAuthentication yes/PasswordAuthentication yes/g' /etc/ssh/sshd_config \
&& echo 'root:root' | chpasswd \
&& systemctl enable ssh \
&& service ssh start


# https://mirrors.ustc.edu.cn/ubuntu/pool/main/l/linux/
RUN wget https://mirrors.ustc.edu.cn/ubuntu/pool/main/l/linux/linux-image-unsigned-5.4.0-205-generic_5.4.0-205.225_amd64.deb -P /src/ \
&& wget https://mirrors.ustc.edu.cn/ubuntu/pool/main/l/linux/linux-headers-5.4.0-205-generic_5.4.0-205.225_amd64.deb -P /src/ \
&& wget https://mirrors.ustc.edu.cn/ubuntu/pool/main/l/linux/linux-headers-5.4.0-205_5.4.0-205.225_all.deb -P /src/ \
&& wget https://mirrors.ustc.edu.cn/ubuntu/pool/main/l/linux/linux-modules-5.4.0-205-generic_5.4.0-205.225_amd64.deb -P /src/

WORKDIR /src

RUN unzip tool.zip && apt-get update && apt-get install -y kmod linux-base initramfs-tools
RUN dpkg -i linux-headers-5.4.0-205_5.4.0-205.225_all.deb \
&& dpkg -i linux-headers-5.4.0-205-generic_5.4.0-205.225_amd64.deb \
&& dpkg -i linux-modules-5.4.0-205-generic_5.4.0-205.225_amd64.deb \
&& dpkg -i linux-image-unsigned-5.4.0-205-generic_5.4.0-205.225_amd64.deb \
&& apt --fix-broken install -y

RUN ls -la /lib/modules/5.4.0-205-generic/ \
&& mkdir -p /lib/modules/5.4.0-205-amd64/ \
&& ln -sf /usr/src/linux-headers-5.4.0-205-generic /lib/modules/5.4.0-205-amd64/build


WORKDIR /src/linux

RUN echo 'MODULE_LICENSE("GPL");' >> module.c && \
sed -i 's/$(shell uname -r)/5.4.0-205-generic/g' Makefile && \
make && \
mv module.dwarf /app && \
cp /boot/System.map* /app

WORKDIR /app

RUN zip ubuntu-5.4.0-205-generic.zip *

CMD ["/bin/bash"]
# docker run -it -p 7080:8000 profile:v1 bash
# cd /app
# python3 -m http.server

linux_find_file -L列出全部文件,保存到flie.txt

image-20250323042423481

找到面板用户数据,直接提取

1
D:\Software\LovelyMem\Tools\python27\python27.exe D:\Software\LovelyMem\Tools\volatility-master\vol.py -f E:\BaiduNetdiskDownload\1.mem --profile=Linuxubuntu-5_4_0-205-genericx64 linux_find_file -i 0xffff9d4468415688 -O extracted_user_file.json

image-20250323042438811

然后使用hashcat爆破得到密码

1
2
.\hashcat.exe -m 3200 -a 0 hash.txt D:\Software\ONE-FOX集成工具箱_V8.2公开版_by狐狸\gui_scan\tscanplus\config\CrackDict\rockyou.txt --show
$2a$10$jtOn5mgMKwhjevsKPe/ps.CIRJ1NoP/uAFWNZos7OF8vzKKGJrIxm:I0am0alone

image-20250323110531511

往下翻发现有backup和log,直接提取日志,并编写python代码批量提取backup文件,同时提取usercache.json来寻找uuid对应的用户名

PS:提取的时候忘记是新建的窗口了,找半天在User里(

image-20250323111032841

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import os
import subprocess

# 内存镜像路径
mem_file = "E:\\BaiduNetdiskDownload\\1.mem"
profile = "Linuxubuntu-5_4_0-205-genericx64"
volatility_path = "D:\\Software\\LovelyMem\\Tools\\volatility-master\\vol.py"
python_path = "D:\\Software\\LovelyMem\\Tools\\python27\\python27.exe"
output_dir = ".\\b\\"

# 确保输出目录存在
if not os.path.exists(output_dir):
os.makedirs(output_dir)

# 需要提取的备份文件列表(使用直接偏移量)
backup_files = [
# 格式: offset, 文件路径, 输出文件名
("0xffff9d43832b5688",
"/opt/mcsmanager/daemon/data/InstanceData/e00336260129441a9b74844d485b2cd6/backups/2025-2-14_10-20-0.zip"),
("0xffff9d43a8b0a328",
"/opt/mcsmanager/daemon/data/InstanceData/e00336260129441a9b74844d485b2cd6/backups/2025-2-14_10-10-0.zip"),
("0xffff9d439a413000",
"/opt/mcsmanager/daemon/data/InstanceData/e00336260129441a9b74844d485b2cd6/backups/2025-2-14_10-0-0.zip"),
("0xffff9d439a415ad0",
"/opt/mcsmanager/daemon/data/InstanceData/e00336260129441a9b74844d485b2cd6/backups/2025-2-14_9-50-0.zip"),
("0xffff9d439a413448",
"/opt/mcsmanager/daemon/data/InstanceData/e00336260129441a9b74844d485b2cd6/backups/2025-2-14_9-40-0.zip"),
("0xffff9d438314cdf8",
"/opt/mcsmanager/daemon/data/InstanceData/e00336260129441a9b74844d485b2cd6/backups/2025-2-14_9-30-0.zip"),
("0xffff9d43a8b0abb8",
"/opt/mcsmanager/daemon/data/InstanceData/e00336260129441a9b74844d485b2cd6/backups/2025-2-14_9-20-0.zip"),
("0xffff9d439a415f18",
"/opt/mcsmanager/daemon/data/InstanceData/e00336260129441a9b74844d485b2cd6/backups/2025-2-14_9-10-0.zip"),
("0xffff9d43a8b0b890",
"/opt/mcsmanager/daemon/data/InstanceData/e00336260129441a9b74844d485b2cd6/backups/2025-2-14_9-0-0.zip"),
("0xffff9d4467e8bcd8",
"/opt/mcsmanager/daemon/data/InstanceData/e00336260129441a9b74844d485b2cd6/backups/2025-2-14_8-50-0.zip")
]

for offset, file_path in backup_files:
filename = os.path.basename(file_path)
output_path = os.path.join(output_dir, filename)

# 使用volatility的linux_dump_map命令提取指定偏移量的数据
cmd = f'{python_path} {volatility_path} -f {mem_file} --profile={profile} linux_find_file -i {offset} -O "{output_path}"'
print(f"执行: {cmd}")

try:
subprocess.call(cmd, shell=True)
print(f"已提取: {file_path} -> {output_path}")
except Exception as e:
print(f"提取失败: {file_path},错误: {str(e)}")

print("-" * 60)

# 添加提取backups.json文件的代码
backups_json_file = "/opt/mcsmanager/daemon/data/InstanceData/e00336260129441a9b74844d485b2cd6/backups/backups.json"
cmd_find = f'{python_path} {volatility_path} -f {mem_file} --profile={profile} linux_find_file -F "{backups_json_file}"'
print(f"寻找backups.json: {cmd_find}")

try:
output = subprocess.check_output(cmd_find, shell=True).decode('utf-8')
for line in output.splitlines():
if backups_json_file in line:
parts = line.split()
if len(parts) >= 2:
inode = parts[0]
output_path = os.path.join(output_dir, "backups.json")
cmd_extract = f'{python_path} {volatility_path} -f {mem_file} --profile={profile} linux_find_file -i {inode} -O "{output_path}"'
subprocess.call(cmd_extract, shell=True)
print(f"已提取: {backups_json_file} -> {output_path}")
break
except Exception as e:
print(f"提取失败: {str(e)}")

image-20250323111944203

usercache.json

image-20250323111452641

分析日志可以得到Alex的房子的位置

image-20250323044726666

从提取到的备份文件中分析stat,或重新提取stat文件,发现没有打火石使用记录,只找到了岩浆桶的,结合usercache判断出玩家名为Nathan

image-20250323111802977

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import os
import subprocess

# 内存镜像路径
mem_file = "E:\\BaiduNetdiskDownload\\1.mem"
profile = "Linuxubuntu-5_4_0-205-genericx64"
volatility_path = "D:\\Software\\LovelyMem\\Tools\\volatility-master\\vol.py"
python_path = "D:\\Software\\LovelyMem\\Tools\\python27\\python27.exe"
output_dir = "."

# 确保输出目录存在
if not os.path.exists(output_dir):
os.makedirs(output_dir)

# 文件路径和对应的偏移量(offset)
files_to_extract = [
# 服务器日志
("0xffff9d4469d29a98", "/opt/mcsmanager/daemon/data/InstanceLog/e00336260129441a9b74844d485b2cd6.log"),

# 玩家统计数据
("0xffff9d43832b3890",
"/opt/mcsmanager/daemon/data/InstanceData/e00336260129441a9b74844d485b2cd6/world/stats/c7515538-6442-3ead-8b80-f72841202097.json"),
("0xffff9d43832b1650",
"/opt/mcsmanager/daemon/data/InstanceData/e00336260129441a9b74844d485b2cd6/world/stats/4181cef3-c452-32c8-a544-99ce83c3c2dd.json"),
("0xffff9d43a8b08978",
"/opt/mcsmanager/daemon/data/InstanceData/e00336260129441a9b74844d485b2cd6/world/stats/f901a319-bc80-37bc-a06d-a93efa505645.json"),
("0xffff9d43a8b0b000",
"/opt/mcsmanager/daemon/data/InstanceData/e00336260129441a9b74844d485b2cd6/world/stats/e90b13f2-6900-3898-8ca4-3dae1a530f4f.json"),
("0xffff9d4467ea2bb8",
"/opt/mcsmanager/daemon/data/InstanceData/e00336260129441a9b74844d485b2cd6/world/stats/e5e2e6a5-49d8-3e0f-bedc-2fc9f1c76420.json"),
("0xffff9d4467e8e7a8",
"/opt/mcsmanager/daemon/data/InstanceData/e00336260129441a9b74844d485b2cd6/world/stats/285ecaf7-4fd9-3a0b-9881-fb7f09541139.json"),

# 玩家成就数据
("0xffff9d43832b3cd8",
"/opt/mcsmanager/daemon/data/InstanceData/e00336260129441a9b74844d485b2cd6/world/advancements/c7515538-6442-3ead-8b80-f72841202097.json"),
("0xffff9d43832b5ad0",
"/opt/mcsmanager/daemon/data/InstanceData/e00336260129441a9b74844d485b2cd6/world/advancements/4181cef3-c452-32c8-a544-99ce83c3c2dd.json"),
("0xffff9d43a8b09208",
"/opt/mcsmanager/daemon/data/InstanceData/e00336260129441a9b74844d485b2cd6/world/advancements/f901a319-bc80-37bc-a06d-a93efa505645.json"),
("0xffff9d43a8b0c568",
"/opt/mcsmanager/daemon/data/InstanceData/e00336260129441a9b74844d485b2cd6/world/advancements/e90b13f2-6900-3898-8ca4-3dae1a530f4f.json"),
("0xffff9d4467ea0dc0",
"/opt/mcsmanager/daemon/data/InstanceData/e00336260129441a9b74844d485b2cd6/world/advancements/e5e2e6a5-49d8-3e0f-bedc-2fc9f1c76420.json"),
("0xffff9d4467e8b448",
"/opt/mcsmanager/daemon/data/InstanceData/e00336260129441a9b74844d485b2cd6/world/advancements/285ecaf7-4fd9-3a0b-9881-fb7f09541139.json"),

# 关键备份文件
("0xffff9d43a8b0b890",
"/opt/mcsmanager/daemon/data/InstanceData/e00336260129441a9b74844d485b2cd6/backups/2025-2-14_9-0-0.zip"),
("0xffff9d4467e8bcd8",
"/opt/mcsmanager/daemon/data/InstanceData/e00336260129441a9b74844d485b2cd6/backups/2025-2-14_8-50-0.zip"),

# 玩家记录文件
("0xffff9d4467e5c9b0", "/opt/mcsmanager/daemon/data/InstanceData/e00336260129441a9b74844d485b2cd6/whitelist.json"),
("0xffff9d4467e5f480", "/opt/mcsmanager/daemon/data/InstanceData/e00336260129441a9b74844d485b2cd6/ops.json"),
("0xffff9d4467e580e8", "/opt/mcsmanager/daemon/data/InstanceData/e00336260129441a9b74844d485b2cd6/banned-ips.json"),
("0xffff9d4467e5d240",
"/opt/mcsmanager/daemon/data/InstanceData/e00336260129441a9b74844d485b2cd6/banned-players.json")
]

for offset, file_path in files_to_extract:
# 创建输出文件路径
filename = os.path.basename(file_path)
dir_name = os.path.dirname(file_path).split('/')[-1] # 获取上级目录名
output_filename = f"{dir_name}_{filename}" if dir_name else filename
output_path = os.path.join(output_dir, output_filename)

# 直接使用偏移量提取文件
cmd_extract = f'{python_path} {volatility_path} -f {mem_file} --profile={profile} linux_find_file -O "{output_path}" -i {offset}'
print(f"提取: {cmd_extract}")

try:
subprocess.call(cmd_extract, shell=True)
print(f"已提取: {file_path} -> {output_path}")
except Exception as e:
print(f"提取失败: {file_path}, 错误: {str(e)}")

print("-" * 60)

使用MCA对存档进行分析,发现在9:20-9:40直接,坐标-405_63_132的位置多了一块岩浆

进入存档确定过位置后确定了坐标

image-20250323112859702

image-20250323113033934

将找到的内容拼接,得到flag

nctf{I0am0alone_Nathan_-405_63_132}


NCTF 2024 Minecraft内存取证 [2025/03/25]
https://more678.github.io/2025/06/30/NCTF 2024 MC取证/
作者
tenstrings
发布于
2025年6月30日
许可协议