惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hacker News: Front Page
P
Palo Alto Networks Blog
T
ThreatConnect
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
T
True Tiger Recordings
P
Privacy & Cybersecurity Law Blog
B
Blog
IT之家
IT之家
Last Week in AI
Last Week in AI
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
C
Comments on: Blog
Microsoft Azure Blog
Microsoft Azure Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
N
News and Events Feed by Topic
NISL@THU
NISL@THU
腾讯CDC
雷峰网
雷峰网
Security Latest
Security Latest
李成银的技术随笔
M
Microsoft Research Blog - Microsoft Research
L
LangChain Blog
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Check Point Blog
Y
Y Combinator Blog
Recent Announcements
Recent Announcements
博客园 - Franky
N
News | PayPal Newsroom
V
V2EX
A
About on SuperTechFans
The Register - Security
The Register - Security
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google Online Security Blog
Google Online Security Blog
MyScale Blog
MyScale Blog
Cisco Talos Blog
Cisco Talos Blog
Vercel News
Vercel News
WordPress大学
WordPress大学
C
Cyber Attacks, Cyber Crime and Cyber Security
The Hacker News
The Hacker News
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
爱范儿
爱范儿
A
Arctic Wolf
L
LINUX DO - 最新话题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

GamerNoTitle

第十九届软件系统安全赛 CCSSSC 2026 华南区域赛复盘(旅行日记) 第十九届 2026 软件系统安全赛华南赛区(CCSSSC2026)个人 Writeup 从 Valine 迁移到 Waline 全记录 记一次对某邮箱软件账户数量上限破解 2025 年终总结 使用 bkcrack 对 ZipCrypto 加密的 ZIP 文件进行明文爆破 2025 第五届“鹏城杯”联邦网络靶场协同攻防演练(初赛)个人 Writeup ADCTF 2025 个人出题记录 2025 羊城杯决赛个人做题思路 Writeup 2025 湾区杯决赛(AKA 珠海旅行记录) 【Volcania】2025 湾区杯初赛 Writeup 【Volcania】LilCTF2025 Writeup 【Volcania】DASCTF 2025 上半年线上赛 Writeup 【更新中】Web3 CTF 从入门到入土 记一次因修改了 WindowsApps 文件夹权限导致的 UWP 应用无法通过运行打开的修复过程 第十八届软件系统安全赛 CCSSSC 2025 全国总决赛复盘(旅行日记) 记第一次为 CTF 比赛出题的经历和踩过的坑 第十六届蓝桥杯省赛个人 Writeup 【Volcania】2025 数字中国创新大赛数据安全产业积分争夺赛初赛 Writeup 【Volcania】2025 数字创新中国大赛数字安全赛道时空数据安全赛题暨三明市第五届“红名谷”杯大赛初赛 Writeup
【Volcania】第十八届软件系统安全赛 CCSSSC 2025 华南赛区区域线下赛复盘
2025-03-25 · via GamerNoTitle

WARNING

吐槽

话在前头:这是我们队第二次打线下赛,第一次是鹏城杯决赛,但是因为考虑到保密问题所以我没写复盘

喜欢我队友下载取证 5 个 G 的附件 20KB/s 剩余时间 3 天嘛?还是说,喜欢的是我根本就进不去比赛平台 ♪

笑死了,华南赛区这边刚开始根本就进不去平台,好不容易我们队四个有一个队友进去了,结果自己的账号密码忘记了先用的我的,后面说可以重置账号密码,上报后说重置完了(为统一的一个强密码),结果还是登不进去,这不是重置了个寂寞吗……最后一个队四个人三个人用我的号,剩下一个队友用自己的

还有还有,怎么有赛事主办方提供的附件(babymooer 的附件)对系统有要求啊(据说是 Win 10 22H2 测试通过),导致我们没有任何一个人能打开这个附件(附加调试器打开就蓝屏了)

还有还有还有,从早上八点半打到下午三点半,连饭都没得吃,饿死啦!!!(哭~~~~~~

比赛题目

这次比赛共有 8 道题目,其中有 3 道 Web 题,一道 re 题,剩下的都是 MISC 题

题目列表在这里

题目名称题目分类题目描述题目备注
babymooerReverse (驱动)请在Windows 10低版本运行该程序,否则会闪退,在Windows 10 22H2测试通过。 注意: 1.请上交题目解题报告,否则题目成绩可能被判定无效。 2.提交答案时只需提交{}中的字符串。 3.请关注赛事公告,访问方法:左侧菜单栏“赛事大厅”>所报名赛事的“详情”>下拉页面“赛事公告”
babymaooer解题提示:kdmapper;内存读写。
babymaooer解题提示:一个exe两个程序。
关于驱动加载,且限制了系统的版本,导致附加调试器后我们队 re 手电脑蓝屏
justdeserializeWeb (反序列化)
ez_sightMISC (AI)公司给大家发公告了…关于 AI 视觉模型的应用以及压缩包明文爆破
razorcorWebmaybe this one is interesting…
sharkmarketMISC (Web3/Rust)sharkmarket解题提示:也许需要获得足够的 coin。用 Rust 写的合约后端
encoderPWN (Buffer)encoder题目说明:请连接socks5代理后,访问题目地址192.0.100.2:8888。socks5代理的连接信息请参考靶机中的socks5端口、用户、密码。
5G消息_TLSMISC (Traffic)Bob窃取到一个文件,并通过5G消息的形式告诉了Alice,不料他们的通信被窃听了,拿到这个文件,努力去获取最终的答案吧通过 SIP 协议明文发送的 TLS 密钥以及 HTTPS 数据流的解密
DC-ForensicsMISC (Forensics)- 小梁的域控机器被黑客攻击了,请你找出一些蛛丝马迹。 攻击者通过AD CS提权至域管理员,在攻击过程中,攻击者使用有问题的证书模版注册了一张证书,该证书的证书模版名、证书序列号是什么?(格式为模版名-序列号,如CertTemplate-2f000000064287f6f5d6ff4a91000000000006)
- 小梁的域控机器被黑客攻击了,请你找出一些蛛丝马迹。 攻击者在获取域管理员权限后,尝试上传木马文件,但是被杀毒软件查杀,上传的木马文件的绝对路径是什么?(如C:\Windows\cmd.exe)
- 小梁的域控机器被黑客攻击了,请你找出一些蛛丝马迹。 攻击者从机器中提取出了用户的连接其他机器的Windows企业凭据,凭据的连接IP、用户名、密码是什么?(格式为IP-用户名-密码,如127.0.0.1-sam-123456)
- 小梁的域控机器被黑客攻击了,请你找出一些蛛丝马迹。 攻击者创建了一个新用户组和一个新用户,并把这个用户加入了新用户组和域管理员组中,新用户组名、新用户的用户名、新用户的密码是什么?(用户组名和用户名均小写,格式为用户组名-用户名-密码 ,如admins-sam-123456)
AD 域中的子设备应急处理

比赛复盘

这次的复盘,我想先从做出来的题目开始。我们队总共做出来两道题,分别是 5G消息_TLSDC-Forensics-2

[MISC] 5G消息_TLS

Bob窃取到一个文件,并通过5G消息的形式告诉了Alice,不料他们的通信被窃听了,拿到这个文件,努力去获取最终的答案吧

附件

题目提供了一个流量包,从中可以看到可以发现 SIP 流(消息发送的流)

查询每个 SIP 流,可以得到所有的 TLS 密钥如下

SERVER_TRAFFIC_SECRET_0 9745a631db0b9b715f18a55220e17c88fdf3389c0ee899cfcc45faa8696462c1 1fbf7c07ca88c7c91be9cce4c9051f2f4bd7fb9714920661d026119ebab458db8637089348dd5a92dc75633bdcf43630
CLIENT_HANDSHAKE_TRAFFIC_SECRET 9745a631db0b9b715f18a55220e17c88fdf3389c0ee899cfcc45faa8696462c1 a98fab3039737579a50e2b3d0bbaba7c9fcf6881d26ccf15890b06d723ba605f096dbe448cd9dcc6cf4ef5c82d187bd0
SERVER_HANDSHAKE_TRAFFIC_SECRET 9745a631db0b9b715f18a55220e17c88fdf3389c0ee899cfcc45faa8696462c1 994da7436ac3193aff9c2ebaa3c072ea2c5b704683928e9f6e24d183e7e530386c1dcd186b9286f98249b4dc90d8b795
EXPORTER_SECRET 9745a631db0b9b715f18a55220e17c88fdf3389c0ee899cfcc45faa8696462c1 31882156a3212a425590ce171cb78068ee63e7358b587fed472d45d67ea567d98a079c84867a18665732cf0bfe18f0b0
CLIENT_TRAFFIC_SECRET_0 9745a631db0b9b715f18a55220e17c88fdf3389c0ee899cfcc45faa8696462c1 646306cb35d94f23e125225dc3d3c727df65b6fcec4c6cd77b6f8e2ff36d48e2b7e92e8f9188597c961866b3b667f405

NOTE

这里的解密过程参考了 @Lunatic 的 Misc-Network Traffic Analysis

刚好我们在赛前看到了这个大佬的 MISC Guide,认为他的经验能够帮助我们在比赛中完成题目,遂将他的 Blog 从 Github 下载了下来,使用 Python 的 http.server 本地浏览,没想到真的能够派上用场

在这里真的很感谢这位大佬,能够公开自己的静态网站的仓库,最后能被我们派上用场

把这个密钥丢到 wireshark 的 TLS 设置里面

为了确定是否正确,我上面是指定了一个 Debug File 的,打开这个文件,可以看到里面的提示

dissect_ssl enter frame #27 (first time)
packet_from_server: is from server - TRUE
  conversation = 0000026E74E34DA0, ssl_session = 0000026E74E358F0
  record: offset = 0, reported_length_remaining = 1386
ssl_try_set_version found version 0x0303 -> state 0x91
dissect_ssl3_record: content_type 22 Handshake
decrypt_ssl3_record: app_data len 69, ssl state 0x91
packet_from_server: is from server - TRUE
decrypt_ssl3_record: using server decoder
decrypt_ssl3_record: no decoder available
dissect_ssl3_handshake iteration 1 type 2 offset 5 length 65 bytes
ssl_try_set_version found version 0x0303 -> state 0x91
Calculating hash with offset 5 69
ssl_dissect_hnd_hello_common found SERVER RANDOM -> state 0x93
ssl_set_cipher found CIPHER 0xC030 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 -> state 0x97
trying to use TLS keylog in F:\CTF\Workspace\CCSSSC2025复赛\TLS.log
  checking keylog line: SERVER_TRAFFIC_SECRET_0 9745a631db0b9b715f18a55220e17c88fdf3389c0ee899cfcc45faa8696462c1 1fbf7c07ca88c7c91be9cce4c9051f2f4bd7fb9714920661d026119ebab458db8637089348dd5a92dc75633bdcf43630
    matched server_appdata
  checking keylog line: CLIENT_HANDSHAKE_TRAFFIC_SECRET 9745a631db0b9b715f18a55220e17c88fdf3389c0ee899cfcc45faa8696462c1 a98fab3039737579a50e2b3d0bbaba7c9fcf6881d26ccf15890b06d723ba605f096dbe448cd9dcc6cf4ef5c82d187bd0
    matched client_handshake
  checking keylog line: SERVER_HANDSHAKE_TRAFFIC_SECRET 9745a631db0b9b715f18a55220e17c88fdf3389c0ee899cfcc45faa8696462c1 994da7436ac3193aff9c2ebaa3c072ea2c5b704683928e9f6e24d183e7e530386c1dcd186b9286f98249b4dc90d8b795
    matched server_handshake
  checking keylog line: EXPORTER_SECRET 9745a631db0b9b715f18a55220e17c88fdf3389c0ee899cfcc45faa8696462c1 31882156a3212a425590ce171cb78068ee63e7358b587fed472d45d67ea567d98a079c84867a18665732cf0bfe18f0b0
    matched exporter
  checking keylog line: CLIENT_TRAFFIC_SECRET_0 9745a631db0b9b715f18a55220e17c88fdf3389c0ee899cfcc45faa8696462c1 646306cb35d94f23e125225dc3d3c727df65b6fcec4c6cd77b6f8e2ff36d48e2b7e92e8f9188597c961866b3b667f405
    matched client_appdata
tls13_load_secret TLS version 0x303 is not 1.3
tls13_load_secret TLS version 0x303 is not 1.3
  record: offset = 74, reported_length_remaining = 1312
  need_desegmentation: offset = 74, reported_length_remaining = 1312

里面写了 matched 说明我们找对了,过滤 HTTP 协议,可以看见一张图片

把图片的数据流拿出来,丢进赛博厨子就能看到 flag 了

得到 flag 为 abcdef1234567890deadbeefc0ffeeba

附:使用电脑的时候导出 SSLKEY

WARNING

需要使用 Google Chrome!!!Edge不行!!!

在环境变量中添加名为 SSLKEYLOGFILE 的变量即可,内容为你需要保存的文件路径

然后直接打开 Google Chrome 访问网站,在你指定的文件里面就会出现 SSLKEY 了

[MISC | Forensics] DC-Forensics-2

小梁的域控机器被黑客攻击了,请你找出一些蛛丝马迹。 攻击者在获取域管理员权限后,尝试上传木马文件,但是被杀毒软件查杀,上传的木马文件的绝对路径是什么?(如C:\Windows\cmd.exe)

这整个系列的题目,我们队的入手点都是这台 Windows 电脑的事件管理器保存下来的事件文件,我们从 C:\Windows\System32\winevt 可以看到 Windows 电脑的事件文件

导出后,在里面可以发现 Microsoft-Windows-Windows Defender%4Operational.evtx,得知电脑使用的是 Windows Defender 作为杀软

打开这个事件日志后,在第二行的警告里面就能看到木马

得到结果为 C:\Users\Public\e9caab4405a14fb6.exe

[MISC | AI] ez_sight | 赛后出

公司给大家发公告了…

附件

题目提供了一个压缩包,里面有 flag.pyworkspace.zip公告.txt 三个文件

公告的内容如下

各位员工:

为了提升公司的安全管理水平,从即日起,我司将引入AI技术对通行密码进行管理。相关的密码图片内容已整理并放入压缩包中,压缩包的密码将由各部门负责组织发放,请大家留意部门通知。

请注意公司内部AI模型的使用规范:
1.除最后一层外与池化层外其他隐藏层输出均需要通过激活函数
2.至少需要通过两次池化层
3.注意隐藏之间输出数据格式的匹配,必要时对数据张量进行重塑
4.为保证模型准确性,输入图片应转换为灰度图


感谢大家的配合与支持。如有疑问,请随时与人事部联系。

此致

从这个文本文件我们可以知道这个题是个 AI 题,要调用它提供的模型来进行图片的辨认

CAUTION

笑死了这个题,我们队里有人看出来了这是压缩包明文爆破,但是但是,我们没有一个人电脑里有 bkcrack……

ZIP 文件里的内容可以用一种叫 ZipCrypto 的加密方式保护,靠密码生成一串随机字节,跟文件内容“混在一起”变成加密后的数据。它的核心是个由三个数字组成的小机器,先用密码启动,然后边加密边更新。但这方法有个弱点:如果有人知道加密后的内容和至少 12 个字节的原文,就能破解这个小机器的内部状态。掌握了状态,就能解开所有用同一密码加密的内容,还能试着猜密码,难度大概是“字符种类数 × 密码长度 - 6”。简单说,就是不够安全,容易被攻破。

压缩包明文攻击的条件

  • 攻击需要至少 12 个字节的已知明文。其中至少 8 个必须是连续的。连续的已知明文越大,攻击速度越快。

解开压缩包

这个题目已经给了我们 公告.txt 文件,并且压缩包内也有这个公告,满足且远远满足于我们的条件

使用这样的命令来 crack 我们的 zip

$ .\bkcrack.exe -C F:\CTF\Workspace\CCSSSC2025复赛\ez_sight\workspace.zip -c 公告.txt -p F:\CTF\Workspace\CCSSSC2025复\ez_sight\公告.txt

这里的参数是这样的

  • -C F:\CTF\Workspace\CCSSSC2025复赛\ez_sight\workspace.zip 表示需要 crack 的压缩包文件
  • -c 公告.txt 压缩包内的已知明文的文件
  • -p F:\CTF\Workspace\CCSSSC2025复赛\ez_sight\公告.txt 对应压缩包内已知明文文件的文件,即压缩包内的文件解压后的文件

等一会,就会给我们三个 key

bkcrack 1.7.1 - 2024-12-21
[15:29:32] Z reduction using 687 bytes of known plaintext
100.0 % (687 / 687)
[15:29:33] Attack on 14755 Z values at index 18
Keys: ffe9e9e9 d65f814a f3c468c9
85.3 % (12585 / 14755)
Found a solution. Stopping.
You may resume the attack with the option: --continue-attack 12585
[15:29:45] Keys
ffe9e9e9 d65f814a f3c468c9

通过这三个 key 我们能够生成一个使用我们自己的密码加密过后的压缩包,也就是说生成的压缩包的密码是已知的

$ .\bkcrack.exe -C F:\CTF\Workspace\CCSSSC2025复赛\ez_sight\workspace.zip -k ffe9e9e9 d65f814a f3c468c9 -U F:\CTF\Workspace\CCSSSC2025复赛\ez_sight\Unlock.zip Volcania
bkcrack 1.7.1 - 2024-12-21
[15:34:06] Writing unlocked archive F:\CTF\Workspace\CCSSSC2025澶嶈禌\ez_sight\Unlock.zip with password "Volcania"
100.0 % (16 / 16)
Wrote unlocked archive.

这里的参数是这样的

  • -C F:\CTF\Workspace\CCSSSC2025复赛\ez_sight\workspace.zip 表示需要 crack 的压缩包文件(上面讲过)

  • -k ffe9e9e9 d65f814a f3c468c9 上面解出来的密钥,按照 bkcrack 的说明

    -k, --keys <X> <Y> <Z>      Internal password representation as three 32-bits
                                  integers in hexadecimal (requires -d, -D, -U,
                                  --change-keys or --bruteforce)
  • -U F:\CTF\Workspace\CCSSSC2025复赛\ez_sight\Unlock.zip Volcania 生成一个新的解锁包,这个压缩包的密码是 Volcania

这个时候,再用我们自己的密码进行解压,就可以得到压缩包里面的附件了

现在可以使用这个压缩包里面的文件了,按照题目的要求,我们需要加载这个模型来识别图片

踩坑环节

首先我们得知道这个模型的各种参数,我使用的是离线的 netron 进行识别的

可以看到这个模型里面的各个参数,与公告是能对应上的

这里抄了别人的调用代码,确实没学过怎么调用模型

import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np
from PIL import Image
from torch.serialization import safe_globals
import os

# 根据模型实际结构定义SimpleCNN类
class SimpleCNN(nn.Module):
    def __init__(self):
        super(SimpleCNN, self).__init__()
        # 第一层卷积层 (1 -> 32)
        self.conv1 = nn.Conv2d(1, 32, kernel_size=3, padding=1)
        # 第二层卷积层 (32 -> 64)
        self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1)
        # 全连接层
        self.fc1 = nn.Linear(64 * 7 * 7, 128)
        self.fc2 = nn.Linear(128, 10)

    def forward(self, x):
        # 第一层卷积 + 激活 + 池化
        x = F.relu(self.conv1(x))
        x = F.max_pool2d(x, 2)
        # 第二层卷积 + 激活 + 池化
        x = F.relu(self.conv2(x))
        x = F.max_pool2d(x, 2)
        # 重塑张量
        x = x.view(-1, 64 * 7 * 7)
        # 全连接层
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return x

# 加载模型
def load_model(model_path):
    # 添加SimpleCNN到安全全局变量列表中
    safe_globals_list = [SimpleCNN]
    
    # 使用safe_globals上下文管理器来安全加载模型
    with safe_globals(safe_globals_list):
        model = torch.load(model_path, weights_only=False)
    
    model.eval()
    return model

# 对现有图像进行预测
def predict_images(model_path, image_paths):
    # 加载模型
    model = load_model(model_path)
    
    results = []
    for img_path in image_paths:
        try:
            # 加载图像并转换为灰度图
            img = Image.open(img_path).convert('L')
            # 调整图像大小为28x28
            img = img.resize((28, 28))
            # 转换为张量
            img_tensor = torch.tensor(np.array(img)).float() / 255.0
            img_tensor = img_tensor.unsqueeze(0).unsqueeze(0)  # 添加批次和通道维度
            
            # 进行预测
            with torch.no_grad():
                output = model(img_tensor)
                prob = F.softmax(output, dim=1)
                pred_class = torch.argmax(prob, dim=1).item()
                confidence = prob[0][pred_class].item()
            
            results.append({
                'image': os.path.basename(img_path),
                'prediction': pred_class,
                'confidence': confidence
            })
            
            print(f"图像 {os.path.basename(img_path)} 预测为: {pred_class}, 置信度: {confidence:.4f}")
        except Exception as e:
            print(f"处理图像 {img_path} 时出错: {e}")
    
    return results

# 主函数
def main():
    model_path = "./password.pt"
    
    # 对已有的0-13.bmp图像进行预测
    image_paths = [f"./flag/{i}.bmp" for i in range(14)]
    print("分析数字图像...")
    predictions = predict_images(model_path, image_paths)
    
    # 打印预测结果摘要
    print("\n预测结果摘要:")
    predicted_digits = ""
    for p in predictions:
        predicted_digits += str(p['prediction'])
    print(f"数字序列: {predicted_digits}")
    
    # 尝试将数字序列转换为ASCII字符
    try:
        ascii_text = ""
        for i in range(0, len(predicted_digits), 2):
            if i+1 < len(predicted_digits):
                char_code = int(predicted_digits[i:i+2])
                if 32 <= char_code <= 126:  # 可打印ASCII范围
                    ascii_text += chr(char_code)
        if ascii_text:
            print(f"可能的ASCII文本: {ascii_text}")
    except Exception as e:
        print(f"转换ASCII时出错: {e}")

if __name__ == "__main__":
    main()

所以 flag 大概应该是 81294687889085

但是队友后来提醒我,官方给了验证的脚本

import uuid
import hashlib
flag = input()# press the corrcet password
final_flag = "dart{" + str(uuid.uuid3(uuid.UUID('11341600-1542-4ee8-b148-23940f18186b'),flag)) + "}"

if hashlib.sha256(final_flag.encode("utf8")).hexdigest() == "115159c751ddf16c527ee96f998ed55ed8a3302f2fd04ba60682493883901684":
    print("correct flag:" + final_flag)

然后输了进去,发现不对

正确解法

问了一下兄弟队(他们当场就做出来了),说要挑概率大的去爆破

这里我们队的 @Jeremiah 改了一下上面搬的脚本

import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np
from PIL import Image
from torch.serialization import safe_globals
import os

class SimpleCNN(nn.Module):
    def __init__(self):
        super(SimpleCNN, self).__init__()
        self.conv1 = nn.Conv2d(1, 32, kernel_size=3, padding=1)
        self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1)
        self.fc1 = nn.Linear(64 * 7 * 7, 128)
        self.fc2 = nn.Linear(128, 10)

    def forward(self, x):
        x = F.relu(self.conv1(x))
        x = F.max_pool2d(x, 2)
        x = F.relu(self.conv2(x))
        x = F.max_pool2d(x, 2)
        x = x.view(-1, 64 * 7 * 7)
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return x

def load_model(model_path):
    safe_globals_list = [SimpleCNN]
    with safe_globals(safe_globals_list):
        model = torch.load(model_path, weights_only=False)
    model.eval()
    return model

def predict_images(model_path, image_paths):
    model = load_model(model_path)
    
    results = []
    for img_path in image_paths:
        try:
            img = Image.open(img_path).convert('L')
            img = img.resize((28, 28))
            img_tensor = torch.tensor(np.array(img)).float() / 255.0
            img_tensor = img_tensor.unsqueeze(0).unsqueeze(0)
            
            with torch.no_grad():
                output = model(img_tensor)
                prob = F.softmax(output, dim=1)
                pred_class = torch.argmax(prob, dim=1).item()
                confidence = prob[0][pred_class].item()
                
                # 获取所有类别的置信度
                all_confidences = {str(i): prob[0][i].item() for i in range(10)}
            
            results.append({
                'image': os.path.basename(img_path),
                'prediction': pred_class,
                'confidence': confidence,
                'all_confidences': all_confidences  # 添加所有类别的置信度
            })
            
            print(f"\n图像 {os.path.basename(img_path)} 预测结果:")
            print(f"预测为: {pred_class}, 最高置信度: {confidence:.4f}")
            print("所有类别置信度:")
            for cls, conf in sorted(all_confidences.items(), key=lambda x: x[1], reverse=True):
                print(f"  类别 {cls}: {conf:.4f}")
                
        except Exception as e:
            print(f"\n处理图像 {img_path} 时出错: {e}")
    
    return results

def main():
    model_path = "./password.pt"
    
    image_paths = [f"./flag/{i}.bmp" for i in range(14)]
    print("分析数字图像...")
    predictions = predict_images(model_path, image_paths)
    
    print("\n预测结果摘要:")
    predicted_digits = ""
    for p in predictions:
        predicted_digits += str(p['prediction'])
    print(f"数字序列: {predicted_digits}")
    
    try:
        ascii_text = ""
        for i in range(0, len(predicted_digits), 2):
            if i+1 < len(predicted_digits):
                char_code = int(predicted_digits[i:i+2])
                if 32 <= char_code <= 126:
                    ascii_text += chr(char_code)
        if ascii_text:
            print(f"可能的ASCII文本: {ascii_text}")
    except Exception as e:
        print(f"转换ASCII时出错: {e}")

if __name__ == "__main__":
    main()

能够得到这样的数据

图像 0.bmp 预测结果:
预测为: 8, 最高置信度: 0.5042
所有类别置信度:
  类别 8: 0.5042
  类别 0: 0.4952
  类别 9: 0.0003
  类别 2: 0.0001
  类别 5: 0.0001
  类别 6: 0.0000
  类别 3: 0.0000
  类别 7: 0.0000
  类别 1: 0.0000
  类别 4: 0.0000

图像 1.bmp 预测结果:
预测为: 1, 最高置信度: 0.9922
所有类别置信度:
  类别 1: 0.9922
  类别 7: 0.0073
  类别 4: 0.0003
  类别 8: 0.0002
  类别 9: 0.0000
  类别 0: 0.0000
  类别 5: 0.0000
  类别 6: 0.0000
  类别 2: 0.0000
  类别 3: 0.0000

图像 2.bmp 预测结果:
预测为: 2, 最高置信度: 0.9129
所有类别置信度:
  类别 2: 0.9129
  类别 8: 0.0871
  类别 1: 0.0000
  类别 0: 0.0000
  类别 9: 0.0000
  类别 3: 0.0000
  类别 6: 0.0000
  类别 7: 0.0000
  类别 5: 0.0000
  类别 4: 0.0000

图像 3.bmp 预测结果:
预测为: 9, 最高置信度: 0.7812
所有类别置信度:
  类别 9: 0.7812
  类别 3: 0.1638
  类别 5: 0.0448
  类别 8: 0.0102
  类别 0: 0.0000
  类别 2: 0.0000
  类别 6: 0.0000
  类别 4: 0.0000
  类别 7: 0.0000
  类别 1: 0.0000

图像 4.bmp 预测结果:
预测为: 4, 最高置信度: 0.9690
所有类别置信度:
  类别 4: 0.9690
  类别 7: 0.0152
  类别 1: 0.0140
  类别 9: 0.0016
  类别 5: 0.0002
  类别 8: 0.0000
  类别 3: 0.0000
  类别 2: 0.0000
  类别 6: 0.0000
  类别 0: 0.0000

图像 5.bmp 预测结果:
预测为: 6, 最高置信度: 0.6037
所有类别置信度:
  类别 6: 0.6037
  类别 5: 0.3927
  类别 8: 0.0034
  类别 4: 0.0001
  类别 0: 0.0000
  类别 1: 0.0000
  类别 9: 0.0000
  类别 3: 0.0000
  类别 7: 0.0000
  类别 2: 0.0000

图像 6.bmp 预测结果:
预测为: 8, 最高置信度: 0.6195
所有类别置信度:
  类别 8: 0.6195
  类别 6: 0.3054
  类别 5: 0.0751
  类别 0: 0.0000
  类别 9: 0.0000
  类别 3: 0.0000
  类别 1: 0.0000
  类别 7: 0.0000
  类别 2: 0.0000
  类别 4: 0.0000

图像 7.bmp 预测结果:
预测为: 7, 最高置信度: 0.5370
所有类别置信度:
  类别 7: 0.5370
  类别 8: 0.4267
  类别 1: 0.0317
  类别 9: 0.0033
  类别 0: 0.0010
  类别 2: 0.0002
  类别 3: 0.0000
  类别 5: 0.0000
  类别 4: 0.0000
  类别 6: 0.0000

图像 8.bmp 预测结果:
预测为: 8, 最高置信度: 0.8916
所有类别置信度:
  类别 8: 0.8916
  类别 3: 0.1081
  类别 5: 0.0003
  类别 9: 0.0000
  类别 2: 0.0000
  类别 1: 0.0000
  类别 6: 0.0000
  类别 4: 0.0000
  类别 0: 0.0000
  类别 7: 0.0000

图像 9.bmp 预测结果:
预测为: 8, 最高置信度: 0.5110
所有类别置信度:
  类别 8: 0.5110
  类别 9: 0.4890
  类别 4: 0.0000
  类别 0: 0.0000
  类别 3: 0.0000
  类别 7: 0.0000
  类别 2: 0.0000
  类别 5: 0.0000
  类别 6: 0.0000
  类别 1: 0.0000

图像 10.bmp 预测结果:
预测为: 9, 最高置信度: 0.9950
所有类别置信度:
  类别 9: 0.9950
  类别 4: 0.0046
  类别 7: 0.0003
  类别 8: 0.0000
  类别 3: 0.0000
  类别 5: 0.0000
  类别 2: 0.0000
  类别 1: 0.0000
  类别 0: 0.0000
  类别 6: 0.0000

图像 11.bmp 预测结果:
预测为: 0, 最高置信度: 0.5646
所有类别置信度:
  类别 0: 0.5646
  类别 8: 0.4350
  类别 6: 0.0003
  类别 3: 0.0001
  类别 9: 0.0000
  类别 5: 0.0000
  类别 2: 0.0000
  类别 1: 0.0000
  类别 4: 0.0000
  类别 7: 0.0000

图像 12.bmp 预测结果:
预测为: 8, 最高置信度: 0.8498
所有类别置信度:
  类别 8: 0.8498
  类别 5: 0.0835
  类别 2: 0.0667
  类别 7: 0.0000
  类别 4: 0.0000
  类别 1: 0.0000
  类别 6: 0.0000
  类别 9: 0.0000
  类别 3: 0.0000
  类别 0: 0.0000

图像 13.bmp 预测结果:
预测为: 5, 最高置信度: 0.9871
所有类别置信度:
  类别 5: 0.9871
  类别 7: 0.0125
  类别 2: 0.0002
  类别 1: 0.0001
  类别 4: 0.0001
  类别 6: 0.0000
  类别 3: 0.0000
  类别 9: 0.0000
  类别 8: 0.0000
  类别 0: 0.0000

也就是说,图片1~13分别可能是

candidates = [
    [8, 0, 9, 2, 5],    # 0.bmp: 8(0.5042), 0(0.4952)
    [1, 7, 4, 8],       # 1.bmp: 1(0.9922)
    [2, 8],       # 2.bmp: 2(0.9129)
    [9, 3, 5, 8], # 3.bmp: 9(0.7812), 3(0.1638), 5(0.0448)
    [4, 7, 1, 9, 5],       # 4.bmp: 4(0.9690)
    [6, 5, 8, 4],    # 5.bmp: 6(0.6037), 5(0.3927)
    [8, 6, 5], # 6.bmp: 8(0.6195), 6(0.3053), 5(0.0751)
    [7, 8, 1, 9, 0, 2],    # 7.bmp: 7(0.5370), 8(0.4267)
    [8, 3, 5],       # 8.bmp: 8(0.8916)
    [8, 9],    # 9.bmp: 8(0.5110), 9(0.4890)
    [9, 4, 7],       # 10.bmp: 9(0.9950)
    [0, 8, 6, 3],    # 11.bmp: 0(0.5646), 8(0.4350)
    [8, 5, 2],       # 12.bmp: 8(0.8498)
    [5]        # 13.bmp: 5(0.9871)
]

于是写了这样的一个爆破脚本(即这个位置可能是什么东西,列举出所有的可能进行爆破求解)

import uuid
import hashlib
from itertools import product

# 定义每个位置的候选数字(置信度>0的)
candidates = [
    [8, 0, 9, 2, 5],    # 0.bmp: 8(0.5042), 0(0.4952)
    [1, 7, 4, 8],       # 1.bmp: 1(0.9922)
    [2, 8],       # 2.bmp: 2(0.9129)
    [9, 3, 5, 8], # 3.bmp: 9(0.7812), 3(0.1638), 5(0.0448)
    [4, 7, 1, 9, 5],       # 4.bmp: 4(0.9690)
    [6, 5, 8, 4],    # 5.bmp: 6(0.6037), 5(0.3927)
    [8, 6, 5], # 6.bmp: 8(0.6195), 6(0.3053), 5(0.0751)
    [7, 8, 1, 9, 0, 2],    # 7.bmp: 7(0.5370), 8(0.4267)
    [8, 3, 5],       # 8.bmp: 8(0.8916)
    [8, 9],    # 9.bmp: 8(0.5110), 9(0.4890)
    [9, 4, 7],       # 10.bmp: 9(0.9950)
    [0, 8, 6, 3],    # 11.bmp: 0(0.5646), 8(0.4350)
    [8, 5, 2],       # 12.bmp: 8(0.8498)
    [5]        # 13.bmp: 5(0.9871)
]

# 生成所有可能的组合
def generate_combinations():
    # 对于每个位置,按置信度从高到低排序候选数字
    ordered_candidates = []
    for pos in candidates:
        ordered_candidates.append(pos)
    
    # 生成所有可能的组合
    return product(*ordered_candidates)

# 检查flag是否正确
def check_flag(flag_str):
    final_flag = "dart{" + str(uuid.uuid3(uuid.UUID('11341600-1542-4ee8-b148-23940f18186b'), flag_str)) + "}"
    if hashlib.sha256(final_flag.encode("utf8")).hexdigest() == "115159c751ddf16c527ee96f998ed55ed8a3302f2fd04ba60682493883901684":
        print("找到正确flag!")
        print("正确flag:", final_flag)
        return True
    return False

# 爆破函数
def brute_force():
    total = 1
    for c in candidates:
        total *= len(c)
    print(f"总共有 {total} 种可能的组合")
    
    tried = 0
    for combo in generate_combinations():
        tried += 1
        flag_str = ''.join(map(str, combo))
        
        # 每10000次尝试打印一次进度
        if tried % 10000 == 0:
            print(f"已尝试 {tried}/{total} 组合, 当前尝试: {flag_str}")
        
        if check_flag(flag_str):
            return
    
    print("未找到匹配的flag")

if __name__ == "__main__":
    brute_force()

最后得到flag

dart{2855dc9b-b8c2-3c82-86d9-6afa9111b715}

咕咕咕

剩下的有空再写

总结

这次主要还是凸显了几个不足的地方吧,首先是工具不够,本来就是线下赛没有网的我们还没有提前下好 bkcrack 这种工具;其次还是经验太少了,对于 Windows 的域渗透取证,我们还是没就接触过,虽然以前做过 Windows 的取证,但那个不是域的,所以是经验太少了。

说实话,比赛的后半程有点坐牢,因为我们在努力找取证题的答案,但是找不到,很难受

不知道到底进多少个队,据说是 19 个,如果是 19 个的话我们能进决赛,等通知了