Project funds can be drained by reusing signatures, in some cases #95
Labels
3 (High Risk)
Assets can be stolen/lost/compromised directly
bug
Something isn't working
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-L490
https://github.com/code-423n4/2022-08-rigor/blob/5ab7ea84a1516cb726421ef690af5bc41029f88f/contracts/Project.sol#L330-L359
https://github.com/code-423n4/2022-08-rigor/blob/5ab7ea84a1516cb726421ef690af5bc41029f88f/contracts/libraries/Tasks.sol#L153-L164
Vulnerability details
This attack path is the results of signatures reusing in 2 functions -
changeOrder()
andsetComplete()
, and a missing modifier atTasks.unApprove()
library function.Impact
Draining the project from funds
Current or previous subcontractor of a task can drain the project out of its funds by running
setComplete()
multiple times.This can be exploited in 3 scenarios:
totalLent - _totalAllocated
, and therefore gets unapproved), and than changed back to the original price (or any price that's not higher than available funds)changeOrder
and then changed back to the original subcontractorAfter
setComplete()
ran once by the legitimate users (i.e. signed by contractor, SC and builder), the attackers can now run it multiple times:changeOrder()
- changing SC or setting the price to higher than available fundschangeOrder()
, reusing signaturesallocateFunds()
to mark it as funded againacceptInvite()
to mark task as activesetComplete()
reusing signaturesChanging tasks costs/subcontractor by external users
This can also be used by external users (you don't need to be builder/GC/SC in order to run
changeOrder()
) to troll the system (This still requires the task to be changed at least twice, otherwise re-runningchangeOrder()
with the same data would have no effect).setComplete()
function)Proof of Concept
Since the tests depend on each other, the PoC tests were created by adding them to the file
test/utils/projectTests.ts
, after the functionit('should be able to complete a task'
( Line 1143 ).In the first test - a subcontractor is changed and then changed back.
In the second scenario a price is changed to the new price (that is higher than the total available funds, and therefore is unapproved) and then back to its original price (it can actually be any price that is not higher than the available funds).
In both cases I'm demonstrating how the project can be drained out of fund,
Tools Used
Hardhat
Recommended Mitigation Steps
setComplete()
andchangeOrder()
from signatures reuseonlyActive()
modifier toTasks.unApprove()
allocateFunds()
for builder only (this is not necessary to resolve the bug, just for hardening security)The text was updated successfully, but these errors were encountered: