Malicious callers can replay change orders #339
Labels
3 (High Risk)
Assets can be stolen/lost/compromised directly
bug
Something isn't working
duplicate
This issue or pull request already exists
sponsor confirmed
Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity")
valid
Lines of code
https://github.com/code-423n4/2022-08-rigor/blob/5ab7ea84a1516cb726421ef690af5bc41029f88f/contracts/Project.sol#L386
https://github.com/code-423n4/2022-08-rigor/blob/5ab7ea84a1516cb726421ef690af5bc41029f88f/contracts/Project.sol#L449
https://github.com/code-423n4/2022-08-rigor/blob/5ab7ea84a1516cb726421ef690af5bc41029f88f/contracts/libraries/Tasks.sol#L160
Vulnerability details
Unlike some of the other signature based operations in the Rigor system, change order signatures do not include a nonce
and are vulnerable to replay attacks. A number of exploits are possible using replayed
change orders, including subcontractors extracting multiple payments for the same task, subcontractors extracting excess
payment for a single task, and denial of service/griefing of competing subcontractors to prevent them from completing tasks.
The worst of these attacks require the attacker to engineer or observe specific changes to both tasks and the project budget, e.g.
multiple change orders at different amounts for the same task. However, these conditions do not seem unreasonable in the context
of an active construction project, where change orders are common and tasks often cost more than originally estimated. Moreover,
the more active the project, the more possibilities there will be for a malicious caller to find a sequence of replays that may be exploited.
I've come up with a few examples below, but I suspect there are additional scenarios where change order replays may be exploited
in unexpected ways.
Scenarios
Multiple payments for the same task
In this scenario, the attacker exploits multiple change orders and the state of the project budget to claim payment for a
task multiple times.
come in under budget! She will only need 3,000 DAI. Since Mallory is establishing a trusted subcontractor relationship with Bob,
and may be bidding for other tasks, it's in her interest to allow the project to reclaim and reallocate the excess amount.
setComplete
transaction. Mallory is paid 3,000 DAI.addTasks
to create these additional tasks, Mallory callschangeOrder
and replays the 10,000 DAI changeorder from step 4. (If Mallory is a sophisticated attacker, she may watch for Bob's transaction in the mempool and frontrun
it, or perhaps she just follows project updates off chain and has knowledge of when Bob will add more tasks).
be marked unapproved
and transition back to the
Inactive
state when the change order is replayed.new tasks, her task will become
Active
and funded.setComplete
transaction from step 8 to complete task 1 for a second time and extract 10,000 DAI.Mallory has extracted 13,000 DAI total rather than 3,000 DAI for task 1.
Impact: Malicious subcontractors may complete tasks multiple times to steal project funds from other tasks. If a given task
has had multiple change orders at multiple prices, this attack may be repeated multiple times.
Excess payment for a single task
Steps 1-7 here are the same as the previous example: Mallory engineers a scenario where a task has multiple change orders at
different total costs. This attack is easier because she does not need to monitor the project budget to force her task into
the unapproved state. Instead, she simply claims payment for the task once at the higher price.
come in under budget! She will only need 3,000 DAI. Since Mallory is establishing a trusted subcontractor relationship with Bob,
and may be bidding for other tasks, it's in her interest to allow the project to reclaim and reallocate the excess amount.
setComplete
transaction.setComplete
transaction, replays the 10,000 DAI change order from step 4, and re-accepts the task.Impact: Malicious subcontractors may extract more payment than agreed for a specific task by replaying past change orders.
Denial of service/griefing of subcontractors
In this scenario, a malicious user can replay past change orders to block or grief an honest subcontractor claiming payment.
setComplete
transaction.setComplete
transaction and replays a previous change order.7a. If the cost of the replayed change order is above the final cost of the task, Alice may be blocked from claiming payment.
7b. If the cost of the replayed change order is below the final cost of the task, Alice will receive less payment than agreed.
Impact: Honest contractors may be blocked from accepting payment or griefed by malicious users replaying change orders.
Test cases
Add the following examples to
test/utils/projectTests.ts
.Multiple payments
Excess payment
Dos/Griefing
Recommendation
I recommend several defense-in-depth changes to prevent these scenarios.
First and most important, add a nonce to change order data and verify it in
changeOrder
, similar to the implementation in other functions lkeupdateTaskHash
:Project#changeOrder
:Second, prevent
Completed
tasks from transitioning back to other states:Tasks#unApprove
(You may also be able to do this using the
onlyActive
modifier).Finally, if third parties are not intended to submit signatures on behalf of the builder/contractor/subcontractor,
ensure that
_msgSender()
matches one of the recovered message signers incheckSignatureTask
:Project#checkSignatureTask
The text was updated successfully, but these errors were encountered: