Microsoft Azure 以太坊節點自動化部署方案漏洞分析
作者:sunsama@知道創宇404區塊鏈安全研究團隊
時間:2018/07/10
一、背景介紹
為了迎合以太坊區塊鏈[1]發展需求,Microsoft Azure[2]早在2016年9月九推出了以太坊節點走自動部署的模塊。部署情況如下:
登陸Microsoft Azure:
部署Ethereum Proof-of-Work Consortium
訪問建立的「ADMIN-SITE」可以看到一個「Blockchain Admin」界面:
我們注意到這個管理介面提供了一個「轉賬」功能並且整個頁面缺少鑒權機制任何人都可以訪問,這樣就導致惡意攻擊者可以通過該介面提交錢包地址和轉賬數量進行轉賬。
Web3.js 是?個兼容了以太坊核心功能的JavaScript庫[3],很多以太坊客戶端及DApp都是通過調用Web3.js的API接?來實現。 以太坊客戶端開發庫主要是提供了兩種類型的API介面:RPC(Remote Procedure Call)及IPC(Inter-process Communications),在以往的攻擊事件里很多關注點都在RPC介面上,而很少關注IPC介面,在本文的涉及「Blockchain Admin」的問題就發生在IPC介面上,由此下面做了詳細的代碼分析:
二、代碼分析
在分析之前我們先介紹下PRC及IPC介面區別:
IPC與RPC簡介
IPC(Inter-process Communications)進程間通信,是指在不同進程之間傳播或交換信息,IPC的方式通常有管道、消息隊列、信號量、共享存儲、Socket、Stream等。對於geth來說IPC的方式更為高效,在安裝geth之後 IPC socket不會自動創建,並且他也不是一個永久的資源,只有在啟動geth時才會創建一個IPC Socket。
有以下幾個參數可以在啟動geth時配置IPC相關服務,其他參數可以使用geth —help查看。
--ipcdisable Disable the IPC-RPC server
--ipcapi "admin,eth,debug,miner,net,shh,txpool,personal,web3" API"s offered over the IPC-RPC interface
--ipcpath "geth.ipc" Filename for IPC socket/pipe within the datadir (explicit paths escape it)
在geth啟動時使用 --ipcpath來指定一個IPC路徑,會有一段信息指明IPC的相關信息。例如
IPC endpoint opened: /Users/username/Library/Ethereum/geth.ipc
Web3.js中提供了使用IPC通信的方法。
// Using the IPC provider in node.js
var net = require("net");
var web3 = new Web3("/Users/myuser/Library/Ethereum/geth.ipc", net); // mac os path
// or
var web3 = new Web3(new Web3.providers.IpcProvider("/Users/myuser/Library/Ethereum/geth.ipc", net)); // mac os path
// on windows the path is: "\\.\pipe\geth.ipc"
// on linux the path is: "/users/myuser/.ethereum/geth.ipc"
node_modules/web3/lib/web3/ipcprovider.js
var IpcProvider = function (path, net) {
var _this = this;
this.responseCallbacks = {};
this.path = path;
this.connection = net.connect();
...............
};
https://github.com/ethereum/go-ethereum/wiki/Management-APIs中給出了在命令行使用IPC的例子
RPC(Remote Procedure Call)遠程過程調用,指通過網路從遠程計算機的程序上請求服務。geth為RPC提供了兩種方法,分別是HTTP JSON RPC API(默認8545埠)和WebSocket JSON RPC API(默認8546埠)。
在命令行中可以使用以下參數配置RPC服務。
--rpc 啟用HTTP-RPC伺服器
--rpcaddr value HTTP-RPC伺服器介面地址(默認值:「localhost」)
--rpcport value HTTP-RPC伺服器監聽埠(默認值:8545)
--rpcapi value 基於HTTP-RPC介面提供的API
WebSocket
--ws 啟用WS-RPC伺服器
--wsaddr value WS-RPC伺服器監聽介面地址(默認值:「localhost」)
--wsport value WS-RPC伺服器監聽埠(默認值:8546)
--wsapi value 基於WS-RPC的介面提供的API
--wsorigins value websockets請求允許的源
同樣的在Web3.js中也提供了使用RPC的方法。
Http Api
var Web3 = require("web3");
var web3 = new Web3("http://localhost:8545");
// or
var web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
WebSocket Api
// change provider
web3.setProvider("ws://localhost:8546");
// or
web3.setProvider(new Web3.providers.WebsocketProvider("ws://localhost:8546"));
/**
* HttpProvider should be used to send rpc calls over http
*/
var HttpProvider = function (host, timeout) {
this.host = host || "http://localhost:8545";
this.timeout = timeout || 0;
};
以太坊黑色情人節事件中,攻擊者就是利用了RPC介面進行惡意轉賬。
流程分析
我們在Blockchain Admin頁面的兩個輸入框中輸入轉賬地址和轉賬數量並提交。
/home/ethtest/etheradmin/app.js定義了提交後伺服器處理的方法。
命令行中的參數
var listenPort = process.argv[2]
var gethIPCPath = process.argv[3];
var coinbase = process.argv[4];
var coinbasePw = process.argv[5];
var consortiumId = process.argv[6];
var registrarHostEndpoint = process.argv[7];
var registrarConnectionString = process.argv[8];
var registrarDatatbaseId = process.argv[9];
var registrarCollectionId = process.argv[10];
定義了使用IPC服務
var web3IPC = new Web3(new Web3.providers.IpcProvider(gethIPCPath, require("net")));
··············
app.post("/", function(req, res) {
var address = req.body.etherAddress;//轉賬地址
var amount = req.body.amount;//轉賬數量
if(web3IPC.isAddress(address)) {
//如果提交的地址是以太坊地址則解鎖賬號
web3IPC.personal.unlockAccount(coinbase, coinbasePw, function(err, res) {
console.log(res);
//通過ipc方法發送一筆交易
web3IPC.eth.sendTransaction(, function(err, res){ console.log(address)});
});
req.session.isSent = true;
} else {
req.session.error = "Not a valid Ethereum address";
}
res.redirect("/");
});
使用POST方法提交後,會判斷我們輸入的地址是否是合法的以太坊地址。默認情況下我們的賬號是處於鎖定狀態的,這裡判斷地址正確後使用personl.unlockAccount()方法解鎖賬號。該方法需要的參數coinbase和coinbasePw在啟動服務時已經在命令行中作為參數傳遞過來了,使用ps命令查看該服務的進程。
其中f9cdc590071d9993b198b08694e5edf376979ce6是我們的錢包地址,123qweasdZXC是解鎖錢包需要的密碼,/home/ethtest/.ethereum/geth.ipc是getIPCPath參數的內容。
personal.js中的unlockAccount方法。
var unlockAccount = new Method({
name: "unlockAccount",
call: "personal_unlockAccount",
params: 3,
inputFormatter: [formatters.inputAddressFormatter, null, null]
});
IpcProvider.js中對發送方法的定義。
IpcProvider.prototype.send = function (payload) {
if(this.connection.writeSync) {
var result;
// try reconnect, when connection is gone
if(!this.connection.writable)
this.connection.connect();
var data = this.connection.writeSync(JSON.stringify(payload));
try {
result = JSON.parse(data);
} catch(e) {
throw errors.InvalidResponse(data);
}
return result;
} else {
throw new Error("You tried to send ""+ payload.method +"" synchronously. Synchronous requests are not supported by the IPC provider.");
}
};
ipcprovider會調用JSONRPC.js將unlockAccount方法中的參數格式化為JSON格式。
在node_modules/web3/lib/web3/ipcprovider.js中下斷點跟蹤一下數據流。
然後將數據通過socket寫入。
接下來geth通過IPC接收到了請求的方法和參數,然後使用UnlockAccount函數進行賬戶解鎖,解鎖賬戶後使?eth.sendTransaction?法發送交易。
sendTransaction方法會使用已經解鎖後的本地賬戶的私鑰進行簽名,並使用SignedTransaction方法進行發送簽名後的交易。
我們通過geth日誌獲取交易hash,在console中查看詳細信息。
下面是從提交交易請求到生成交易並發送的流程圖。
值得一提的是:在我們分析過程發現通過Microsoft Azure提供的以太坊節點自動化部署方案仍然使用的1.7.3版本的geth ?這個版本里UnlockAccount函數:
func (s *PrivateAccountAPI) UnlockAccount(addr common.Address, password string, duration *uint64) (bool, error) {
const max = uint64(time.Duration(math.MaxInt64) / time.Second)
var d time.Duration
if duration == nil {
d = 300 * time.Second
} else if *duration > max {
return false, errors.New("unlock duration too large")
} else {
d = time.Duration(*duration) * time.Second
}
err := fetchKeystore(s.am).TimedUnlock(accounts.Account, password, d)
return err == nil, err
}
wiki中對personal_unlockAccount方法的定義:
從keystore中解鎖賬戶並獲得私鑰,並把已經解鎖的私鑰放到內存中。解鎖賬戶的api允許傳入超時時間,默認超時為300秒,如果傳?入的超時時間為0,則是永久不不會超時,賬戶?直處於解鎖狀態,直到節點進程退出。這也是「以太坊【偷渡】漏洞事件[5]」發生的主要原因。
三、風險評估
在以往的關於以太坊攻擊案例里更多的是發生在暴露在互聯網的RPC介面上,?基於本地進程通訊的IPC介面 被認為是相對安全可靠的,但是如果類似於Microsoft Azure提供的以太坊節點?動化部署?案里 的「Blockchain Admin」基於IPC調?程序,本身沒有任何認證直接暴露在互聯網上無疑是巨大的安全風險。(註:通過ZoomEye?路空間搜索引擎[7]可以看到曾經暴露在互聯網上的目標。)
在實際測試分析過程發現使用Microsoft Azure提供的以太坊節點自動化部署方案更多的是聯盟鏈或私有鏈,部署共有鏈的情況較少,所以這個安全事件實際可能給共有鏈的帶來的影響相對不大。對於聯盟鏈或私有鏈的影響需要根據其本身的情況去衡量量評估。
四、報告流程
針對以上問題我們第一時間聯繫了微軟:
五、總結
區塊鏈虛擬貨幣安全事件頻發,安全刻不不容。通過這次的案例可以得幾點建議:
盡量避免使用這種自動化部署區塊鏈應用的方案,如果必須使用的話,請仔細查看該方案使用的程序是否存在安全缺陷與漏洞。
修改默認埠,關閉對外的高許可權介面,如果必須暴露在互聯網,請對介面進行鑒權。
關注官方發布的更新日誌,及時更新代碼。
針對目前主流的以太坊應用,知道創宇提供專業權威的智能合約審計服務,規避因合約安全問題導致的財產損失,為各類以太坊應用安全保駕護航。
知道創宇404智能合約安全審計團隊:https://www.scanv.com/lca/index.html
聯繫電話:(086) 136 8133 5016(沈經理,工作日:10:00-18:00)
歡迎掃碼諮詢:
參 考 鏈 接
[1]https://baike.baidu.com/item/%E4%BB%A5%E5%A4%AA%E5%9D%8A/20865117?fr=aladdin
[2]https://azure.microsoft.com/en-us/
[3]https://github.com/ethereum/web3.js/
[4]https://github.com/ethereum/go-ethereum/wiki/Management-APIs
[5]https://paper.seebug.org/547/
[6]https://mp.weixin.qq.com/s/Kk2lsoQ1679Gda56Ec-zJg
[7]https://www.zoomeye.org/searchResult?q=%22Blockchain%20Admin%22
往 期 熱 門
TAG:Seebug漏洞平台 |