近日據(jù)慢霧區(qū)情報(bào)顯示,針對(duì)門(mén)羅幣(XMR)轉(zhuǎn)賬鎖定攻擊在多個(gè)交易所出現(xiàn),慢霧安全團(tuán)隊(duì)在收到情報(bào)第一時(shí)間進(jìn)行分析跟進(jìn),本著負(fù)責(zé)任披露的原則我們第一時(shí)間在慢霧區(qū)進(jìn)行了預(yù)警并為我們所服務(wù)的客戶(hù)進(jìn)行了及時(shí)的情報(bào)同步以及協(xié)助檢測(cè)和修復(fù)。
攻擊步驟
0x01:通過(guò) monero-wallet-cli 輸入密碼登錄錢(qián)包
0x02:通過(guò)命令發(fā)送鎖定交易
0x03:轉(zhuǎn)賬完成,交易所未進(jìn)行鎖定交易(locked_transfer)檢測(cè),接收到被設(shè)置鎖定區(qū)塊高度才能解鎖的幣(可以理解為鎖定了指定時(shí)間)。
0x04:惡意用戶(hù)立即提幣走人,留下交易所一臉懵逼。
造成影響
首先該攻擊不會(huì)導(dǎo)致交易所任何資金損失,但是會(huì)鎖定了交易所 XMR 流動(dòng)性。
極端情況舉例:如果交易所收到的都是需要鎖定一年甚至更多年的門(mén)羅幣則會(huì)導(dǎo)致一年內(nèi)用戶(hù)來(lái)提幣的時(shí)候無(wú)幣可以提(只能去購(gòu)買(mǎi)額外的幣來(lái)給用戶(hù)提取)。
關(guān)于 locked_transfer 命令
monero-wallet-cli 關(guān)于 locked_transfer 命令解釋如下:
locked_transfer [index=《N1》[,《N2》,。..]] [《priority》] [《ring_size》] (《URI》 | 《addr》 《amount》) 《lockblocks》 [《payment_id (obsolete)》]
轉(zhuǎn)賬命令:
locked_transfer FromAddress ToAddress 0.0101 20000
FromAddress:發(fā)送地址(一般為攻擊者錢(qián)包地址)
ToAddress:接收地址(一般為交易所錢(qián)包地址)
0.0101:為轉(zhuǎn)賬金額
20000:為鎖定區(qū)塊數(shù)
如何防護(hù)
一般交易所會(huì)通過(guò) get_transfers RPC 接口來(lái)解析 XMR 交易檢測(cè)充值是否到賬,在進(jìn)行解析的時(shí)候只需要對(duì) unlock_time 字段進(jìn)行判斷是否大于 0 則可以進(jìn)行有效檢測(cè)。
注:unlock_time 為 int 類(lèi)型,如果大于 0 則意味著該交易有鎖定區(qū)塊,為惡意交易可以不予確認(rèn)到賬。為了避免充值不予到賬損害“用戶(hù)”利益可以進(jìn)行另外一種處理:判斷鎖定區(qū)塊是否到達(dá),如果未到達(dá)則不予入賬。
所有受影響 RPC 接口
(1)get_transfer
(2)get_bulk_payments
(3)show_transfer
(4)get_payments
同理:在其他地方使用了如上四個(gè)接口的地方也需要對(duì) unlock_time 字段進(jìn)行判斷是否大于 0 ,大于 0 則不予充值到賬。
該問(wèn)題之前在 HackerOne 也有被白帽子提過(guò)漏洞賞金,其中門(mén)羅官方回復(fù):
附:以下內(nèi)容為官方文檔摘錄
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”: “7BnERTpvL5MbCLtj5n9No7J5oE5hHiB3tVCK5cjSvCsYWD2WRJLFuWeKTLiXo5QJqt2ZwUaLy2Vh1Ad51K7FNgqcHgjW85o”,
“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
}
}
}
評(píng)論
查看更多