Zcash遮蔽地址漏洞或揭示全節點IP地址(附解決方案)

買賣虛擬貨幣

作者:灑脫喜

匿名幣的技術之爭是非常有意思的,比如KMD核心開發者Duke Leto剛發表了一篇部落格文章,披露了關於Zcash及其多數分叉幣存在的漏洞,而這個漏洞可能會洩露使用遮蔽地址(zaddr)的全節點 IP地址。

其還為此分配了一個通用漏洞披露(CVE)編碼CVE-2019-16930來跟蹤這一問題。

(以下是其具體披露的內容)

太長不看:自Zcash和Zcash協議建立以來,所有遮蔽地址都存在著一個漏洞。它出現在所有Zcash原始碼分叉中,這使得攻擊者可利用它找到擁有遮蔽地址(zaddr)全節點的ip地址。換而言之,如果Alice給Bob一個遮蔽地址(zaddr)用於支付,實際上可允許Bob發現Alice的IP地址,這與Zcash協議的設計是違背的。

受影響的群體:

所有使用遮蔽地址(zaddr)以及與第三方共享遮蔽地址(zaddr)的人,例如:

  1. 如果你在社交媒體上公開發布了你的遮蔽地址(zaddr);

  2. 如果你在github/email/IRC的漏洞報告中給出了你的遮蔽地址(zaddr);

  3. 如果你曾把自己的遮蔽地址(zaddr)告訴了交易所、礦池或企業;

  4. 如果你曾在一份遮蔽備忘錄中回覆過你的遮蔽地址(zaddr);

不受漏洞影響的群體:

如果你從未使用過zaddr,那漏洞就不會影響到你:

  1. 如果你只是給其他使用zaddr的人傳送過錢,但從未收到過資金,你是安全的;

  2. 如果你使用Tor/TAILS,則IP後設資料洩漏對攻擊者而言就不是有價值的資訊。

受影響的加密貨幣(非詳盡清單):

  1. Zcash (ZEC)

  2. Hush (HUSH)

  3. Pirate (ARRR)

  4. 所有帶有zaddr的Komodo (KMD)智慧鏈(預設啟用)

  5. Horizen (ZEN)

  6. Zero (ZER)

  7. VoteCoin (VOT)

  8. Snowgem (XSG)

  9. BitcoinZ (BTCZ)

  10. LitecoinZ (LTZ)

  11. Zelcash (ZEL)

  12. Ycash (YEC)

  13. Arrow (ARW)

  14. Verus (VRSC)

  15. BitcoinPrivate (BTCP)

  16. ZClassic (ZCL)

  17. Anon (ANON)

需要澄清的是,雖然Bitcoin Gold (BTG)使用了Zcash提供的Equihash PoW共識機制,但它並不是Zcash原始碼的分叉,其也沒有使用遮蔽地址(zaddr),因此它是不受影響的。

額外的說明:KMD以前也有使用遮蔽地址(zaddr),但後來禁用了該功能,Safecoin (SAFE)走了一條類似的路線,其目前也禁用了遮蔽地址(zaddr)。

緩解措施

首先,防止這種“後設資料洩漏攻擊”的首要方法,是在使用你喜歡的加密貨幣的同時,透過-onlynet=onion使用Tor,或者更好的選擇,是使用TAILS作業系統。

其次,使用者可使用全新的zaddr建立一個全新的wallet.dat(錢包檔案),然後將所有資金髮送到該地址。如果使用者將這個新的zaddr保持為私有狀態,那它就不會受到此類攻擊。

Zcash在這裡釋出了一個緊急原始碼(沒有二進位制檔案)。

如果你不希望知道你的zaddr地址的人知道你的IP地址,我建議你建立新的錢包,並在軟體釋出更新之前停止使用舊錢包。

到這裡,普通使用者或許可以停止閱讀了。

更多的建議

如果你執行了一個支援遮蔽地址(zaddr)的礦池,則不需要提供所有礦工和遮蔽地址(zaddr)的公開列表。由於當前的後設資料洩漏攻擊和其他原因,這嚴重地消除了礦工們的隱私。這在過去是很常見的,但由於隱私問題,大多數礦池已經停止了這一做法。

也不要在github的錯誤報告中給出zaddr!很多工具不斷地從所有公共程式碼儲存庫中抽取潛在的敏感資料和公開來源資訊。

為了提高安全性,如果你必須要給出遮蔽地址(zaddr),你可以將它們隔離到一個單獨的wallet.dat,該wallet.dat通常不使用且保持離線狀態,而另一個帶有遮蔽地址(zaddr)的錢包可用於傳送資金。由於傳送資金的錢包從未發出zaddr,因此這種型別的漏洞對於該節點而言是不可被利用的。

程式碼分析

這個漏洞是在最初的Zcash程式碼庫中被引入的,相關提交時間是在2016年:

“介紹新的“libzcash”zcash協議API和圍繞zkSNARK電路的加密結構。”

這一提交將漏洞程式碼新增到了較舊版本的遮蔽地址,而新版本的遮蔽地址程式碼都將其複製了進去。

該漏洞存在於Zcash的P2P層(從比特幣繼承而來)中,其中節點會與對等節點交換資料。

對攻擊的解釋:

  1. 攻擊者節點將無效交易中繼至其對等節點的mempool;

  2. 此交易對加密memo欄位具有無效的序列化;

  3. 沒有私鑰且沒有遮蔽地址檢視金鑰的節點,通常會對此無效交易做出反應;

  4. 具有私鑰(或檢視金鑰)的節點將生成C++異常;

  5. 這個C++異常會導致不同的網路行為,從而暴露節點的“身份”;

  6. 區塊鏈或瀏覽器上沒有此類攻擊的記錄;

修正漏洞的程式碼在這裡:

https://github.com/zcash/zcash/commit/c1fbf8ab5d73cff5e1f45236995857c75ba4128d

核心修改如下:

-    CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
-    ss << pt.get(); -      SaplingNotePlaintext ret; -    ss >> ret;
+    try {
+        CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
+        ss << pt.get(); +        ss >> ret;
+        assert(ss.size() == 0);
+    } catch (const boost::thread_interrupted&) {
+        throw;
+    } catch (...) {
+        return boost::none;
+    }

下面這行程式碼沒有try/catch是漏洞存在的核心原因:

ss << pt.get();

由於pt是由攻擊者控制的資料,其正被寫入本地CDataStream ss物件,因此需要更仔細的處理。

現在我們可以看到,只有boost::thread_interrupted型別的異常冒泡,所以其他異常都被“消滅”了,boost::none則會返回。這使得具有zaddr地址私鑰的節點與所有其他節點一樣,可以防止後設資料洩露。

作者注意到,這裡仍然存在尋找舊Sprout地址的易受攻擊的程式碼。

有人可能認為這種攻擊只能針對節點的對等節點,而不能針對整個網路,但增加最大對等節點計數是微不足道的,透過一個或幾個節點來研究整個網路是可行的。

高階攻擊者將擁有一個他們想要連線IP的zaddr資料庫,然後執行密集連線至整個網路的節點,並定期向所有對等節點的mempool傳送無效交易,從而建立(時間戳、Zaddr、IP地址)的三元組資料歷史記錄。然後,他們就可以使用這些資料,並透過數量分析和定時分析將其連結到其他資料,以完全取消遮蔽交易的匿名性,並將它們直接與IP地址和地理位置相繫結。

免責聲明:

  1. 本文版權歸原作者所有,僅代表作者本人觀點,不代表鏈報觀點或立場。
  2. 如發現文章、圖片等侵權行爲,侵權責任將由作者本人承擔。
  3. 鏈報僅提供相關項目信息,不構成任何投資建議

推荐阅读

;