之前我們發現了一個Aptos Move VM的嚴重漏洞,經過深入研究,我們發現了另外一個新的整數溢出漏洞,這次一的漏洞觸發過程相對更有趣一點, 下面是對這個漏洞的深入分析過程,里面包含了很多Move語言本身的背景知識.通過本文講解相信你會對move語言有更深入的理解。
眾所周知,Move 語言在執行字節碼之前會驗證代碼單元。驗證代碼單元的過程,分為4步。這個漏洞就出現在 reference_safety 的步驟中。
如上面代碼所示, 此模塊定義了用于驗證過程主體的引用安全性的轉移函數。其檢查包括(但不限于)驗證沒有懸空引用、對可變引用的訪問是否安全、對全局存儲引用的訪問是否安全。
下面是引用安全驗證入口函數, 它將調用analyze_function.
在analyze_function中,函數將對每一個基本塊進行驗證,那么什么是基本塊呢?
在代碼編譯領域,基本塊是一個代碼序列,除了入口之外沒有分支指令,除了出口之外沒有分支指令。
在Move 語言中, 基本塊是通過遍歷字節碼、查找所有分支指令以及循環指令序列來確定的。以下是核心代碼:
區塊鏈證書驗證平臺TheRollNumber完成16.5萬美元種子輪融資:金色財經報道,區塊鏈證書驗證平臺TheRollNumber 宣布完成 16.5 萬美元種子輪融資,Inflection Point Ventures 領投,該公司旨在為個人提供基于區塊鏈的證書管理系統,該系統不僅可以實現證書數字化和驗證,還可以讓用戶或個人知道在什么時間、什么人、以及如何使用憑證,繼而解決身份和憑證盜竊問題。(financialexpress )[2023/2/9 11:57:36]
接下來,我們來分享一個move ir代碼基本塊的例子, 如下所示, 它 3 個基本塊。分別由分支指令:BrTrue,Branch,Ret確定。
參考Rust語言的思想,Move 支持兩種類型的引用類型。不可變引用&(例如&T)和可變引用&mut(例如&mut T)。你可以使用不可變 (&) 引用從結構中讀取數據,使用可變 (&mut)引用 修改它們。通過使用恰當的引用類型,有助于維護安全性以及識別讀取模塊。這樣可以讓讀者清晰地知道此方法是更改值還是僅讀取。 下面是官方Move教程中的示例:
Numida宣布完成1230萬美元A輪融資:金色財經報道,烏干達金融科技公司Numida通過A輪前股權債務完成1230萬美元融資,Numida計劃該筆融資將數字借貸業務拓展到國外,這輪融資由美國網球明星小威廉姆斯的風險投資公司 Serena Ventures 領投。Breega、4Di Capital、Launch Africa、Soma Capital 和 Y Combinator 也參與了這一輪融資。[2022/10/2 18:37:37]
在示例中,我們可以看到mut_ref_t是 t 的可變引用。
所以在Move 引用安全模塊中,嘗試通過以函數為單元,掃描函數中的基本塊中的字節碼指令驗證判斷所有引用操作是否合法。
下圖顯示了驗證引用安全性的主要流程。
這里的state是AbstractState結構體, 它包含了borrow graph 和locals ,他們共同用于確保引用函數中的引用安全性。
這里borrow graph是用來表示局部變量引用之間關系的圖。
從上圖中可以看到, 這里有一個pre state ,其包含locals 和borrow graph (L ,BG)。然后執行了basic block 生成一個post state (L’, BG’)。然后將前后的state合并以更新塊狀態并將該塊的后置條件傳播到后續塊。這就像 V8 turbofan中的Sea of Nodes 思想。
華為云與Numen Cyber Technology簽署MoU,推動亞太地區Web3發展:金色財經報道,華為旗下云服務品牌華為云(HUAWEI Cloud)宣布與新加坡Web3安全公司Numen Cyber Technology簽署諒解備忘錄(MoU),雙方展開全面戰略合作,共同推動以新加坡為中心的亞太地區Web3市場蓬勃發展,共同構建安全的Web3生態系統,覆蓋各類 Web3 應用場景的網絡安全需求,以及智能合約、公鏈、錢包、交易所平臺、服務和產品的安全審計。(prnasia)[2022/9/22 7:13:56]
下面的代碼是上圖對應的主循環。首先, 執行塊代碼(如果執行指令不成功,將返回 AnalysisError)然后嘗試通過join_result是否更改,來合并pre state和post state。如果更改并且當前塊本身包含一個后向的邊指向自己(這意味著有一個循環)將跳回到循環的開頭, 在下一輪循環仍將執行此基本塊,直到post state等于pre state或因某些錯誤而中止。
因此在引用安全模塊,如何判斷 join的結果是否改變?
通過上面的代碼,我們可以通過判斷locals和borrow關系是否發生變化來判斷join結果是否發生變化。 這里的 join_ 函數用于更新本地變量和 borrow關系圖 。
瑞士加密銀行Sygnum正推出基于穩定幣DCHF的收益產品:3月16日消息,瑞士加密銀行Sygnum正在推出基于其自己的穩定幣DCHF的收益產品,這種三個月的定期存款產品每年將產生0.75%的收益率。DCHF存款1:1錨定瑞士法郎。該產品的推出是為了滿足以瑞士法郎計價的產生收益的貨幣市場產品的需求。(CoinDesk)[2021/3/16 18:50:12]
下面是join_ 函數代碼,第 6 行是初始化一個新的 locals Map 對象。 第 9 行迭代 locals 中的所有索引,如果pre state與 post state都值為 None,則不要插入到新的 locals 映射中,如果 pre state 有值,post state為None,則需要釋放 brow_graph id ,意味著這里消除該值的借用關系, 反之亦然。特別的,當pre state與 post state 兩個值都存在且相同時,像第30-33行一樣將它們插入到新的map中,然后在第38行合并 borrow graph。
通過上面代碼,我們可以看到 self.iter_locals() 是locals變量的個數。 請注意,此局部變量不僅包括函數的真實局部變量,還包括參數。
在這里我們已經覆蓋了所有與漏洞相關的代碼,你找到漏洞了嗎?
如果你沒有發現漏洞也沒關系,下面我會詳細說明漏洞觸發過程。
首先在下面的代碼中,如果參數長度添加局部長度大于 256。這似乎沒有問題?
動態 | Numerai 公司從Paradigm籌集了1100萬美元的融資:據coindesk消息,對沖基金和預測市場初創公司Numerai在3月份剛剛結束了一輪1100萬美元的融資,融資方是Paradigm和Placeholder,主要銷售NMR令牌。該公司于2017年通過空投首次推出NMR令牌。[2019/3/21]
當函數 join_() 中是 function_view.parameters().len() 和 function_view.locals().len() 組合值大于 256,由于語句 for local in self.iter_locals()中 local 是 u8類型,此時執行此語句對造成溢出。
開發者似乎只檢查了 Move Modules代碼中的 locals+parameter 長度,而忽略了script。
通過上面的介紹,我們知道有一個主循環來掃描代碼塊,然后調用execute_block函數,之后會合并執行前后的state,當move代碼中存在循環,則會跳轉到代碼塊開始,再次執行基本塊。 因此,如果我們制造一個循環代碼塊并利用溢出改變塊的state,使 AbstractState 對象中的新的locals map與之前不同,當再次執行 execute_block 函數時,在分析basic block中字節碼指令序列的時候會訪問新的locals map,這時候如果指令中需要訪問的索引在新的AbstractState locals map中不存在,將導致DoS。
在審核代碼后,我發現在 reference safety模塊中,MoveLoc/CopyLoc/FreeRef 操作碼,我們可以實現這個目標。
這里讓我們看一下文件路徑中execute_block函數調用的copy_loc函數作為一個說明:
move/language/move-bytecode-verifier/src/reference_safety/abstract_state.rs
在第287行,代碼嘗試通過LocalIndex作為參數獲取本地值,如果LocalIndex不存在會導致panic,想象一下當節點執行滿足上述條件代碼的時候,會導致整個節點崩潰。
下面是你可以在git里面重現的PoC:
commit:add615b64390ea36e377e2a575f8cb91c9466844
thread 'regression_tests::reference_analysis::PoC' panicked at 'called `Option::unwrap()` on a `None` value', language/move-bytecode-verifier/src/reference_safety/abstract_state.rs:287:39 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
我們可以看到PoC中代碼塊存在一個basic block,分支指令是一個無條件分支指令,每次執行最后一條指令時,branch(0) 將跳回第一條指令,因此這個代碼塊將多次調用 execute_block 和 join 函數。
1.在第一次執行完 execute_block 函數,當這里設置 parameters 為SignatureIndex(0),locals為SignatureIndex(0)會導致num_locals為132*2=264。 所以在執行join_函數下面這行代碼之后
將會導致新的locals map長度為8.
2.在第二次執行execute_block函數時,執行move代碼第一條指令copyloc(57),57是locals需要壓入棧的offset,但是這次locals只有長度8,offset 57不存在,所以會導致 get(57).unwrap() 函數返回 none ,最后導致panic。
以上就是這個漏洞的來龍去脈。首先這個漏洞說明沒有絕對安全的代碼, Move語言在代碼執行之前確實做了很好的靜態校驗,但是就像這個漏洞一樣,可以通過溢出漏洞完全繞過之前的邊界校驗。再者代碼審計很重要,程序員難免會疏忽。作為Move語言安全研究的領導者,我們將繼續深挖Move的安全問題。第三點,對于Move語言,我們建議語言設計者在move運行時增加更多的檢查代碼,以防止意外情況的發生。目前move語言主要是在verify階段進行一系列的安全檢查,但我覺得這還不夠,一旦驗證被繞過,運行階段沒有過多的安全加固,將導致危害進一步加深,引發更嚴重的問題。最后,我們還發現了Move語言的另一個漏洞,后續會繼續分享給大家。
參考資料
https://github.com/move-language/move
https://github.com/MystenLabs/awesome-move
https://move-language.github.io/move/
Numen Cyber
企業專欄
閱讀更多
金色早8點
金色財經
去中心化金融社區
CertiK中文社區
虎嗅科技
區塊律動BlockBeats
念青
深潮TechFlow
Odaily星球日報
騰訊研究院
Tags:BSPNBSLOCMOVEBSPNetworknbs幣前景vechainblockchaintokenMovement DAO
原文:《Cross-chain Bridges, Composability, and a New Era in Blockchain Interoperability》by Georgios.
1900/1/1 0:00:00經過接近半年的漫長等待,Genie 終于將「豬腳飯」端到了 NFT 老鳥們的面前。這份雖遲但到的「豬腳飯」十分良心——只要在今年 4 月 15 日的北京時間早 8 點前曾使用 Genie 完成過.
1900/1/1 0:00:00原作者:Zee Prime 聯合創始人 Matti我在舊文章《2022 年加密新手生存指南》上收到的積極反饋讓我思考如何為這些新鮮血液提供更多有用的 tips.
1900/1/1 0:00:00原文作者:Lao Bai今天來說說 Layer2 的 OP 與 ZK 之爭問題 短期 OP,長期 ZK? 這句話因為 V 神說過,所以被很多人認為是「金科玉律」.
1900/1/1 0:00:00原文:《Counterparty vs RGB vs TARO》by Mandel duck我最近參加了一個古董 NFT 節(Historical NFT festival).
1900/1/1 0:00:00原文:a16z推文 編譯:Azuma 我們很高興看到 crypto 社區出現了許多令人興奮的新創意。在接下來的推文中,你將可以找到一些有助于你繼續build的開發工具.
1900/1/1 0:00:00