深入到閃電貸的原始碼,理解什麼是閃電貸和閃電貸攻擊。
分享嘉賓:Frog,Numen 區塊鏈安全研究員
整理:小胡
編輯:辰一
我們在上一期文章中,主要介紹了針對領先 DeFi 借貸協議 Euler Finance 的閃電貸攻擊。在本期文章中,我們會更進一步,深入到閃電貸的原始碼,理解什麼是閃電貸和閃電貸攻擊。
01 TL; DR
正如我們上一期文章(「暴雷」啟示錄:Euler Finance 被攻擊前因後果復現),閃電貸有如下關鍵詞:
1. 不需要抵押資金的貸款
2. 放貸、使用資金和還貸「同時」進行
因此利用無需抵押的大額資金,黑客可以:
1. 操縱價格,砸盤或拉盤
2. 成倍地放大已有漏洞
02 什麼是閃電貸
閃電貸(Flash loan)是一種去中心化金融(DeFi)的創新產品,它允許使用者在不提供任何抵押的情況下,借用協議池中的任意數量的資產,只要在同一筆交易(一個區塊)中歸還本金和利息。閃電貸的優勢在於,它可以讓使用者利用市場上的套利機會,實現低成本、高收益的操作。閃電貸的風險在於,如果使用者無法在規定時間內還款,那麼交易會被撤銷,使用者將損失交易費用和利息。
1 常見的閃電貸平臺
提到閃電貸,你可能會立刻聯想到 Aave,這家公司是閃電貸的發明者和領導者。由於閃電貸的資金本身有低風險的特性,較高的需求立刻湧現了一大批閃電貸平臺。提供閃電貸服務的頭部平臺還有:
- Uniswap: 一個去中心化的交易平臺,提供閃電貸服務。使用者可以通過 Uniswap 借用任何支援的代幣,並在同一筆交易中進行兌換、做市、套利等操作。
- Compound:一個開源的借貸協議,支援多種數字資產的借貸和借款,提供閃電貸服務。使用者可以通過 Compound 借用任何可用的資產,並在同一筆交易中進行還款、抵押、借款等操作。
- MakerDAO:一個去中心化的穩定幣平臺,支援 DAI 穩定幣的發行和交易,提供閃電貸服務。使用者可以通過 MakerDAO 借用 DAI,並在同一筆交易中進行還款、兌換、償還清算罰金等操作。
- dYdX:一個去中心化交易所,提供閃電貸服務和開放式借貸市場。使用者可以通過 dYdX 借用任何可用的資產,並在同一筆交易中進行還款、交易、槓桿等操作。
除此之外,常見的還有 Nuo、Fulcrum、bZx、DeFi Money Market、ETHLend 等。
這些閃電貸平臺在功能上都提供了無抵押、即時借貸的服務,細節上的差異更多的是體現在平臺的安全性、使用者體驗和手續費上。
2 Uniswap 閃電貸
Uniswap 是 DeFi 中最受歡迎的去中心化交易所之一。一般使用者接觸到 Uniswap 的途徑是網頁介面。比如下圖展示了 ETH-DAI 的兌換。我們稱兩個代幣之間的兌換為一個交易對。

但除了使用網站進行互動,我們還可以直接呼叫智慧合約互動。當你想在他們的平臺上購買 token 時:
- 首先需要傳送 token 用於支付
- 然後呼叫一個 swap() 的函式,它將傳送你剛剛購買的 token。
Uniswap V2 版有一個新的功能,叫做 Flashswap,是 Uniswap 對閃電貸的稱呼。這一功能是整合在常規的 swap() 函式中的。
一個常見的閃電貸操作邏輯有四步,必須在同一個區塊中完成:
1. 傳送交易請求,並上傳智慧合約
2. 向協議傳送代幣
3. 上傳的智慧合約使用代幣互動
4. 歸還代幣給協議

因為 Uniswap 的 swap() 函式模式是先轉賬再進行校驗,所以第二步可以先將需要的代幣借出後,第三步呼叫自己合約中的 uniswapV2Call() 函式進行其它操作,完成後第四步再將借的代幣歸還,完成閃電貸服務。
在程式碼中,紅框部分就是使用者預先部署的合約。要想在同一個區塊中完成上面的所有操作,使用者要將如何使用借出的資金用合約預先定義好,畢竟手工操作的速度沒有程式碼執行快。

而在紅框上方的兩行中,我們看到有兩個轉賬函式。如註釋所言,這是「樂觀的轉賬」──即不校驗是否支付就先轉賬。在最後的部分中,呼叫完使用者合約之後,swap() 函式才會慢悠悠地 require 支付金額。
而無論是否使用閃電貸服務,Uniswap 都會對每筆交易收取高達 0.3% 的手續費。
3 AAVE 閃電貸
總體而言,AAVE 的 LendingPool 合約中的 Flashloan 函式提供了類似的閃電貸功能。通過呼叫 Flashloan 函式,傳入借貸的金額和代幣型別借貸地址等引數。執行過程中將代幣轉給傳入的接收地址後會呼叫傳入地址的 executeOperation 函式,這時可以在 executeOperation 函式完成其它操作。

AAVE 和 Uniswap 有一點點不同之處在於還款的流程。AAVE 閃電貸的還款,是需要借貸者向 LendingPool 合約授權,在完成閃電貸過程後,由 AAVE 合約將借用的錢和手續費從借款地址中轉回。而在 Uniswap 中,是由使用者呼叫 safeTransfer 進行手動轉賬。

這樣可以保證更高的成功率,但相應的可能有一定的合約漏洞風險。
03 閃電貸攻擊
關於閃電貸攻擊的討論是不斷的。有人說閃電貸攻擊嚴格來講名不副實,因為並沒有利用閃電貸的漏洞,而是利用大額的資金提前發現了已有的漏洞。比如利用閃電貸低成本的大額資金,可以:
1. 利用閃電貸大的資金量操縱價格,一些項目中價格獲取邏輯存在問題。
2. 一些項目在抵押或其它過程中會產生瞬時獎勵,利用閃電貸獲得大額獎勵。
3. 項目中存在其它的邏輯漏洞,利用閃電貸大的資金量放大套利空間。
我們先從案例進行分析,然後再討論哪些漏洞容易被閃電貸攻擊。
1 DFX 攻擊事件
簡單來講,針對 DFX 的攻擊分為三步:
1. 從 UniswapV3 完成對 USDC 和 XIDR 的閃電貸。

2. 從 DFX 的合約中呼叫 flash 函式借貸到 UCDC 和 XIDR 後又去呼叫了 deposit 函式進行了抵押,抵押時可以看到又將黑客借出的錢抵押回了 DFX 合約。

3. 因為使用者抵押時將代幣又轉回到了 DFX 的合約導致借款前後的餘額驗證通過,不用再歸還借出的閃電貸,但是黑客有抵押操作,此時便可以呼叫提取函式,提取抵押後離場。

2 常見漏洞分析
讓我們來盤點一下下面程式碼都有哪些漏洞。
1. 通過代幣數量獲取價格:

這段程式碼直接讀取了去中心化交易所 pair 合約中的代幣數量,將兩者之商作為代幣的價格。對於缺乏程式碼審計經驗的人來說,這樣寫乍一看似乎沒有什麼問題。但是如果考慮到 Uniswap 支援閃電貸這一事實,事情就變得有趣了起來。
如果沒有閃電貸,兩種代幣的數量一定是一個減少另一個就增加。但是有了閃電貸,很有可能發生的局面是一個代幣減少,而另一種代幣沒有增加。如果閃電貸的數額不大,兩種情況下的差額不大。但如果借出了鉅額閃電貸,這個價差將會被立刻拉大,形成巨大套利空間。
這樣的漏洞對於沒有程式碼審計經驗的人來說很難發現,需要在安全領域有較長時間的深耕和積累,才能形成一套成熟的程式碼審計體系。
2. 發放獎勵:

在這段程式碼中,合約會根據抵押量的大小,立刻將獎勵返還給使用者地址。這裡的問題我們已經提到過了,也是比較好想到。如果獎勵發放沒有延遲,閃電貸的錢在合約中質押了僅僅一瞬間就能獲得獎勵,這樣無疑是一個巨大的套利漏洞。
3 防範措施
在 DeFi 還沒有成熟的時間段內,閃電貸攻擊仍將持續不斷,成為懸在人們頭上的一把達摩克利斯之劍。不同的閃電貸攻擊影響的範圍也不同,有的可能導致某個看起來毫不相干的 DeFi 協議暴雷,有的可能波及眾多使用者。我們能做好的就是做好防範措施,靜待 DeFi 不斷成熟:
1. 質押挖礦功能和借貸合約做分離,不要將使用者抵押的代幣轉移到借貸合約或者記錄變數做運算。
2. 借貸時新增特殊重入鎖,借貸時不允許抵押。
3. 項目在價格獲取時採用多資料來源的形式,資料對比後減小价格誤差。
4. 移除流動性時應當先銷燬 LP,再進行其它呼叫。
5. 獎勵的產生儘量採用隔區塊或者時間差的形式,可以有效避免閃電貸攻擊。
6. 項目邏輯問題是導致黑客利用閃電貸放大套利最常見得情況。因此,項目在上線前要做好安全審計和測試,保證項目安全性。



