You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
gavofyork opened this issue
Jun 19, 2020
· 1 comment
Labels
D1-mediumCan be fixed by a coder with good Rust knowledge but little knowledge of the codebase.T1-FRAMEThis PR/Issue is related to core FRAME, the framework.T10-testsThis PR/Issue is related to tests.
Basically a test for paritytech/substrate#6445; will require a pallet with interior dispatch mutability in order to call the cancel_as_multi from the as_multi dispatcher.
Exploit
When starting a multisig transaction with threshold >= 2, a certain amount of your balance will be reserved as a deposit (and unreserved once the multisig transaction is executed or cancelled). However, the implementation of as_multi and cancel_as_multi has no protection against re-entrance. So if the call argument to as_multi somehow triggers a cancel_as_multi for the same multisig transaction, the deposit will be unreserved twice. With normal pallets this is not possible since the cancel_as_multi call will need the call_hash argument and this call_hash must be a hash of an encoded call to cancel_as_multi with the same call_hash, which is computationally infeasible to find assuming that the hash function (blake2_256) is cryptographically secure.
However, the multisig call could call a smart contract, which will load the call_hash and timepoint arguments from its storage and then call cancel_as_multi via env.dispatch_call.
Exploit outline:
Create two account ids (account1 and account2) with sufficient funds to pay transaction fees as required (account2 may also be a sub-account of account1 so that only one funded account is required)
Calculate multisig account id for these two accounts with threshold=2
As account1: Do some operations (in other pallets) which legitimately require reserving a deposit
Give the multisig account proxy permission (ProxyType::Any) to access account1
As account1: Create a smart contract which allows calling cancel_as_multi with the parameters timepoint and call_hash stored in the storage of the smart contract
As account1: Start a multisig transaction via approve_as_multi. This will reserve some balance of account1 as a deposit. The call_hash corresponds to the following call: as_proxy(account1) => contracts.call.
Get the timepoint and call_hash parameters from the multisig transaction and store these values in the storage of the smart contract.
As account2 trigger the multisig transaction by calling as_multi
During the call from as_multi to call.dispatch, the smart contract is executed (via as_proxy(account1)). The smart contract takes the timepoint and call_hash parameters from storage and uses that to call cancel_as_multi for the very same multisig transaction, which will unreserve the deposit reserved for the multisig transaction
After dispatching the call, as_multi will unreserve the same deposit a second time. By repeating the process over and over again, an attacker can unreserve an arbitrary amount of funds reserved by other pallets for a different reason.
The text was updated successfully, but these errors were encountered:
* Worker interface + WorkerPool run logic
* Comment out beefy stuff in listener for now
* Create Eth relayer using worker interface
* Update Worker interface, simplify ethrelayer
* Use factories in WorkerPool, better interface
* Add back deadlock detection
* Allow v1 or v2 relay to be run
* Fix conn bug
* Remove unused keypair
jonathanudd
pushed a commit
to jonathanudd/polkadot-sdk
that referenced
this issue
Apr 10, 2024
* Rename Header to AuraHeader
This prevents some type conflicts with the PolkadotJS Apps types.
* Fix test and benchmark builds
* Update AuraHeader in types.json
As account1: Create a smart contract which allows calling cancel_as_multi with the parameters timepoint and call_hash stored in the storage of the smart contract
@gavofyork Could you please explain whether I should implement a smart contract in my pallet per se (if so, how) or somehow integrate smart contract written in ink! code and call the smart contract from my pallet? Thanks for any explanation.
D1-mediumCan be fixed by a coder with good Rust knowledge but little knowledge of the codebase.T1-FRAMEThis PR/Issue is related to core FRAME, the framework.T10-testsThis PR/Issue is related to tests.
Basically a test for paritytech/substrate#6445; will require a pallet with interior dispatch mutability in order to call the
cancel_as_multi
from theas_multi
dispatcher.Exploit
When starting a multisig transaction with threshold >= 2, a certain amount of your balance will be reserved as a deposit (and unreserved once the multisig transaction is executed or cancelled). However, the implementation of as_multi and cancel_as_multi has no protection against re-entrance. So if the call argument to as_multi somehow triggers a cancel_as_multi for the same multisig transaction, the deposit will be unreserved twice. With normal pallets this is not possible since the cancel_as_multi call will need the call_hash argument and this call_hash must be a hash of an encoded call to cancel_as_multi with the same call_hash, which is computationally infeasible to find assuming that the hash function (blake2_256) is cryptographically secure.
However, the multisig call could call a smart contract, which will load the call_hash and timepoint arguments from its storage and then call cancel_as_multi via env.dispatch_call.
Exploit outline:
The text was updated successfully, but these errors were encountered: