1. 从.pth文件到CTF Flag:一次PyTorch模型权重的逆向实战
最近在参加CTF比赛时,遇到了一道很有意思的Misc题目,题目给了一个PyTorch的模型权重文件(.pth),要求从中找出隐藏的flag。作为一个AI和安全双重爱好者,我觉得这个题目特别有意思,因为它把AI模型和安全攻防结合在了一起。今天我就来分享一下我是如何从.pth文件中逆向出flag的完整过程。
.pth文件是PyTorch模型的标准权重文件格式,通常包含了模型的参数和状态。在正常的AI开发流程中,我们会用它来保存和加载训练好的模型。但在CTF比赛中,出题人往往会利用这种常见文件格式来隐藏一些特殊的信息。这道题目就是一个很好的例子。
2. 准备工作:理解.pth文件的结构
2.1 PyTorch模型权重文件基础
在开始解题之前,我们需要先了解一下.pth文件的基本结构。PyTorch提供了两种保存模型的方式:
第一种是保存整个模型:
torch.save(model, 'model.pth')第二种是只保存模型的state_dict(推荐方式):
torch.save(model.state_dict(), 'model.pth')在CTF题目中,出题人可能会利用这些保存机制,在文件中隐藏额外的信息。比如在保存state_dict时,可以添加自定义的键值对。
2.2 检查文件内容
拿到题目文件后,我首先尝试直接加载这个.pth文件:
import torch data = torch.load('easy.pth') print(type(data))这一步很关键,因为它能告诉我们文件里保存的是什么类型的数据。如果是整个模型,输出会是模型类;如果是state_dict,输出会是OrderedDict;如果出题人做了特殊处理,可能是其他类型。
3. 逆向分析.pth文件
3.1 查看文件中的键值
当我运行上面的代码后,发现输出是一个字典类型。于是我开始检查这个字典包含哪些键:
print(data.keys())输出显示除了常见的模型参数键外,还有两个特别的键:'hint'和'flag'。这明显是出题人故意留下的线索。
3.2 提取隐藏信息
接下来,我尝试提取这两个特殊键对应的值:
hint = data['hint'] flag = data['flag'] print(hint) print(flag)输出是两个张量(tensor)。第一个张量看起来像是一串字符,第二个张量则像是加密后的数据。
3.3 解码张量数据
由于张量中的数据是以数值形式存储的,我们需要将其转换为可读的字符串:
hint_str = ''.join([chr(int(i)) for i in hint.tolist()]) flag_str = ''.join([chr(int(i)) for i in flag.tolist()]) print(hint_str) print(flag_str)解码后,hint_str显示为"ZzYyXxAaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWw0123456789+/",这明显是一个自定义的base64编码表。而flag_str则是一串看似随机的字符。
4. 破解加密的flag
4.1 理解加密方式
根据hint提供的信息,我猜测flag是使用自定义base64表编码的。标准的base64编码表是"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",而这里出题人使用了打乱顺序的编码表。
4.2 实现自定义base64解码
为了解码flag,我需要实现一个使用自定义编码表的base64解码器:
import base64 custom_b64table = "ZzYyXxAaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWw0123456789+/" standard_b64table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" encoded_flag = "LidUJ3fQM2FVJoxpDwLvDyF3DwpPdwxOEgbQJoxnEgdnJgnojoZ5mF" # 创建转换表 trans = str.maketrans(custom_b64table, standard_b64table) # 转换编码表 standard_encoded = encoded_flag.translate(trans) # 解码 decoded_flag = base64.b64decode(standard_encoded).decode('utf-8') print(decoded_flag)运行这段代码后,成功输出了隐藏的flag。这个过程展示了如何利用PyTorch模型文件的特性来隐藏信息,以及如何通过逆向分析提取这些信息。
5. 深入分析:为什么这种方法有效
5.1 PyTorch序列化机制
PyTorch使用Python的pickle模块来序列化模型数据。pickle是一个非常灵活的序列化工具,可以保存几乎任何Python对象。这种灵活性使得我们可以在模型文件中存储额外的数据。
5.2 安全注意事项
虽然这种方法在CTF比赛中很有趣,但在实际项目中需要注意:
- 不要加载来源不明的.pth文件,因为它们可能包含恶意代码
- 在生产环境中,应该验证模型文件的完整性和来源
- 考虑使用更安全的序列化方法,如ONNX格式
6. 扩展思考:其他可能的隐藏方式
除了在state_dict中添加额外键值对外,出题人还可能使用其他方法隐藏信息:
- 将信息隐藏在模型参数中(如卷积核权重)
- 使用模型的特定参数值作为加密密钥
- 在模型结构中嵌入信息(如特定层的配置)
7. 防御措施:如何保护模型安全
作为AI开发者,我们也应该思考如何防止他人从我们的模型文件中提取敏感信息:
- 使用模型加密技术
- 对模型进行混淆处理
- 避免在模型文件中存储敏感信息
- 使用专门的模型保护工具
这次逆向实战让我对PyTorch模型文件有了更深的理解,也让我意识到AI模型安全的重要性。在CTF比赛中,这类题目很好地结合了AI和安全两个领域,既考验了对AI技术的理解,也考验了逆向分析能力。