作者:ATN
2018年5月11日中午,ATN技術人員收到異常監控報告,顯示ATN Token供應量出現異常,迅速介入后發現Token合約由于存在漏洞受到攻擊。本報告描述黑客的攻擊操作、利用的合約漏洞以及ATN的應對追蹤方法。
攻擊:
-
黑客利用ERC223方法漏洞,獲得提權,將自己的地址設為owner
https://etherscan.io/tx/0x3b7bd618c49e693c92b2d6bfb3a5adeae498d9d170c15fcc79dd374166d28b7b -
黑客在獲得owner權限后,發行1100w ATN到自己的攻擊主地址
https://etherscan.io/tx/0x9b559ffae76d4b75d2f21bd643d44d1b96ee013c79918511e3127664f8f7a910 -
黑客將owner設置恢復,企圖隱藏蹤跡
https://etherscan.io/tx/0xfd5c2180f002539cd636132f1baae0e318d8f1162fb62fb5e3493788a034545a -
黑客從主地址將偷來的黑幣分散到14個地址中
0x54868268e975f3989d77e0a67c943a5e65ed4a73 3411558.258
0x62892fd48fd4b2bbf86b75fc4def0a37b224fcc1 946828.3
0x57be7b4d3e1c6684dac6de664b7809185c8fc356 929,995.9
0x3b361e253c41897d78902ce5f7e1677fd01083da 838,991
0x7279e64d3ae20745b150e330fc080050deebeb4d 784,409.41
0xb729eac33217c0b28251261194d79edd89d18292 762,518.6
0xe67dc4b47e0ac9b649e52cdb883370d348871d64 682,026.9
0x44660bae953555ccfdcc5a38c78a5a568b672daa 564,288
0xf7e915e7ec24818f15c11ec74f7b8d4a604d7538 551,018.8
0xa4b45e8cca78e862d3729f10f4998da4200f10ef 438,277.6
0xc98e179f2909b1d0bce5b5d22c92bf803fc0d559 350,597.35
0xd5f898c7914e05ec7eaa3bf67aafd544a5bb5f24 325,291.1
0x3dd815af5d728903367a3036bc6dbe291de6f0ee 282,069.29
0x6d8750f28fffb8e9920490edb4ed1817a4736998 110,261.2948
利用的合約漏洞:
ATN Token合約采用的是在傳統ERC20Token合約基礎上的擴展版本ERC223,并在其中使用了 dapphub/ds-auth 庫。采用這樣的設計是為了實現以下幾個能力:
- 天然支持Token互換協議,即ERC20Token與ERC20Token之間的直接互換。本質上是發送ATN時,通過回調函數執行額外指令,比如發回其他Token。
- 可擴展的、結構化的權限控制能力。
- Token合約可升級,在出現意外狀況時可進行治理。
單獨使用 ERC223 或者 ds-auth 庫時,并沒有什么問題,但是兩者結合時,黑客利用了回調函數回調了setOwner方法,從而獲得高級權限。
ERC223轉賬代碼如下:
function transferFrom(address _from, address _to, uint256 _amount,
bytes _data, string _custom_fallback) public returns (bool success)
{
...
ERC223ReceivingContract receiver =
ERC223ReceivingContract(_to);
receiving.call.value(0)(byte4(keccak256(_custom_fallback)),
_from, amout, data);
...
}
當黑客轉賬時在方法中輸入以下參數:
transferFrom( hacker_address, atn_contract_address, 0, 0,
"setOwner(address)")
_from: 0x2eca25e9e19b31633db106341a1ba78accba7d0f -- 黑客地址
_to: 0x461733c17b0755ca5649b6db08b3e213fcf22546 -- ATN合約地址
_amount: 0
_data: 0x0
_custom_fallback: setOwner(address)
該交易執行的時候 receiver 會被 _to(ATN合約地址) 賦值, ATN 合約會調用 _custom_fallback 即 DSAuth 中的 setOwner(adddress) 方法,而此時的 msg.sender 變為 ATN 合約地址,owner_參數為_from(黑客地址)
ds-auth庫中setOwner 代碼如下:
functuin setOwner(address owner_) public auth
{
own = owner_;
LogSetOwner(owner);
}
此時 setOwner 會先驗證 auth 合法性的,而 msg.sender 就是ATN的合約地址。setOwner 的 modifier auth 代碼如下:
modifier auth {
require(isAuthorized(msg.sender, msg.sig));
_;
}
function isAuthorized(address src, bytes4 sig) internal view returns
(bool) {
if (src == address(this)) { //此處的src與ATN合約地址一致返回true
return true;
} else { … }
通過利用這個ERC223方法與DS-AUTH庫的混合漏洞,黑客將 ATN Token合約的 owner 變更為自己控制的地址。獲取 owner 權限后,黑客發起另外一筆交易對 ATN 合約進行攻擊,調用 mint 方法給另外一個地址發行 1100wATN。
最后,黑客調用 setOwner 方法將權限復原。
漏洞評估:
漏洞等級:嚴重
產品影響:atn-contracts
可能損失:導致Token總供應量發生變化
發現了基于ERC223標準與dapphub/ds-auth庫相結合的合約漏洞,更準確的說是在ERC223回調函數發起時,調用本身合約時可能造成內部權限控制失效。
應對措施:
經過上面的追蹤,發現黑客將黑幣分散在14個不同的新地址中,而這些地址中并沒有ETH,暫時不存在立即的轉賬到交易所銷贓的風險。我方有能力立即凍結黑客的黑幣,恢復供應量的變化,所以,重點在如何追蹤到黑客,應對思路如下:
- 準備修復措施,增加Guard合約禁止回調函數向ATN合約本身回調;增加黑名單合約,隨時凍結黑客地址
- 等待黑客向交易所發送充值交易,以便獲得進一步證據
- 獲得證據后,立即啟動修復流程,將黑客相關地址加入黑名單,禁止其轉移ATN Token
- 基金會銷毀等量ATN Token以恢復供給總量,并在ATN主鏈上線時予以修正。
產品修復:新增Guard合約,禁止對ATN合約發送轉賬交易,進而防止回調函數對ATN合約進行方法調用。
由于 ATN 合約的靈活性和治理擴展性,創建并添加了兩個 Guard 合約。
- 創建添加 FrozenGuard 合約,禁止對 ATN 合約發送轉賬交易。
- 創建添加 StopTransferGuard 合約,凍結黑客賬戶地址,禁止其 ATN進行轉賬。
- 基金會銷毀 1100w ATN,恢復 ATN 總量。
ATN Gurad 會在發生轉賬交易時,對交易的合法性進行處理。
ATN 轉賬代碼如下:
function transferFrom(address _from, address _to, uint256 _amount,
bytes _data, string _custom_fallback) public returns (bool success) {
if (isContract(controller)) {
if (!TokenController(controller).onTransfer(_from, _to,
_amount))
throw;
}
...
}
ATN 的 TokenController 接管了 onTranser(_from, _to, amount) 處理方法,實現對交易的合法性驗證。具體方法在 SwapController 中實現:
function onTransfer(address _from,address _to, uint _amount) public
returns (bool) {
for (uint i =0; i<guards.length; i++) {
if (!gruards[i].onTokenTransfer(_from, _to, amount)) {
return false;
}
}
}
SwapController 中維護了 TokenTransferGuard 的合約列表,可以添加多個 Guard 合約對交易的合法性進行驗證。
FrozenGuard.sol 代碼如下:
function onTokenTransfer(address _from, addres _to, uint _amount)
public returns (bool) {
if (_to == tokenAddress) {
return false;
}
return true;
}
tokenAddress為 ATN 合約地址,禁止對 ATN 地址發送轉賬交易。
StopTransferGurad.sol 代碼如下:
function onTokenTransfer(address _from, addres _to, uint _amount)
public returns (bool) {
if (!stopped && isBlack[_from]) {
return false;
}
return true;
}
isBlack 存儲所有黑客非法發行 ATN 的賬戶地址,支持動態更新。所有轉賬到這些的 ATN 也將無法轉賬。
stopped 該Guard的開關。
安全審計結果:
模擬凍結黑名單地址轉賬結果:
https://kovan.etherscan.io/tx/0x68755305fee0d995f4ee79f6ab9d14e1aaf5d4b1c2d5838acbbaff464b6579d5
模擬向ATN合約轉賬結果:
https://kovan.etherscan.io/tx/0x78738ab30a507ac209fb4aaf80be7e92c558bff8767887d3e1f4e0a445f16444
模擬黑客攻擊結果:
https://kovan.etherscan.io/tx/0x7c72613fca4440b7775d08fde6beeba0e428a975cdf58a912ee76cb0e1ea87af
轉賬都失敗,判定漏洞已修復。
最終,黑客向交易所進行充值,獲得證據
https://etherscan.io/tx/0x18bd80b810f6a6b6d397901d677657d39f8471069bcb7cfbf490c1946dfd617d
Guard安全修復合約即刻部署,黑客相關地址予以禁止轉賬處理。
ATN將在交易所配合的情況下向黑客進行追蹤,并保留向執法機構報案的權利。基金會銷毀 1100w ATN,恢復 ATN 總量,并將在主鏈上線時對黑客地址內的資產予以剔除。
總結
“合約無小事”
由于 ATN 合約設計增加多項功能及治理機制,增加了審計的難度和復雜度,在發布到鏈上之前進行的幾次內部和外部審計均未發現該漏洞。
攻擊發生后,ATN技術團隊及時察覺極速反應并部署了ATN Token合約的防御措施并迅速修復了此未知漏洞;在實時監測到黑客將資金轉入交易所地址基本可斷定為黑客攻擊(而非白帽行為)后,跟相關交易所協商追蹤黑客信息并保留追責權利。
合約的安全審計,僅依靠開發者的經驗和能力總有隱患,過去業內的幾次合約漏洞事件也說明了這個問題。將來我們需要有更多的類似形式化驗證的工具來幫助開發者發現潛在問題,從而編寫更加健壯的合約。
對其他以太坊Token合約的預警:
所有同時用到類似ERC223推薦實現的custom_fallback和ds-auth的合約,或者說內置有其他權限控制得合約,很可能也存在這個漏洞,需要檢查確認。
ERC223的這個custom_fallback 的call處理,可以讓public獲取Token合約的this作為msg.sender調用其他方法(雖然參數限定,但是也可以通過編碼的方式hack),另外ds-auth默認是this可以獲得授權,這邊有一些爭議,是否ds-auth默認授權范圍太大。
本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/621/
暫無評論