Unix time unlock_time values have dangerous validation rules enabling a number of exploits
High
M
Monero
Submitted None
Actions:
Reported by
thecharlatan
Vulnerability Details
Technical details and impact analysis
*Initially found by TheCharlatan, discussed with and expanded on by Isthmus, impacts all releases of monero and monero wallets*
## Description
The unlock_time field in monero transaction dictates when a transaction's outputs can be spent again. This rule is enforced by the consensus code in https://github.com/monero-project/monero/blob/master/src/cryptonote_core/blockchain.cpp#L3478 . The rule has two parts. If the unlock_time is below 500000000, it is interpreted as a block height and compared with the current block height. If the unlock_time in a used transaction input's previous output is below the current block height, a transaction using that output is valid. Otherwise it is invalid and not relayed.
If the unlock time is above 500000000, then it is interpreted as unix time in seconds. However, the unlock_time is not compared to the network or rather block time, but to the local time of the machine running the monero node. Using this local time is potentially problematic for the following reasons.
## Exploits
Through consuming outputs locked by carefully chosen unlock_time values, it is possible to poll the local time of other nodes. The attacker can generate any number of transactions encumbered with a spread of unlock_time values, for example with an unlock_time 20 blocks per the expected block time into the future and then spread out over intervals of seconds. The attacker then creates transactions consuming these locked outputs and connects two nodes to the node she wants to spy on. She sends the transaction from one of the nodes to the node she wants to spy on and then checks if the other node receives the transaction. If the consumed unlock_time is invalid by the consensus rules for the attacker and the greater network, but valid for the surveiled node, the attacker will get the transaction relayed to her other node as well. This then indicates that the local time on the surveiled node matches the time on the attacker's transaction. Using a binary search methodology, the attacker can then pinpoint the node's time within a precision of seconds.
If such a node is found with a different clock (running late or early), or if the attacker can manipulate a node's local time through another channel, we identified two additional ways to exploit the current unlock_time validation.
Assume that a node has a clock running forward (showing a higher unix time). The attacker then creates a transaction consuming at least one output with a high enough unlock_time that it is invalid by the clocks of most node's on the netowrk, but valid for the node where the clock runs forward. If the attacker relays this transaction to the victim's node, the node will validate it as a valid transaction. This is especially useful for the attacker in the context of mining. For Example if the victim's node is a large mining pool, this can be used to make the pool expend work on a block that is not valid with the locked transaction included by the consensus rules of the rest of the network. If the attacker is a mining pool herself, she can use this to increase her profit.
If a node has a clock running behind (showing a lower unix time), the attacker can trick it into thinking that a chain that is valid by the rest of the network's consensus rules, is invalid to the attacked node. By continuously submitting transactions consuming an unlock_time encumbered output with a value just later than the victim node's clock, the node will never accept the network's best chain as valid. This would be a very effective way for an eclipse attack, even allowing the attacker enough time to feed it a "slower" malicious chain without expending too much proof of work.
## Recommendations
We believe that these scenarios are serious enough to warrant a change away from the current consensus rules for interpreting unix time unlock_time values. Consensus rules must react to consensus variables (e.g. miner-reported block time). The local time should not be taken into account any more. Instead, an aggregation of previous block time values should be used.
A similar problem existed in bitcoin's nlocktime field. However this problem was less serious at the time, since the nlocktime semantics are different compared to monero's unlock_time (nlocktime's influence is on the finality of the transaction itself, not a later transaction), and since the last block's timestamp was used instead. It was fixed through BIP113: https://github.com/bitcoin/bips/blob/master/bip-0113.mediawiki , by using the median timestamp of the past 11 blocks to determine if an unlock time is valid. The fix was also a required step for the deployment of the CSV and CLTV opcodes, which adopt a similar output locking mechanism to the one of monero's unlock_time.
We therefore propose to also use the median timestamp over the past 60 blocks as calculated in https://github.com/monero-project/monero/blob/master/src/cryptonote_core/blockchain.cpp#L3592 , to verify the unlock_time. In fact, it looks like the cryptonote developers intended to implement something along these lines by reading both the function signatures and the comments around this line. Currently this median is used to check that a new block's timestamp is strictly increasing compared to the median. A proof of concept patch was written to use this median timestamp calculation in the unlock time.
Since the exploits do not require changes to the monero software, but rather some minor scripting work to generate the locked transactions, no proof of concept is provided.
## Patch:
We provide a proof of concept patch to the validation code and the wallet code in monero. This should be tested extensively before deploying, since it touches key functionality of monero. We also provide a patch to the wallet code, however this needs some additional discussion, since it touches quite a few unrelated components in its current form.
## Impact
Without any additional assumptions, the attacker can get the local time of another node.
Under the assumption that a node's local time is off, the attacker is able to launch an eclipse attack.
Additionally, if the node is mining, the attack can diminish its profit.
Report Details
Additional information and metadata
State
Closed
Substate
Resolved
Submitted
Weakness
Business Logic Errors