細(xì)說實現(xiàn):大模型是如何被投毒的

0 評論 2894 瀏覽 2 收藏 15 分鐘

這幾天字節(jié)的大模型事件鬧得沸沸揚(yáng)揚(yáng),一名實習(xí)生居然能給公司造成巨量的損失,不少人覺得不可思議。但從方法上來說,其實是可以達(dá)到的。這篇文章,作者就給我們分享了如何實現(xiàn)的辦法。

這兩天,字節(jié) GPU 投毒事件沸沸揚(yáng)揚(yáng):

和朋友們細(xì)聊了這個事兒,也在這里給大家盤一盤。

根據(jù)公開信息,推測一下可能的實現(xiàn)方法,或為三個方面:

  1. 惡意代碼執(zhí)行
  2. 擾亂模型訓(xùn)練
  3. 代碼隱藏與對抗

下面介紹每個唯維度可能攻擊的手法,以及如何進(jìn)行安全防護(hù)。

一、惡意代碼執(zhí)行

攻擊者通過精心設(shè)計的模型文件或數(shù)據(jù)集,利用底層庫的漏洞,引發(fā)遠(yuǎn)程代碼執(zhí)行(RCE),從而獲得控制權(quán)。在這種攻擊中,即便攻擊者沒有直接的集群 SSH 權(quán)限,也可以通過以下幾種方式悄無聲息地執(zhí)行惡意代碼。

1. 有關(guān) transformer

以 transformers 庫為例,已經(jīng)發(fā)現(xiàn)了多起相關(guān)的安全漏洞:

  • CVE-2024-3568:該漏洞影響 transformers 庫版本低于 4.38.0,主要利用 TFAutoModel 的反序列化過程觸發(fā)惡意代碼執(zhí)行。
  • CVE-2023-7018:影響版本低于 4.36.0 的 transformers 庫,tokenizer 解析存在類似的反序列化漏洞。
  • CVE-2023-6730:涉及 RagRetriever.from_pretrained 方法,影響版本同樣是低于 4.36.0。

這些漏洞的存在,意味著如果攻擊者能夠控制模型文件內(nèi)容,便可通過反序列化行為,在模型加載的瞬間就可以觸發(fā)惡意代碼執(zhí)行。

2. trust_remote_code:遠(yuǎn)程代碼執(zhí)行的“后門”

在 transformers 庫中,還有一個較為隱蔽的危險選項:trust_remote_code。這個參數(shù)允許從遠(yuǎn)程服務(wù)器加載代碼,并直接在本地執(zhí)行。它的初衷是為了方便開發(fā)者快速獲取并使用最新的模型和功能,但同時也給了攻擊者一個可乘之機(jī)。

當(dāng) trust_remote_code=True 時,攻擊者可以誘導(dǎo)用戶加載一個經(jīng)過篡改的模型,而這個模型會包含惡意代碼。一旦加載,惡意代碼將在本地執(zhí)行,可能導(dǎo)致系統(tǒng)被入侵、數(shù)據(jù)泄露,甚至模型訓(xùn)練過程被完全掌控。

目前大多數(shù)開源模型的官方教程都默認(rèn)開啟這個選項,如果倉庫權(quán)限被控制,后果不堪設(shè)想。

3. 惡意數(shù)據(jù)集

除了模型文件,攻擊者還可以通過偽造數(shù)據(jù)集來達(dá)到執(zhí)行惡意代碼的目的。

huggingface 的 datasets 庫是目前最流行的數(shù)據(jù)集加載工具之一,但該庫也存在一個潛在的安全風(fēng)險:如果下載的數(shù)據(jù)集中包含與數(shù)據(jù)集同名的 Python 腳本,datasets 庫在加載數(shù)據(jù)時會自動執(zhí)行該腳本。

換句話說,攻擊者可以通過嵌入惡意代碼在數(shù)據(jù)集中,來實現(xiàn)遠(yuǎn)程代碼執(zhí)行。

官方已明確指出,這一行為是 datasets 的“特性”而非漏洞,但這無疑給了攻擊者一個可利用的機(jī)會。

二、擾亂模型訓(xùn)練:隱蔽的“暗手”如何影響 AI 模型

在 GPU 模型投毒攻擊中,觸發(fā)惡意代碼執(zhí)行只是開始。更為隱蔽且難以察覺的是攻擊者通過精細(xì)化手段,直接干擾模型的訓(xùn)練過程。這不僅讓模型的最終效果變得不可預(yù)測,甚至可能導(dǎo)致模型朝著錯誤的方向訓(xùn)練,產(chǎn)生嚴(yán)重的商業(yè)后果。本文將揭示幾種常見的擾亂模型訓(xùn)練的方式,讓大家更加警惕這一隱秘的威脅。

1. 修改模型層輸出:讓模型“產(chǎn)生幻覺”

在深度學(xué)習(xí)模型的訓(xùn)練過程中,模型的每一層都會輸出中間結(jié)果,并依次傳遞到下一層。如果攻擊者在這些中間層的輸出上做手腳,模型的表現(xiàn)將會變得極為混亂。

一種常見的方式是向模型的某些層(例如 lm_head)加入鉤子函數(shù),疊加隨機(jī)數(shù)或噪聲。這種“微調(diào)”看起來不起眼,但由于大模型的自回歸特性,早期層的微小擾動會在模型后續(xù)的輸出中被逐漸放大,最終導(dǎo)致模型產(chǎn)生“幻覺”,生成錯誤甚至荒謬的結(jié)果。

示例:在輸出層添加鉤子

在沒有鉤子之前,模型可能會輸出正確的預(yù)測結(jié)果。然而,加入鉤子并疊加隨機(jī)噪聲后,輸出結(jié)果可能逐步偏離正常軌道:

經(jīng)過這樣的篡改,模型在訓(xùn)練過程中就會逐漸偏離正軌,生成大量錯誤的預(yù)測。特別是在超大規(guī)模自回歸模型中,這樣的擾亂會隨著生成過程不斷放大,最終導(dǎo)致整個訓(xùn)練數(shù)據(jù)無效。

加鉤子前輸出結(jié)果:

加鉤子后輸出結(jié)果:

2. 篡改優(yōu)化器

優(yōu)化器是模型訓(xùn)練的核心模塊,負(fù)責(zé)根據(jù)梯度更新模型參數(shù)。如果攻擊者能夠篡改優(yōu)化器的行為,模型的訓(xùn)練過程將變得極其不穩(wěn)定,甚至根本無法收斂。

攻擊者可以通過修改優(yōu)化器的 step 方法,加入延時或隨機(jī)清空梯度等操作,來偽造正常的訓(xùn)練狀態(tài)。例如,以下代碼通過簡單的延時操作拖慢了訓(xùn)練過程,這不僅會增加訓(xùn)練時間,還可能影響訓(xùn)練的整體效果:

更嚴(yán)重的是,攻擊者可以通過隨機(jī)化梯度或參數(shù),直接破壞模型的訓(xùn)練進(jìn)程。例如,清空優(yōu)化器的梯度或隨機(jī)篡改參數(shù)值,都會使模型訓(xùn)練陷入混亂,無法正常更新參數(shù)。

3. 篡改梯度方向

深度學(xué)習(xí)模型的訓(xùn)練過程依賴于梯度下降法,通過不斷調(diào)整參數(shù),使模型逐漸收斂到最優(yōu)解。而梯度的方向正是參數(shù)更新的“指南針”,如果這個“指南針”被篡改,模型就會朝著錯誤的方向前進(jìn),訓(xùn)練出的模型可能完全失效。

攻擊者可以通過修改梯度的方向來擾亂模型訓(xùn)練。例如,簡單地反轉(zhuǎn)梯度方向就可以讓模型的參數(shù)朝著與預(yù)期相反的方向更新,使得模型無法收斂,甚至訓(xùn)練出一個帶有后門的模型。

這種方式雖然隱蔽,但后果卻極其嚴(yán)重。模型不僅會訓(xùn)練出錯誤的結(jié)果,甚至可以被設(shè)計成帶有特定行為的“后門模型”,在特定條件下生成攻擊者預(yù)期的輸出。

三、代碼隱藏與對抗

在 GPU 模型投毒的攻擊鏈條中,代碼隱藏與對抗是攻擊者最隱蔽、最難防范的環(huán)節(jié)。通過巧妙地隱藏惡意代碼,攻擊者可以長時間不被察覺,持續(xù)影響模型訓(xùn)練,甚至在面對內(nèi)部調(diào)查時,依然能夠“全身而退”。本章將揭示攻擊者是如何通過篡改庫文件、動態(tài)加載代碼等手法,隱蔽地進(jìn)行攻擊,以及如何對抗這些潛在威脅。

1. 篡改 site-packages 目錄:持久化“幽靈攻擊”

在 Python 環(huán)境下,site-packages 目錄存放著項目依賴的第三方庫(如 transformers、torch 等)。攻擊者可以通過篡改這些常用庫的代碼,將惡意代碼嵌入其中,達(dá)到持久化攻擊的目的。

由于這些庫被頻繁調(diào)用,攻擊者可以在庫的初始化代碼或關(guān)鍵函數(shù)(如模型加載、優(yōu)化器更新、梯度計算等)中加入惡意代碼,每次庫被加載時,惡意代碼都會悄無聲息地執(zhí)行。這種方式不僅能保證攻擊的持續(xù)性,還十分隱蔽,因為開發(fā)者或運(yùn)維人員通常不會頻繁審查這些已安裝的庫文件。

示例:篡改初始化代碼

攻擊者可以在庫的初始化代碼中插入惡意操作,并偽裝成正常的加載過程,難以被察覺。比如,以下代碼展示了如何在庫加載時執(zhí)行惡意代碼:

這種篡改方式非常隱蔽,因為 site-packages 目錄下的文件往往不在日常的代碼審查范圍內(nèi),攻擊者可以“潛伏”在系統(tǒng)中,悄悄執(zhí)行惡意操作。

2. Python 運(yùn)行時動態(tài)加載:無痕跡篡改核心函數(shù)

除了直接篡改 Python 庫文件,攻擊者還可以通過動態(tài)加載的方式,修改模型訓(xùn)練中的關(guān)鍵函數(shù)(如 backward()、step()等),以便在不修改顯著代碼的情況下,悄悄改變模型的訓(xùn)練行為。

這種方法利用 Python 語言的動態(tài)特性,攻擊者可以在訓(xùn)練框架初始化之前,提前注入代碼,改變函數(shù)的返回值或行為。例如,攻擊者可以修改 backward()函數(shù),使得梯度計算出現(xiàn)偏差,或修改 step()函數(shù),干擾優(yōu)化器的正常更新。

示例:動態(tài)修改函數(shù)行為

以下代碼展示了如何通過動態(tài)加載篡改模型的關(guān)鍵函數(shù):

通過這種動態(tài)篡改,攻擊者可以在不直接修改代碼文件的情況下,影響模型的訓(xùn)練過程。這種方式尤為隱蔽,開發(fā)者可能在調(diào)試時發(fā)現(xiàn)不了任何異常。

3. 對抗內(nèi)部調(diào)查

為了進(jìn)一步隱藏惡意行為,攻擊者往往會為惡意代碼設(shè)置特定的觸發(fā)條件,只有在特定情況下才會執(zhí)行。例如,攻擊者可以設(shè)置只有當(dāng)任務(wù)使用 256 張 GPU 時,惡意代碼才會被觸發(fā),這使得日常的小規(guī)模訓(xùn)練任務(wù)不會檢測到任何異常。

此外,攻擊者可能會利用內(nèi)部的調(diào)試工具或渠道,悄悄修改代碼并隨時調(diào)整攻擊策略。比如,通過內(nèi)部的 debug 群組,攻擊者可以實時監(jiān)控訓(xùn)練任務(wù)的進(jìn)展,隨時修改惡意代碼或增加新的觸發(fā)條件。這大大增加了內(nèi)部調(diào)查的難度。

示例:設(shè)置觸發(fā)條件

攻擊者可以通過簡單的條件判斷,控制惡意代碼的觸發(fā)時機(jī):

這種方式讓惡意代碼在大多數(shù)情況下處于“休眠”狀態(tài),只有在特定條件滿足時才會執(zhí)行,進(jìn)一步增加了調(diào)查和排查的難度。最后

最后預(yù)測一下某字節(jié)的攻擊手法:推測是基于其公司內(nèi)部 AI 訓(xùn)練平臺正常員工權(quán)限,利用訓(xùn)練組件漏洞執(zhí)行了惡意代碼,并進(jìn)一步篡改模型輸出、優(yōu)化器與修改梯度方向?qū)崿F(xiàn)來擾亂 GPU 集群中的模型訓(xùn)練結(jié)果,同時由于該內(nèi)鬼員工還進(jìn)行了隱藏與持續(xù)修改代碼等對抗操作,導(dǎo)致了其公司在較長時間后才調(diào)查清楚。

本文由人人都是產(chǎn)品經(jīng)理作者【賽博禪心】,微信公眾號:【賽博禪心】,原創(chuàng)/授權(quán) 發(fā)布于人人都是產(chǎn)品經(jīng)理,未經(jīng)許可,禁止轉(zhuǎn)載。

題圖來自Unsplash,基于 CC0 協(xié)議。

更多精彩內(nèi)容,請關(guān)注人人都是產(chǎn)品經(jīng)理微信公眾號或下載App
評論
評論請登錄
  1. 目前還沒評論,等你發(fā)揮!