吐槽 话在前头:这是我们队第二次打线下赛,第一次是鹏城杯决赛,但是因为考虑到保密问题所以我没写复盘
喜欢我队友下载取证 5 个 G 的附件 20KB/s 剩余时间 3 天嘛?还是说,喜欢的是我根本就进不去比赛平台 ♪
笑死了,华南赛区这边刚开始根本就进不去平台,好不容易我们队四个有一个队友进去了,结果自己的账号密码忘记了先用的我的,后面说可以重置账号密码,上报后说重置完了(为统一的一个强密码),结果还是登不进去,这不是重置了个寂寞吗……最后一个队四个人三个人用我的号,剩下一个队友用自己的
还有还有,怎么有赛事主办方提供的附件(babymooer 的附件)对系统有要求啊(据说是 Win 10 22H2 测试通过),导致我们没有任何一个人能打开这个附件(附加调试器打开就蓝屏了)
还有还有还有,从早上八点半打到下午三点半,连饭都没得吃,饿死啦!!!(哭~~~~~~
比赛题目 这次比赛共有 8 道题目,其中有 3 道 Web 题,一道 re 题,剩下的都是 MISC 题
题目列表在这里
题目名称
题目分类
题目描述
题目备注
babymooer
Reverse (驱动)
请在Windows 10低版本运行该程序,否则会闪退,在Windows 10 22H2测试通过。 注意: 1.请上交题目解题报告,否则题目成绩可能被判定无效。 2.提交答案时只需提交{}中的字符串。 3.请关注赛事公告,访问方法:左侧菜单栏“赛事大厅”>所报名赛事的“详情”>下拉页面“赛事公告” babymaooer解题提示:kdmapper;内存读写。 babymaooer解题提示:一个exe两个程序。
关于驱动加载,且限制了系统的版本,导致附加调试器后我们队 re 手电脑蓝屏
justdeserialize
Web (反序列化)
ez_sight
MISC (AI)
公司给大家发公告了….
关于 AI 视觉模型的应用以及压缩包明文爆破
razorcor
Web
maybe this one is interesting….
sharkmarket
MISC (Web3/Rust)
sharkmarket解题提示:也许需要获得足够的 coin。
用 Rust 写的合约后端
encoder
PWN (Buffer)
encoder题目说明:请连接socks5代理后,访问题目地址192.0.100.2:8888。socks5代理的连接信息请参考靶机中的socks5端口、用户、密码。
5G消息_TLS
MISC (Traffic)
Bob窃取到一个文件,并通过5G消息的形式告诉了Alice,不料他们的通信被窃听了,拿到这个文件,努力去获取最终的答案吧
通过 SIP 协议明文发送的 TLS 密钥以及 HTTPS 数据流的解密
DC-Forensics
MISC (Forensics)
- 小梁的域控机器被黑客攻击了,请你找出一些蛛丝马迹。 攻击者通过AD CS提权至域管理员,在攻击过程中,攻击者使用有问题的证书模版注册了一张证书,该证书的证书模版名、证书序列号是什么?(格式为模版名-序列号,如CertTemplate-2f000000064287f6f5d6ff4a91000000000006) - 小梁的域控机器被黑客攻击了,请你找出一些蛛丝马迹。 攻击者在获取域管理员权限后,尝试上传木马文件,但是被杀毒软件查杀,上传的木马文件的绝对路径是什么?(如C:\Windows\cmd.exe) - 小梁的域控机器被黑客攻击了,请你找出一些蛛丝马迹。 攻击者从机器中提取出了用户的连接其他机器的Windows企业凭据,凭据的连接IP、用户名、密码是什么?(格式为IP-用户名-密码,如127.0.0.1-sam-123456) - 小梁的域控机器被黑客攻击了,请你找出一些蛛丝马迹。 攻击者创建了一个新用户组和一个新用户,并把这个用户加入了新用户组和域管理员组中,新用户组名、新用户的用户名、新用户的密码是什么?(用户组名和用户名均小写,格式为用户组名-用户名-密码 ,如admins-sam-123456)
AD 域中的子设备应急处理
比赛复盘 这次的复盘,我想先从做出来的题目开始。我们队总共做出来两道题,分别是 5G消息_TLS
和 DC-Forensics-2
[MISC] 5G消息_TLS
Bob窃取到一个文件,并通过5G消息的形式告诉了Alice,不料他们的通信被窃听了,拿到这个文件,努力去获取最终的答案吧
附件
题目提供了一个流量包,从中可以看到可以发现 SIP 流(消息发送的流)
查询每个 SIP 流,可以得到所有的 TLS 密钥如下
1 2 3 4 5 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
这里的解密过程参考了 @Lunatic 的 Misc-Network Traffic Analysis
刚好我们在赛前看到了这个大佬的 MISC Guide,认为他的经验能够帮助我们在比赛中完成题目,遂将他的 Blog 从 Github 下载了下来,使用 Python 的 http.server 本地浏览,没想到真的能够派上用场
在这里真的很感谢这位大佬,能够公开自己的静态网站的仓库,最后能被我们派上用场
把这个密钥丢到 wireshark 的 TLS 设置里面
为了确定是否正确,我上面是指定了一个 Debug File 的,打开这个文件,可以看到里面的提示
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 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 需要使用 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.py
workspace.zip
公告.txt
三个文件
公告的内容如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 各位员工: 为了提升公司的安全管理水平,从即日起,我司将引入AI技术对通行密码进行管理。相关的密码图片内容已整理并放入压缩包中,压缩包的密码将由各部门负责组织发放,请大家留意部门通知。 请注意公司内部AI模型的使用规范: 1.除最后一层外与池化层外其他隐藏层输出均需要通过激活函数 2.至少需要通过两次池化层 3.注意隐藏之间输出数据格式的匹配,必要时对数据张量进行重塑 4.为保证模型准确性,输入图片应转换为灰度图 感谢大家的配合与支持。如有疑问,请随时与人事部联系。 此致
从这个文本文件我们可以知道这个题是个 AI 题,要调用它提供的模型来进行图片的辨认
笑死了这个题,我们队里有人看出来了这是压缩包明文爆破,但是但是,我们没有一个人电脑里有 bkcrack……
ZIP 文件里的内容可以用一种叫 ZipCrypto 的加密方式保护,靠密码生成一串随机字节,跟文件内容“混在一起”变成加密后的数据。它的核心是个由三个数字组成的小机器,先用密码启动,然后边加密边更新。但这方法有个弱点:如果有人知道加密后的内容和至少 12 个字节的原文,就能破解这个小机器的内部状态。掌握了状态,就能解开所有用同一密码加密的内容,还能试着猜密码,难度大概是“字符种类数 × 密码长度 - 6”。简单说,就是不够安全,容易被攻破。
压缩包明文攻击的条件
攻击需要至少 12 个字节的已知明文。其中至少 8 个必须是连续的。连续的已知明文越大,攻击速度越快。
解开压缩包 这个题目已经给了我们 公告.txt
文件,并且压缩包内也有这个公告,满足且远远满足于我们的条件
使用这样的命令来 crack 我们的 zip
1 $ .\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
1 2 3 4 5 6 7 8 9 10 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 我们能够生成一个使用我们自己的密码加密过后的压缩包,也就是说生成的压缩包的密码是已知的
1 2 3 4 5 $ .\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.
这里的参数是这样的
1 2 3 -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 进行识别的
lutzroeder/netron: Visualizer for neural network, deep learning and machine learning models
可以看到这个模型里面的各个参数,与公告是能对应上的
这里抄了别人的调用代码 ,确实没学过怎么调用模型
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 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 import torchimport torch.nn as nnimport torch.nn.functional as Fimport numpy as npfrom PIL import Imagefrom torch.serialization import safe_globalsimport osclass 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() results.append({ 'image' : os.path.basename(img_path), 'prediction' : pred_class, 'confidence' : confidence }) print (f"图像 {os.path.basename(img_path)} 预测为: {pred_class} , 置信度: {confidence:.4 f} " ) except Exception as e: print (f"处理图像 {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()
所以 flag 大概应该是 81294687889085
但是队友后来提醒我,官方给了验证的脚本
1 2 3 4 5 6 7 8 import uuidimport hashlibflag = input () 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 改了一下上面搬的脚本
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 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 import torchimport torch.nn as nnimport torch.nn.functional as Fimport numpy as npfrom PIL import Imagefrom torch.serialization import safe_globalsimport osclass 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:.4 f} " ) print ("所有类别置信度:" ) for cls, conf in sorted (all_confidences.items(), key=lambda x: x[1 ], reverse=True ): print (f" 类别 {cls} : {conf:.4 f} " ) 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()
能够得到这样的数据
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 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 图像 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分别可能是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 candidates = [ [8 , 0 , 9 , 2 , 5 ], [1 , 7 , 4 , 8 ], [2 , 8 ], [9 , 3 , 5 , 8 ], [4 , 7 , 1 , 9 , 5 ], [6 , 5 , 8 , 4 ], [8 , 6 , 5 ], [7 , 8 , 1 , 9 , 0 , 2 ], [8 , 3 , 5 ], [8 , 9 ], [9 , 4 , 7 ], [0 , 8 , 6 , 3 ], [8 , 5 , 2 ], [5 ] ]
于是写了这样的一个爆破脚本(即这个位置可能是什么东西,列举出所有的可能进行爆破求解)
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 import uuidimport hashlibfrom itertools import productcandidates = [ [8 , 0 , 9 , 2 , 5 ], [1 , 7 , 4 , 8 ], [2 , 8 ], [9 , 3 , 5 , 8 ], [4 , 7 , 1 , 9 , 5 ], [6 , 5 , 8 , 4 ], [8 , 6 , 5 ], [7 , 8 , 1 , 9 , 0 , 2 ], [8 , 3 , 5 ], [8 , 9 ], [9 , 4 , 7 ], [0 , 8 , 6 , 3 ], [8 , 5 , 2 ], [5 ] ] def generate_combinations (): ordered_candidates = [] for pos in candidates: ordered_candidates.append(pos) return product(*ordered_candidates) 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)) 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 个的话我们能进决赛,等通知了