漏洞分析
IOST公鏈使用Go語言開發,Go語言的make函數如果參數控制不當容易產生拒絕服務漏洞。在IOST的公鏈代碼中搜索make,找到了一處貌似可以利用的地方。
func(sy*SyncImpl)getBlockHashes(startint64,endint64)*msgpb.BlockHashResponse{resp:=&msgpb.BlockHashResponse{BlockInfos:make(*msgpb.BlockInfo,0,end-start1),}node:=sy.blockCache.Head()ifnode!=nil&&end>node.Head.Number{end=node.Head.Number}省略...
Line3make的第3個參數為end-start1,end和start來自handleHashQuery
func(sy*SyncImpl)handleHashQuery(rh*msgpb.BlockHashQuery,peerIDp2p.PeerID){ifrh.End<rh.Start||rh.Start<0{return}varresp*msgpb.BlockHashResponseswitchrh.ReqType{casemsgpb.RequireType_GETBLOCKHASHES:resp=sy.getBlockHashes(rh.Start,rh.End)casemsgpb.RequireType_GETBLOCKHASHESBYNUMBER:resp=sy.getBlockHashesByNums(rh.Nums。省略...
可以看到并沒有限制end-start1的大小,只要end足夠大,start足夠小就可以導致拒絕服務。所以現在問題就只剩下如何觸發這個漏洞。
漏洞利用
IOST節點之間的P2P通信使用的是libp2p,libp2p是一個模塊化的網絡堆棧,匯集了各種傳輸和點對點協議,使開發人員可以輕松構建大型,強大的p2p網絡。
來看一看IOST節點的P2Pservice啟動流程。
首先創建一個NetService,代碼如下:
Polygon推出新部門Polygon Studios,專注于區塊鏈游戲及NFT領域:7月20日消息,以太坊擴展方案Polygon推出新工作室Polygon Studios,推進其區塊鏈游戲和NFT工作。新成立的Polygon Studios有三個核心目標:1.確立Polygon在去中心化游戲領域的領導者地位;2.創造一個能夠吸引開發者和投資者進入其NFT生態系統的品牌;3.幫助將Polygon定位為過渡到Web3.0的首選平臺。通過Polygon Gaming Studio的項目,該公司旨在幫助開發者創造和運營去中心化游戲。另一個項目Polygon NFT Studio旨在幫助品牌和知識產權所有者推出定制的數字收藏品和市場。[2021/7/20 1:04:07]
//NewNetServicereturnsaNetServiceinstancewiththeconfigargument.funcNewNetService(config*common.P2PConfig)(*NetService,error){ns:=&NetService{config:config,}iferr:=os.MkdirAll(config.DataPath,0755);config.DataPath!=""&&err!=nil{ilog.Errorf("failedtocreatep2pdatapath,err=%v,path=%v",err,config.DataPath)returnnil,err}privKey,err:=getOrCreateKey(filepath.Join(config.DataPath,privKeyFile))iferr!=nil{ilog.Errorf("failedtogetprivatekey.err=%v,path=%v",err,config.DataPath)returnnil,err}host,err:=ns.startHost(privKey,config.ListenAddr)iferr!=nil{ilog.Errorf("failedtostartahost.err=%v,listenAddr=%v",err,config.ListenAddr)returnnil,err}ns.host=hostns.PeerManager=NewPeerManager(host,config)ns.adminServer=newAdminServer(config.AdminPort,ns.PeerManager)returnns,nil}
IOST鏈上個性化自管理SWAP+C2C SWAP流動性挖礦項目冬瓜金融今日20:00正式上線:由IOST節點合伙人開發,IOST項目方提供支持的首個個性化自管理SWAP+C2C SWAP流動性挖礦項目冬瓜金融將于今日20:00正式上線,并開通WG、SAB、PPT、TPT、XUSD、VOST、XG流動性挖礦池。
據介紹,冬瓜金融旨在通過獨特的個性化做市和C2C模式,為用戶提供更好的兌換價格和更優質的參與體驗。冬瓜金融建立一套交易所聚合系統,任何人都可以在冬瓜金融合于上建立并管理自己的去中心化SwapDex。[2020/10/31 11:19:29]
主要看Line18的startHost,該函數調用libp2p庫創建了一個host
//startHoststartsalibp2phost.func(ns*NetService)startHost(pkcrypto.PrivKey,listenAddrstring)(host.Host,error){tcpAddr,err:=net.ResolveTCPAddr("tcp",listenAddr)iferr!=nil{returnnil,err}if!isPortAvailable(tcpAddr.Port){returnnil,ErrPortUnavailable}opts:=libp2p.Option{libp2p.Identity(pk),libp2p.NATPortMap(),libp2p.ListenAddrStrings(fmt.Sprintf("/ip4/%s/tcp/%d",tcpAddr.IP,tcpAddr.Port)),libp2p.Muxer(protocolID,mplex.DefaultTransport),}h,err:=libp2p.New(context.Background(),opts...)iferr!=nil{returnnil,err}h.SetStreamHandler(protocolID,ns.streamHandler)returnh,nil}
該host的流處理邏輯在ns.streamHandler中
func(ns*NetService)streamHandler(slibnet.Stream){ns.PeerManager.HandleStream(s,inbound。
IOST與區塊鏈云服務平臺Ankr正式達成合作伙伴關系:據官方消息,IOST與區塊鏈云服務平臺Ankr正式達成合作伙伴關系,共同為IOST節點合伙人社區提供節點托管解決方案。Ankr針對IOST節點合伙人研發了一鍵節點部署應用,在其節點商店即可下載。這款應用可以讓用戶用最直接、最輕松的方法創建IOST全節點。詳情見原文鏈接。[2020/5/22]
steamHandler又調用PeerManager的HandleStream函數
//HandleStreamhandlestheincomingstream.////Itcheckswhethertheremotepeeralreadyexists.//Ifthepeerisnewandtheneighborcountdoesn'treachthethreshold,itaddsthepeerintotheneighborlist.//Ifpeeralreadyexits,justaddthestreamtothepeer.//Inothercases,resetthestream.func(pm*PeerManager)HandleStream(slibnet.Stream,directionconnDirection){remotePID:=s.Conn().RemotePeer()pm.freshPeer(remotePID)ifpm.isStreamBlack(s){ilog.Infof("remotepeerisinblacklist.pid=%v,addr=%v",remotePID.Pretty(),s.Conn().RemoteMultiaddr())s.Conn().Close()return}ilog.Debugf("handlenewstream.pid=%s,addr=%v,direction=%v",remotePID.Pretty(),s.Conn().RemoteMultiaddr(),direction)peer:=pm.GetNeighbor(remotePID)ifpeer!=nil{s.Reset()return}ifpm.NeighborCount(direction)>=pm.neighborCap{if!pm.isBP(remotePID){ilog.Infof("neighborcountexceeds,closeconnection.remoteID=%v,addr=%v",remotePID.Pretty(),s.Conn().RemoteMultiaddr())ifdirection==inbound{bytes,_:=pm.getRoutingResponse(string{remotePID.Pretty(。)iflen(bytes)>0{msg:=newP2PMessage(pm.config.ChainID,RoutingTableResponse,pm.config.Version,defaultReservedFlag,bytes)s.Write(msg.content()。time.AfterFunc(time.Second,func(){s.Conn().Close(。。else{s.Conn().Close(。return}pm.kickNormalNeighbors(direction。pm.AddNeighbor(NewPeer(s,pm,direction))return}
公告 | BetaEX平臺將于2月25日14:00上線IOST:據官方消息,BetaEX將于2020年2月25日14:00(UTC+8)上線IOST,開通 IOST/USDT 交易市場,充值提現通道將于2020年2月24日17:00(UTC+8)開放。同步于2月25日14:00-2月28日14:00(UTC+8) 期間推出“30萬IOST獎勵大放送”活動。
IOST是一個高性能區塊鏈公鏈項目。通過獨創的PoB(置信度證明)共識機制,項目實現了高層次的擴展性和去中心化。BetaEX成立于2019年6月,目前擁有馬耳他全合規交易所牌照。團隊由業界頂級產品研發團隊、券商團隊及資深加密貨幣運營人員組成。[2020/2/25]
對于新建立連接的peer,IOST會啟動該peer并添加到neighborlist中
//AddNeighborstartsapeerandaddsittotheneighborlist.func(pm*PeerManager)AddNeighbor(p*Peer){pm.neighborMutex.Lock()deferpm.neighborMutex.Unlock()ifpm.neighbors==nil{p.Start()pm.storePeerInfo(p.id,multiaddr.Multiaddr{p.addr})pm.neighbors=ppm.neighborCount}}
peer啟動之后,IOST會調用peer的readLoop和writeLoop函數對該peer進行讀寫。
//Startstartspeer'sloop.func(p*Peer)Start(){ilog.Infof("peerisstarted.id=%s",p.ID())gop.readLoop()gop.writeLoop(。
我們主要看readLoop,看IOST對我們發送的數據如何處理。
func(p*Peer)readLoop(){header:=make(byte,dataBegin)for{_,err:=io.ReadFull(p.stream,header)iferr!=nil{ilog.Warnf("readheaderfailed.err=%v",err)break}chainID:=binary.BigEndian.Uint32(header)ifchainID!=p.peerManager.config.ChainID{ilog.Warnf("mismatchedchainID.chainID=%d",chainID)break}length:=binary.BigEndian.Uint32(header)iflength>maxDataLength{ilog.Warnf("datalengthtoolarge:%d",length)break}data:=make(byte,dataBeginlength)_,err=io.ReadFull(p.stream,data)iferr!=nil{ilog.Warnf("readmessagefailed.err=%v",err)break}copy(data,header)msg,err:=parseP2PMessage(data)iferr!=nil{ilog.Errorf("parsep2pmessagefailed.err=%v",err)break}tagkv:=mapstring{"mtype":msg.messageType().String(。byteInCounter.Add(float64(len(msg.content())),tagkv)packetInCounter.Add(1,tagkv)p.handleMessage(msg。p.peerManager.RemoveNeighbor(p.id。
公告 | Poloniex iOS版現接受TRC20-USDT存款:Poloniex官方今日發布公告稱,Poloniex iOS版現接受TRC20-USDT存款。此前11月8日消息,Poloniex已宣布其安卓版接受TRC20-USDT存款。[2019/11/11]
主要是讀取一個固定長度的header,然后根據header中的length來讀取data,通過header和data創建一個P2PMessage,最后調用handleMessage來處理這個msg。節點發送的數據包結構如下:
/*P2PMessageprotocol:0123(bytes)01234567012345670123456701234567--------------------------------|ChainID|--------------------------------------------------------------|MessageType|Version|--------------------------------------------------------------|DataLength|---------------------------------------------------------------|DataChecksum|---------------------------------------------------------------|Reserved|---------------------------------------------------------------||.Data.||---------------------------------------------------------------*/
handleMessage會根據messageType對message進行處理
//HandleMessagehandlesmessagesaccordingtoitstype.func(pm*PeerManager)HandleMessage(msg*p2pMessage,peerIDpeer.ID){data,err:=msg.data()iferr!=nil{ilog.Errorf("getmessagedatafailed.err=%v",err)return}switchmsg.messageType(){caseRoutingTableQuery:gopm.handleRoutingTableQuery(msg,peerID)caseRoutingTableResponse:gopm.handleRoutingTableResponse(msg)default:inMsg:=NewIncomingMessage(peerID,data,msg.messageType())ifm,exist:=pm.subs.Load(msg.messageType());exist{m.(*sync.Map).Range(func(k,vinterface{})bool{select{casev.(chanIncomingMessage)<-*inMsg:default:ilog.Warnf("sendingincomingmessagefailed.type=%s",msg.messageType()。returntrue}。}
了解了IOST節點之間P2P通信的處理邏輯,再來看看如何觸發存在漏洞的handleHashQuery函數。messageLoop中調用了handlerHashQuery
func(sy*SyncImpl)messageLoop(){defersy.wg.Done()for{select{casereq:=<-sy.messageChan:switchreq.Type(){casep2p.SyncBlockHashRequest:varrhmsgpb.BlockHashQueryerr:=proto.Unmarshal(req.Data(),&rh)iferr!=nil{ilog.Errorf("UnmarshalBlockHashQueryfailed:%v",err)break}gosy.handleHashQuery(&rh,req.From())省略...
可以看到當messageType為p2p.SyncBlockHashRequest,Data為BlockHashQuery時,handlerHashQuery函數會被調用。BlockHashQuery的結構如下,End和Start的值可控。
typeBlockHashQuerystruct{ReqTypeRequireType`protobuf:"varint,1,opt,name=reqType,proto3,enum=msgpb.RequireType"json:"reqType,omitempty"`Startint64`protobuf:"varint,2,opt,name=start,proto3"json:"start,omitempty"`Endint64`protobuf:"varint,3,opt,name=end,proto3"json:"end,omitempty"`Numsint64`protobuf:"varint,4,rep,packed,name=nums,proto3"json:"nums,omitempty"`XXX_NoUnkeyedLiteralstruct{}`json:"-"`XXX_unrecognizedbyte`json:"-"`XXX_sizecacheint32`json:"-"`}
因此,我們可以構造一個Message,將Start的值設為0,End的值設為math.MaxInt64,將該Message發送給節點,就可以觸發make函數的capoutofrange,導致拒絕服務。
POC見https://github.com/fatal0/poc/blob/master/go-iost/p2p_dos.go
漏洞修復
官方的修復方式也很簡單,限制end-start1的大小。
https://github.com/iost-official/go-iost/commit/9824cfce3bb4b14f43b60f470cbba86e879dd32a#diff-4e27320b328b8f0d452f10e1ed383d73R330
作者|MarcHoward 編譯|Guoxi 出品|區塊鏈大本營 玩過股票的人都知道,股票市場的波動受各種因素的共同影響,有著很強的隨機性,很難預測.
1900/1/1 0:00:00尊敬的ZG.TOP用戶:ZG.TOP“搶購點卡送ZGT活動”第二天順利完成!再次感謝每一位新老用戶的參與,感謝各位對我們的信任和支持!4月25日將是“搶購點卡送ZGT活動”的最后一天.
1900/1/1 0:00:00各位朋友們如果有認真看過哈希君前兩天的推文的話,應該還記得哈希君說過“剪刀差”這么個概念。就是說現在“比特幣”和“區塊鏈”的搜索熱度出現了你高我低的現象.
1900/1/1 0:00:00好了,經過前面幾節課程的學習,大家對比特幣及其區塊鏈的基本概念有了初步的理解了吧!那么新的問題來了,比特幣是怎么交易的呢?今天我們來講講比特幣的交易機制的問題吧!大家都知道.
1900/1/1 0:00:004月28日,火幣發布官方公告:火幣全球站將于新加坡時間5月9日20:00通過火幣優選通道極速版上線首期項目ThunderCore(TT),并正式確定了交易規則.
1900/1/1 0:00:00Gate.io的理財和借貸市場是一個用戶對用戶的借貸平臺,平臺不參與任何借貸和放貸。市場出現大幅波動的時候,就會出現因為市場借貸需求增長同時提供理財借出的資金不足而造成的市場無幣可借的問題.
1900/1/1 0:00:00