by : 風之傳說編程
最近在研究區塊鏈方面的漏洞,智能合約top 1重入漏洞。在網上找了不少相關的文章,發現大部分都是經過代碼進行分析。話說,咱們不瞭解應用場景,只是瞭解漏洞成因,只知其原理不知其過程,不便於咱們的漏洞理解。編程語言
在此以前,咱們須要先了解一個東西,The DAO。"在2016年6月18日被攻擊前募集了$150M。攻擊者 利用合約中的漏洞發動了Reentrancy攻擊,得到了$60M。爲了追回這部分資金,以太坊社區決定進行硬分叉,在新分支中回滾自攻擊開始後的全部交易記錄並修復合約漏洞,但由於此舉違背了‘Code is law’精神,部分紅員拒絕新分支,致使最終造成了兩個分支。舊分支稱爲以太坊經典(Ethereum Classic/ETC),新分支爲現行以太坊。攻擊者最終離開以太坊經典,帶走了數千萬美圓。"函數
以上新聞說明兩個問題:區塊鏈
技術細節:spa
那麼衆籌就須要三方,付款方,公證人(平臺),收款方。咱們先進行簡單瞭解。談完了,背景,咱們再來談談漏洞,先看一段:blog
大多數都沒有進行註釋,畢竟是新的編程語言,國內熟悉的比較少。我進行了註釋。可是爲了你們便於理解,我就從新解釋一次。部署
假如帳戶有10個幣,你要轉9個出去。確定是能夠的,你要轉11個,就不行。由於你沒有11個。因此此處要轉9個出去確定是能夠的。由於10>=9。最後一步就是減去你帳戶中的9個幣了。此時帳戶裏面只有1個幣了。因此,各位看官確定會說,這裏沒毛病啊。嗯,程序好像看似沒毛病可是。看看黑客如何進行攻擊的:it
攻擊者首先構造一個惡意合約Mallory,將Mallory部署以後,攻擊者調用withdraw函數向Mallory合約捐贈一點以太幣。看似沒什麼問題。社區
但是withdraw函數中的msg.sender.call.value(amout)()執行以後,因爲轉帳 操做特性 ,會在轉帳結束以後自動調用Mallory 的 fallback函數,因而再次調用 withdraw函數。由於此時credit中並未更新額度,因此依然能夠正常取款,便陷入遞 歸循環,每次都提取DAO中的一部分以太幣到Mallory合約中。class
講到這裏,究竟是哪裏出了問題呢? 實際上是msg.sender.call.value 這個調用出了問題。壓根就不能這麼調。 (因此後來出了一個什麼氣Gas?而且要求使用send() 和 transfer() 轉幣進行轉帳。扯遠了,有空能夠去了解一下)
在這裏,咱們上面分析過了,咱們是先進行轉帳再進行扣款的。那麼這樣有什麼壞處呢?也就是說,若是在轉帳處一直循環卡住了,那麼扣款就不會執行。也就是說,你能夠一直轉帳下去。
舉個流程例子:
正常狀況下
不正常狀況下:
重複此操做,理論上可以將The DAO的以太幣所有提取到Mallory。
最後確定還有人會說,錢怎麼轉出來啊?別忘了,該合約是由你建立的,拿通常的衆籌平臺去了解,也就是說,衆籌的錢最後都給你,由於是你發起的衆籌。因此你還擔憂轉不出錢來?因此,應用到實際場景,就能理解了吧。
注:因爲剛接觸區塊鏈這一塊,以上代碼註釋若是有錯誤歡迎指正。