門羅幣(XMR)鎖定轉賬攻擊細節分析

買賣虛擬貨幣
近日據慢霧區情報顯示,針對門羅幣(XMR)轉賬鎖定攻擊在多個交易所出現,慢霧安全團隊在收到情報第一時間進行分析跟進,本著負責任披露的原則我們第一時間在慢霧區進行了預警併為我們所服務的客戶進行了及時的情報同步以及協助檢測和修復。如有其他需要提供驗證和檢測服務歡迎聯絡慢霧安全團隊。攻擊步驟0x01:透過 monero-wallet-cli 輸入密碼登入錢包0x02:透過命令傳送鎖定交易0x03:轉賬完成,交易所未進行鎖定交易(locked_transfer)檢測,接收到被設定鎖定區塊高度才能解鎖的幣(可以理解為鎖定了指定時間)。0x04:惡意使用者立即提幣走人,留下交易所一臉懵逼。
造成影響首先該攻擊不會導致交易所任何資金損失,但是會鎖定了交易所 XMR 流動性。極端情況舉例:如果交易所收到的都是需要鎖定一年甚至更多年的門羅幣則會導致一年內使用者來提幣的時候無幣可以提(只能去購買額外的幣來給使用者提取)。關於 locked_transfer 命令monero-wallet-cli 關於 locked_transfer 命令解釋如下:locked_transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] (<URI> | <addr> <amount>) <lockblocks> [<payment_id (obsolete)>]
轉賬命令:locked_transfer FromAddress ToAddress 0.0101 20000 FromAddress:傳送地址(一般為攻擊者錢包地址)ToAddress:接收地址(一般為交易所錢包地址)0.0101:為轉賬金額20000:為鎖定區塊數
如何防護一般交易所會透過 get_transfers RPC 介面來解析 XMR 交易檢測充值是否到賬,在進行解析的時候只需要對 unlock_time 欄位進行判斷是否大於 0 則可以進行有效檢測。注:unlock_time 為 int 型別,如果大於 0 則意味著該交易有鎖定區塊,為惡意交易可以不予確認到賬。為了避免充值不予到賬損害“使用者”利益可以進行另外一種處理:判斷鎖定區塊是否到達,如果未到達則不予入賬。所有受影響 RPC 介面(1)get_transfer(2)get_bulk_payments
(3)show_transfer(4)get_payments同理:在其他地方使用瞭如上四個介面的地方也需要對 unlock_time 欄位進行判斷是否大於 0 ,大於 0 則不予充值到賬。

該問題之前在 HackerOne 也有被白帽子提過漏洞賞金,其中門羅官方回覆:

附:以下內容為官方文件摘錄

get_transfers

Returns a list oftransfers.
Alias: None.
Inputs:
· in - boolean;     (Optional) Include incoming transfers.
· out - boolean;     (Optional) Include outgoing transfers.
· pending - boolean;     (Optional) Include pending transfers.
· failed - boolean;     (Optional) Include failed transfers.
· pool - boolean;     (Optional) Include transfers from the daemon's transaction pool.
· filter_by_height - boolean;     (Optional) Filter transfers by block height.
· min_height - unsigned     int; (Optional) Minimum block height to scan for transfers, if filtering     by height is enabled.
· max_height - unsigned     int; (Opional) Maximum block height to scan for transfers, if filtering by     height is enabled (defaults to max block height).
· account_index - unsigned     int; (Optional) Index of the account to query for transfers. (defaults to     0)
· subaddr_indices - array of     unsigned int; (Optional) List of subaddress indices to query for     transfers. (Defaults to empty - all indices)

Outputs:

· in array of     transfers:
  · address - string;      Public address of the transfer.
  · amount - unsigned      int; Amount transferred.
  · confirmations -      unsigned int; Number of block mined since the block containing this      transaction (or block height at which the transaction should be added to      a block if not yet confirmed).
  · double_spend_seen -      boolean; True if the key image(s) for the transfer have been seen before.
  · fee -      unsigned int; Transaction fee for this transfer.
  · height -      unsigned int; Height of the first block that confirmed this transfer (0      if not mined yet).
  · note - string;      Note about this transfer.
  · payment_id - string;      Payment ID for this transfer.
  · subaddr_index - JSON      object containing the major & minor subaddress index:
      major -       unsigned int; Account index for the subaddress.
      minor -       unsigned int; Index of the subaddress under the account.
  · suggested_confirmations_threshold -      unsigned int; Estimation of the confirmations needed for the transaction      to be included in a block.
  · timestamp -      unsigned int; POSIX timestamp for when this transfer was first confirmed      in a block (or     · timestamp submission if not mined yet).
  ·txid - string;      Transaction ID for this transfer.
  ·type - string;      Transfer type: "in"
  ·unlock_time - unsigned int; Number of blocks until transfer is safely      spendable.
·out array of     transfers (see above).
·pending array of     transfers (see above).
·failed array of     transfers (see above).
·pool array of transfers (see above).

Example:

$ curl -X POST http://127.0.0.1:18082/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"get_transfers","params":{"in":true,"account_index":1}}' -H 'Content-Type: application/json'
{
  "id": "0",
  "jsonrpc": "2.0",
  "result": {
    "in": [{
      "address": "77Vx9cs1VPicFndSVgYUvTdLCJEZw9h81hXLMYsjBCXSJfUehLa9TDW3Ffh45SQa7xb6dUs18mpNxfUhQGqfwXPSMrvKhVp",
      "amount": 200000000000,
      "confirmations": 1,
      "double_spend_seen": false,
      "fee": 21650200000,
      "height": 153624,
      "note": "",
      "payment_id": "0000000000000000",
      "subaddr_index": {
        "major": 1,
        "minor": 0
      },
      "suggested_confirmations_threshold": 1,
      "timestamp": 1535918400,
      "txid": "c36258a276018c3a4bc1f195a7fb530f50cd63a4fa765fb7c6f7f49fc051762a",
      "type": "in",
      "unlock_time": 0
    }]
  }
}

get_payments

Get a list ofincoming payments using a given payment id.
Alias: None.
Inputs:

· payment_id - string;     Payment ID used to find the payments (16 characters hex).
Outputs:
· payments - list of:
  · payment_id - string;      Payment ID matching the input parameter.
  · tx_hash - string;      Transaction hash used as the transaction ID.
  · amount - unsigned      int; Amount for this payment.
  · block_height -      unsigned int; Height of the block that first confirmed this payment.
  · unlock_time - unsigned int; Time (in block height) until      this payment is safe to spend.
  ·subaddr_index -      subaddress index:
     major - unsigned       int; Account index for the subaddress.
     minor -       unsigned int; Index of the subaddress in the account.
· address - string;      Address receiving the payment; Base58 representation of the public keys.

Example:

$ curl -X POST http://127.0.0.1:18082/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"get_payments","params":{"payment_id":"60900e5603bf96e3"}}' -H 'Content-Type: application/json'
{
  "id": "0",
  "jsonrpc": "2.0",
  "result": {
    "payments": [{
      "address": "55LTR8KniP4LQGJSPtbYDacR7dz8RBFnsfAKMaMuwUNYX6aQbBcovzDPyrQF9KXF9tVU6Xk3K8no1BywnJX6GvZX8yJsXvt",
      "amount": 1000000000000,
      "block_height": 127606,
      "payment_id": "60900e5603bf96e3",
      "subaddr_index": {
        "major": 0,
        "minor": 0
      },
      "tx_hash": "3292e83ad28fc1cc7bc26dbd38862308f4588680fbf93eae3e803cddd1bd614f",
      "unlock_time": 0
    }]
  }
}

get_bulk_payments

Get a list ofincoming payments using a given payment id, or a list of payments ids, from agiven height. This method is the preferred method over get_paymentsbecause it has the same functionality butis more extendable. Either is fine for looking up transactions by a singlepayment ID.

Alias: None.

Inputs:

· payment_ids - array     of: string; Payment IDs used to find the payments (16 characters hex).
· min_block_height - unsigned     int; The block height at which to start looking for payments.

Outputs:

·payments - list of:
  · payment_id - string;      Payment ID matching one of the input IDs.
  · tx_hash - string;      Transaction hash used as the transaction ID.
  · amount -      unsigned int; Amount for this payment.
  · block_height -      unsigned int; Height of the block that first confirmed this payment.
  ·unlock_time - unsigned int; Time (in block height) until      this payment is safe to spend.
  · subaddr_index - subaddress      index:
      major -       unsigned int; Account index for the subaddress.
      minor -       unsigned int; Index of the subaddress in the account.
  · address - string;      Address receiving the payment; Base58 representation of the public keys.

Example:

$ curl -X POST http://127.0.0.1:18082/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"get_bulk_payments","params":{"payment_ids":["60900e5603bf96e3"],"min_block_height":"120000"}}' -H 'Content-Type: application/json'
{
  "id": "0",
  "jsonrpc": "2.0",
  "result": {
    "payments": [{
      "address": "55LTR8KniP4LQGJSPtbYDacR7dz8RBFnsfAKMaMuwUNYX6aQbBcovzDPyrQF9KXF9tVU6Xk3K8no1BywnJX6GvZX8yJsXvt",
      "amount": 1000000000000,
      "block_height": 127606,
      "payment_id": "60900e5603bf96e3",
      "subaddr_index": {
        "major": 0,
        "minor": 0
      },
      "tx_hash": "3292e83ad28fc1cc7bc26dbd38862308f4588680fbf93eae3e803cddd1bd614f",
      "unlock_time": 0
    }]
  }
}

get_transfer_by_txid

Show informationabout a transfer to/from this address.
Alias: None.

Inputs:

· txid - string;     Transaction ID used to find the transfer.
· account_index - unsigned     int; (Optional) Index of the account to query for the transfer.

Outputs:

·transfer - JSON     object containing payment information:
  ·address - string;      Address that transferred the funds. Base58 representation of the public      keys.
  ·amount -      unsigned int; Amount of this transfer.
  ·confirmations -      unsigned int; Number of block mined since the block containing this      transaction (or block height at which the transaction should be added to      a block if not yet confirmed).
  ·destinations - array      of JSON objects containing transfer destinations:
    ·amount -       unsigned int; Amount transferred to this destination.
    ·address -       string; Address for this destination. Base58 representation of the public       keys.
  ·double_spend_seen -      boolean; True if the key image(s) for the transfer have been seen before.
  ·fee -      unsigned int; Transaction fee for this transfer.
  ·height -      unsigned int; Height of the first block that confirmed this transfer.
  ·note - string;      Note about this transfer.
  ·payment_id - string;      Payment ID for this transfer.
  ·subaddr_index - JSON      object containing the major & minor subaddress index:
     major -       unsigned int; Account index for the subaddress.
     minor -       unsigned int; Index of the subaddress under the account.
  ·suggested_confirmations_threshold -      unsigned int; Estimation of the confirmations needed for the transaction      to be included in a block.
  ·timestamp -      unsigned int; POSIX timestamp for the block that confirmed this transfer      (or timestamp submission if not mined yet).
  ·txid - string;      Transaction ID of this transfer (same as input TXID).
  ·type - string;      Type of transfer, one of the following: "in", "out",      "pending", "failed", "pool"
  ·unlock_time - unsigned int; Number of blocks until      transfer is safely spendable.

Example:

$ curl -X POST http://localhost:18082/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"get_transfer_by_txid","params":{"txid":"c36258a276018c3a4bc1f195a7fb530f50cd63a4fa765fb7c6f7f49fc051762a"}}' -H 'Content-Type: application/json'
{
  "id": "0",
  "jsonrpc": "2.0",
  "result": {
    "transfer": {
      "address": "55LTR8KniP4LQGJSPtbYDacR7dz8RBFnsfAKMaMuwUNYX6aQbBcovzDPyrQF9KXF9tVU6Xk3K8no1BywnJX6GvZX8yJsXvt",
      "amount": 300000000000,
      "confirmations": 1,
      "destinations": [{
        "address": "7BnERTpvL5MbCLtj5n9No7J5oE5hHiB3tVCK5cjSvCsYWD2WRJLFuWeKTLiXo5QJqt2ZwUaLy2Vh2Ad51K7FNgqcHgjW85o",
        "amount": 100000000000
      },{
        "address": "77Vx9cs1VPicFndSVgYUvTdLCJEZw9h81hXLMYsjBCXSJfUehLa9TDW3Ffh45SQa7xb6dUs18mpNxfUhQGqfwXPSMrvKhVp",
        "amount": 200000000000
      }],
      "double_spend_seen": false,
      "fee": 21650200000,
      "height": 153624,
      "note": "",
      "payment_id": "0000000000000000",
      "subaddr_index": {
        "major": 0,
        "minor": 0
      },
      "suggested_confirmations_threshold": 1,
      "timestamp": 1535918400,
      "txid": "c36258a276018c3a4bc1f195a7fb530f50cd63a4fa765fb7c6f7f49fc051762a",
      "type": "out",
      "unlock_time": 0
    }
  }
}

免責聲明:

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

推荐阅读

;