Google Agent首次發現真實世界程式碼漏洞或挽回數十億美元損失?
LLM居然在真實世界的程式碼中,發現了一個漏洞?想像一下,AI正在默默地守護著我們日常使用的軟體。忽然,它發現了一個你我可能從未察覺的安全隱患,並且悄無聲息地把它修復了!就在剛剛,Google的Big Sleep專案揭示了一個驚人的成果:一個真實世界的安全漏洞,出現在全球廣泛使用的SQLite資料庫中,而這個漏洞竟然被AI成功辨識出來了?在真實世界的危機擴散之前,它及時挽回了局面。
隸屬於GoogleProject Zero和Google DeepMind的團隊聲稱,這是AI Agent在廣泛使用的現實軟體中,發現未知可利用記憶體安全問題的第一個公開範例。
要知道,這不僅僅是一個崩潰的測試案例,它是AI首次在真實世界的軟體中找到未知的、可利用的記憶體漏洞。
先前,網路安全巨頭CrowdStrike鬧出的一個由「C-00000291*.sys」設定檔觸發的系統邏輯錯誤,瞬間破壞掉全世界約10億台計算機,直接導致微軟藍屏、全球停擺。
如果未來某一天,AI能幫我們解決所有科技領域的單點瞬時故障,不知會幫人類省下多少財富?
用LLM在真實世界中“捉蟲”
隨著LLM程式碼理解和一般推理能力的提高,Google研究者一直在探索這些模型如何在識別和演示安全漏洞時,重新人類安全研究人員的方法。
在《Project Naptime:評估大型語言模型的攻防能力》中,Big Sleep團隊介紹了一個利用LLM輔助的漏洞研究框架,並透過在Meta的CyberSecEval2基準測試上提升了最新的性能,展示了這種方法的潛力。
從那時起,Naptime變成“Big Sleep”,成為了Google Project Zero與Google DeepMind的合作計畫。
就在剛剛,Google研究者興奮地表示,Big Sleep Agent發現了首個真實世界漏洞:存在於SQLite中的可利用堆疊緩衝區下溢漏洞。
SQLite是一款廣為使用的開源資料庫引擎。
在十月初,Agent發現了這個漏洞,於是Google研究者立刻將其報告給了開發者,他們在同一天進行了修復。
幸運的是,AI在這個問題出現在官方發布版本之前,就發現了它,因此SQLite的用戶不受影響。
要知道,SQLite作為輕量級嵌入式資料庫,廣泛應用於智慧型手機、瀏覽器、嵌入式系統、IoT設備等多種環境,涵蓋了許多使用者和敏感資訊。
如果攻擊者利用漏洞進行資料外洩、系統入侵或破壞,潛在損失金額可能少則數百萬,多則數十億美元!
Google研究者表示,這是AI Agent首次在廣泛使用的真實世界軟體中發現未知的、可利用的記憶體安全問題的公開案例。
之所以會有這次嘗試,是因為今年早些時候,在DARPA的AIxCC活動中,亞特蘭大團隊在SQLite中發現了一個空指針取消引用的漏洞,這給了Google研究者啟發——
是否可以使用SQLite進行測試,看看能否找到更嚴重的漏洞?
果然,AI Agent真的找出了一個漏洞。
這項工作,無疑具有巨大的潛力。
在軟體尚未發布前就發現漏洞,就意味著攻擊者沒有機會利用:漏洞在他們有機會使用之前,就已修復。
虽然模糊测试也能带来显著的帮助,但我们更需要的是一种方法,帮助防御者找到那些很难通过模糊测试发现的漏洞。
現在,AI有望縮小這一差距!
Google研究者表示,這是一條有希望的道路,能為防禦者帶來不對稱的優勢。
因為這個漏洞相當有趣,而且SQLite的現有測試基礎設施(包括OSS-Fuzz和專案本身的測試)並沒有發現它,因此Google研究者進行了深入調查。
方法架構
Naptime和Big Sleep專案的關鍵驅動因素,就是已經發現並修補的漏洞變種,在現實中仍在不斷被發現。
顯而易見,fuzzing(模糊測試)並不能成功捕捉此類變種漏洞,而對攻擊者而言,手動變種分析的方法仍然性價比很高。
Google研究者認為,相較於廣泛的開放式漏洞研究問題,這種變種分析任務更適合目前的LLM。
透過提供一個具體的起點——例如先前修復的漏洞的詳細資訊——我們就可以降低漏洞研究中的不確定性, 並且還能從一個明確的、有理論支撐的假設出發:「這裡曾經存在一個漏洞,很可能在某處還存在類似的問題」。
目前,他們的專案仍處於研究階段,正在使用已知漏洞的小型程式來評估研究進展。
最近,他們決定透過在SQLite上進行首次大規模的真實環境變種分析實驗,來測試他們的模型和工具鏈。
他們收集了SQLite repository近期的一系列提交,手動篩除了無關緊要的改動和純文件更新。
隨後,他們調整了prompt,為AI Agent同時提供了提交資訊和程式碼變更,並要求它審查當前程式碼庫(在HEAD位置)中可能仍未修復的相關問題。
午睡計劃
Naptime採用了一種專門的架構來增強大語言模型進行漏洞研究的能力,其核心是AI Agent與目標程式碼庫之間的交互作用。
系統架構
為了讓AI Agent可以模仿人類安全研究員的工作流程,研究團隊發展了一系列專用的工具:
程式碼瀏覽工具(Code Browser)使AI Agent能夠瀏覽目標程式碼庫,這與工程師使用Chromium Code Search的方式類似。它提供了查看特定實體(如函數、變數等)原始程式碼的功能,並能識別函數或實體被引用的位置。
Python工具讓AI Agent能夠在隔離的沙盒(Sandbox)環境中執行Python腳本,用於執行中間計算並產生精確而複雜的目標程式輸入。
調試器工具(Debugger)為AI Agent提供了程式互動能力,可以觀察程式在不同輸入下的行為表現。它支援斷點設定並能在斷點處評估表達式,從而實現動態分析。
報告工具(Reporter)為AI Agent提供了一個結構化的進度通報機制。 AI Agent可以發送任務完成訊號,觸發控制器驗證是否達成成功條件(通常表現為程式崩潰)。當無法取得進一步進展時,它還允許AI Agent主動中止任務,避免陷入停滯狀態。
發現漏洞
這個漏洞非常有趣,例如在一個通常為索引類型的欄位iColumn中,使用了一個特殊的哨兵值-1:
7476: struct sqlite3_index_constraint {
7477: int iColumn; /* Column constrained. -1 for ROWID */
7478: unsigned char op; /* Constraint operator */
7479: unsigned char usable; /* True if this constraint is usable */
7480: int iTermOffset; /* Used internally - xBestIndex should ignore */
7481: } *aConstraint; /* Table of WHERE clause constraints */
這種模式產生了一個邊緣案例,所有使用該欄位的程式碼都需要正確處理這種情況,因為按照常規預期,有效的列索引值應該是非負的。
seriesBestIndex函數在處理這個edge case時有缺陷,當處理包含rowid列約束的查詢時,導致寫入了一個帶有負索引的堆疊緩衝區。
在研究者提供給AI Agent的編譯版本中,debug assertion功能已啟用,這種異常情況會被第706行的斷言檢查所捕獲:
619 static int seriesBestIndex(
620 sqlite3_vtab *pVTab,
621 sqlite3_index_info *pIdxInfo
622 ){
...
630 int aIdx[7]; /* Constraints on start, stop, step, LIMIT, OFFSET,
631 ** and value. aIdx[5] covers value=, value>=, and
632 ** value>, aIdx[6] covers value<= and value< */
633 const struct sqlite3_index_constraint *pConstraint;
...
642 for(i=0; inConstraint; i++, pConstraint++){
643 int iCol; /* 0 for start, 1 for stop, 2 for step */
644 int iMask; /* bitmask for those column */
645 int op = pConstraint->op;
...
705 iCol = pConstraint->iColumn - SERIES_COLUMN_START;
706 assert( iCol>=0 && iCol<=2 );
707 iMask = 1 << iCol;
...
713 if( pConstraint->usable==0 ){
714 unusableMask |= iMask;
715 continue;
716 }else if( op==SQLITE_INDEX_CONSTRAINT_EQ ){
717 idxNum |= iMask;
718 aIdx[iCol] = i;
719 }
720 }
然而,在發布版本中,這個斷言檢查並不存在。
在研究者的測試環境中(具體表現會因編譯器和最佳化等級而異),第718行的後續寫入操作會越界寫入aIdx緩衝區下方的記憶體區域,導致pConstraint指標的最低有效32位元被破壞。
當這個被破壞的指標在循環的下一個迭代中被取消引用時,就會產生潛在的可利用漏洞條件。
不過,即使有了這樣的漏洞說明,對於人類研究員來說,要精確地理解如何觸發這個漏洞仍然不易。
雖然針對ROWID欄位設定約束顯然是個不錯的切入點,但要完全理解,還需要深入研讀程式碼。
而AI 智能體似乎已經掌握了比人類研究員更多的SQLite相關知識,這使它能夠更有效率地定位問題!
這種情況的典型例子,就是LLM在產生測試案例時會直接使用generate_series虛擬表。
(雖然研究者也觀察到模型會先研究可用的虛擬表的情況,但很明顯,它能夠在這裡直接運用已有的知識)。
執行過程重點分析
在這次基於Gemini 1.5 Pro的成功測試中,seed commit為[1976c3f7],這是一個規模較大、複雜的程式碼變更。
而研究者的AI Agent發現的漏洞,與該seed commit中的變更僅存在鬆散關聯——這種情況在手動變種分析中較為常見,因為在理解程式碼庫中的某個漏洞時,研究人員往往會由此發現其他潛在問題。
以下是關鍵節點摘要,其中,所有ASSISTANT區塊中的內容均直接來自AI Agent。
AI Agent對差異中的變化進行了合理的評估,並以此作為研究的切入點:
助理
透過引入termFromWhereClause函數,CL改進了在虛擬表查詢中處理OR分支共享的WHERE條件的方式。此函數在考慮巢狀子句的情況下,從WhereClause中檢索特定的條件。
在此變更之前,由於條件索引映射不正確,共享的條件可能未被正確處理,可能導致低效的查詢計劃或錯誤的結果。
最可能出現的問題涉及在allocateIndexInfo和whereLoopAddVirtualOne函數中不正確地處理WHERE子句約束,其中CL 修改瞭如何使用新的輔助函數來處理約束偏移量。
我將首先檢查allocateIndexInfo函數。
在經過數個步驟探索相關程式碼後,AI Agent形成了一個更明確的測試假設——它試圖透過執行patch中測試案例的修改版本來驗證這個假設,但未能成功。
原因在於patch中的測試案例依賴一個在目前配置環境中未啟用的擴充模組:
工具(debugger_run)
程式在未崩潰或命中斷點的情況下退出。退出代碼為1。
STDERR輸出為:
第 2 行附近的運行時錯誤:沒有這樣的模組:tcl
第 3 行附近解析錯誤:沒有這樣的表:x1
助理
程式終止是因為TCL模組不可用。測試依賴TCL虛擬表模組,需要在編譯SQLite時啟用此模組。提供的程式的輸入是基於bestindexC.test文件,它使用TCL模組來測試虛擬表的最佳索引選擇。
為了解決這個問題,需要更改程式輸入,使用不需要TCL模組的其他虛擬表。然而,該漏洞與虛擬表的查詢計劃有關,所以我們仍然需要一個虛擬表來觸發此問題。
我將使用code_browser_source工具來檢索SQLite中的內建虛擬表示例。然後,我將調整輸入,使用其中一個虛擬表,並重新在whereLoopAddVirtualOne中設定斷點。
AI Agent很好地應對了這個問題,準確識別出了修復測試用例所需的各個步驟,並在後續幾個步驟中成功收集到了所有構建測試用例所需的信息,最終實現了觸達whereLoopAddVirtualOne的目標:
助理
sqlite3_create_module函數用於註冊虛擬表模組。 shell.c檔案包含了多個這樣的實例,包括generate_series、fsdir、completion和expert模組。其中json表的實作也很值得關注。
我首先關注的是generate_series,然後建構出一個使用該模組的查詢,從而觸發錯誤的約束處理。
需要注意的是,在最初發現和復現該漏洞時,AI Agent對於它試圖觸發的「不正確約束處理」的描述相當模糊。
在這種情況下,完整的執行軌跡讀起來頗似人類研究員的思考過程——從一個想法開始,在調查過程中產生其他幾個想法,最終產生了一個可以復現略有不同漏洞的測試案例。
在本例中,當whereLoopAddVirtualOne在generate_series表上被呼叫時,執行流程最終會進入seriesBestIndex,在那裡約束確實被錯誤處理了。
特別有趣的是,一旦程式崩潰,模型會在解釋問題時表現得更為出色——在生成根因分析(root-cause analysis)和完整崩潰報告時,我們可以看到AI Agent清晰地構造了一個測試用例來觸發特定的已識別邊緣案例:
助理
相關的欄位是sqlite3_index_constraint結構體中的iColumn。此欄位表示約束的列編號。要導致斷言失敗,我們需要對索引大於3或小於-1的列設定約束。
讓我們建立一個涉及這些列約束的SQL查詢。 generate_series表有名為value、start、step和stop的欄位。它們的索引是:
– 值:0
– 開始:1
– 步驟:2
– 停止:3
要觸發此漏洞,我們可以對ROWID施加一個約束,並對ROWID的約束使用iColumn = -1。
範例查詢如下:
SELECT * FROMgenerate_series(1,10,1) WHERE ROWID = 1;
該查詢將導致seriesBestIndex函數崩潰。
最終,得到了一個清晰準確的問題總結,幾乎可以直接用於漏洞報告!
工具(調試器_運行)
程式崩潰:SIGABRT at :0
STDERR輸出為:
sqlite3: src/shell.c:6816: int seriesBestIndex(sqlite3_vtab *, sqlite3_index_info *): 斷言 `iCol>=0 && iCol<=2′ 失敗。
助理(報告成功)
程式在執行SELECT * FROM generate_series(1,10,1) WHERE ROWID = 1;時因seriesBestIndex函數中的斷言失敗而崩潰。
斷言assert(iCol>=0 && iCol<=2)失敗的原因是sqlite3_index_info結構體中的iColumn欄位可能包含超出列索引有效範圍的值,例如在約束涉及ROWID時為-1。
這導致iCol被計算為-2,從而導致斷言失敗。
關於模糊測試
一個顯而易見的問題是:為什麼傳統的模糊測試沒有更早發現這個漏洞?
答案就在模糊測試工具鏈的配置上。
OSS-Fuzz所使用的工具並沒有啟用generate_series擴展,而替代的fuzzingshell.c工具包含的是舊版的seriesBestIndex函數,未受此漏洞影響。
雖然SQLite AFL倉庫中包含一個針對研究者提供給Big Sleep智能體的、相同CLI二進位檔案的模糊測試配置,但似乎並未被廣泛使用。
這個漏洞是否真的容易發現?
為此,研究者嘗試透過模糊測試重新發現它。
他們遵循SQLite文件中的模糊測試說明,並使用CLI目標。在啟動AFL運行之前,他們還驗證了模糊測試語料庫中包含所需的generate_series和rowid關鍵字。
然而,經過150個CPU小時的模糊測試,問題仍未被發現。
隨後,他們嘗試透過將必要的關鍵字加入AFL的SQL字典中,來簡化模糊測試的任務。
然而,似乎只有當語料庫包含與導致崩潰的輸入非常接近的範例時,漏洞才能被快速發現,因為程式碼覆蓋率對這個特定問題並不是可靠的指標。
誠然,AFL並不是針對像SQL這種基於文字的格式最適合的工具,大多數輸入在語法上無效,會被解析器拒絕。
然而,如果將此結果與Michal Zalewski在2015年關於模糊測試SQLite的部落格文章進行比較,會發現十分有趣的事。
那時,AFL在發現SQLite漏洞方面相當有效;經過多年的模糊測試,該工具似乎已經達到自然的飽和點。
虽然研究者迄今为止的结果与AFL发布时带来的显著效果相比显得微不足道,但它有自己的优势——有概率能够有效地发现一组不同的漏洞。
結論
對團隊來說,這個專案無疑成功了。
在廣泛使用且模糊化的開源專案中找到漏洞,非常一個令人興奮!
這也意味著:當提供正確的工具時,目前的LLMs可以進行漏洞研究。
不過,研究者想重申,這些都是高度實驗性的結果。
Big Sleep 團隊表示:目前,在發現漏洞方面,針對特定目標的模糊器可能至少同樣有效。
研究者希望,未来这项工作将为防御者带来显著优势——
不僅有可能找到導致崩潰的測試案例,還能提供高品質的根本原因分析,使得問題的分類和修復變得更便宜且更有效。
Google研究者表示,會持續分享自己的研究成果,盡可能縮小公共技術前沿和私有技術前沿之間的差距。
Big Sleep團隊也會將繼續努力,推動零日計畫的使命,讓0-day變得更加困難。
團隊介紹
Dan Zheng
團隊中唯一的華人Dan Zheng是GoogleDeepMind的研究工程師,從事程式碼和軟體工程的機器學習,以及程式語言的研究。
此前,他曾參與Swift for TensorFlow的工作,並專注於Swift中的可微分編程。
他在普渡大學獲得了電腦科學專業的學士學位。畢業後,他當了多年的學生研究員,期間研究成果豐富。
來源:申次元