Biconomy - Smart Contract Wallet contest - wait's results

One-Stop solution to enable an effortless experience in your dApp to onboard new users and abstract away transaction complexities.

General Information

Platform: Code4rena

Start Date: 04/01/2023

Pot Size: $60,500 USDC

Total HM: 15

Participants: 105

Period: 5 days

Judge: gzeon

Total Solo HM: 1

Id: 200

League: ETH

Biconomy

Findings Distribution

Researcher Performance

Rank: 44/105

Findings: 3

Award: $127.24

🌟 Selected for report: 0

🚀 Solo Findings: 0

Awards

26.2582 USDC - $26.26

Labels

bug
3 (High Risk)
satisfactory
sponsor confirmed
duplicate-460

External Links

Lines of code

https://github.com/code-423n4/2023-01-biconomy/blob/53c8c3823175aeb26dee5529eeefa81240a406ba/scw-contracts/contracts/smart-contract-wallet/SmartAccountFactory.sol#L33 https://github.com/code-423n4/2023-01-biconomy/blob/53c8c3823175aeb26dee5529eeefa81240a406ba/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L166 https://github.com/code-423n4/2023-01-biconomy/blob/53c8c3823175aeb26dee5529eeefa81240a406ba/scw-contracts/contracts/smart-contract-wallet/base/FallbackManager.sol#L32

Vulnerability details

Impact

A malicious user can initiate an arbitrary external call in the role of other user's smart wallet, which is equivalent to stealing a smart wallet and sending a transaction with it. This can lead to fund being stolen from the smart wallet directly, may also lead to authority, funds, function problems of other contracts.

Proof of Concept

If a smart wallet has not been deployed or is being deployed, a hacker can launch an attack by deploying the wallet directly or front-running the deployment.

The following lists some possible attack scenarios.

If a hacker wants to steal USDT from a smart wallet:

  1. The hacker invokes SmartAccountFactory.sol#deployCounterFactualWallet to deploy the smart wallet contract and sets _handler to the USDT contract address.
  2. The hacker invokes the ERC20 - approve function of the smart contract wallet.
  3. The hacker invokes the ERC20 - transferFrom function of the USDT contract to steal all the USDT from the smart wallet.

The principle of step 2 is: The smart contract wallet itself does not implement the ERC20 - approve function, so the invoking will go into FallbackManager.sol#fallback. Because in step 1, the hacker has already set the fallback handler to the USDT contract address when deploying the smart wallet, so eventually the smart wallet will call the approve function of USDT contract in FallbackManager.sol#fallback.

If a hacker wants to steal some ERC721 assets from a smart wallet: Similarly, the hacker just need to set the fallback handler to the ERC721 contract address in step 1, and invokes ERC721 - setApprovalForAll or ERC721 - transferFrom in step 2.

If a smart wallet manages the assets or functions of another contract: Similarly, the hacker just need to set the fallback handler to the target contract address in step 1, and invokes the specific function in step 2.

Tools Used

Manual

I recommend removing the input parameter _handler from SmartAccountFactory.sol#deployCounterFactualWallet and SmartAccountFactory.sol#deployWallet, and using a fixed verified DefaultCallbackHandler contract instead.

#0 - c4-judge

2023-01-17T07:23:46Z

gzeon-c4 marked the issue as duplicate of #460

#1 - c4-sponsor

2023-01-26T02:44:40Z

livingrockrises marked the issue as sponsor confirmed

#2 - c4-judge

2023-02-10T12:25:24Z

gzeon-c4 marked the issue as satisfactory

Awards

22.7235 USDC - $22.72

Labels

bug
3 (High Risk)
satisfactory
sponsor confirmed
duplicate-175

External Links

Lines of code

https://github.com/code-423n4/2023-01-biconomy/blob/53c8c3823175aeb26dee5529eeefa81240a406ba/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L302

Vulnerability details

Impact

All SmartAccount contracts can be hacked, assets can be stolen, arbitrary functions can be called by hackers.

Proof of Concept

A hacker can hack any SmartAccount by calling SmartAccount.sol#execTransaction. All the hacker needs to do is to deploy an eip-1271 contract and assemble a signature that meets the structural requirements of SmartAccount.sol#checkSignatures.

The hacker was able to call execTransaction successfully because SmartAccount.sol#checkSignatures does not check that the _signer is the owner when v is 0.

Using this vulnerability and the power of execTransaction, the hacker can make the SmartAccount to call or delegatecall any interface of any contract, including but not limited to:

Tools Used

Manual

I recommend to checking in SmartAccount.sol#checkSignatures to make sure _signer is the owner:

function checkSignatures( bytes32 dataHash, bytes memory data, bytes memory signatures ) public view virtual { // omitted if(v == 0) { // omitted _signer = address(uint160(uint256(r))); // -- added -- require(_signer == owner, "INVALID_SIGNATURE"); // omitted } // omitted }

#0 - c4-judge

2023-01-17T07:17:11Z

gzeon-c4 marked the issue as duplicate of #175

#1 - c4-sponsor

2023-01-25T23:17:52Z

livingrockrises marked the issue as sponsor confirmed

#2 - c4-judge

2023-02-10T12:28:26Z

gzeon-c4 marked the issue as satisfactory

Findings Information

🌟 Selected for report: immeas

Also found by: 0xDave, 0xbepresent, HE1M, Kutu, betweenETHlines, hansfriese, hihen, peanuts, prc, wait

Labels

bug
2 (Med Risk)
satisfactory
sponsor confirmed
duplicate-390

Awards

78.2598 USDC - $78.26

External Links

Lines of code

https://github.com/code-423n4/2023-01-biconomy/blob/53c8c3823175aeb26dee5529eeefa81240a406ba/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L460 https://github.com/code-423n4/2023-01-biconomy/blob/53c8c3823175aeb26dee5529eeefa81240a406ba/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L465

Vulnerability details

Impact

Transaction will always revert if EntryPoint invokes SmartAccount.sol#execute or SmartAccount.sol#executeBatch.

Proof of Concept

The SmartAccount.sol#execute contais a checking _requireFromEntryPointOrOwner(), while this checking will always succeed and invoking from EntryPoint will always fail because the modifier onlyOwner restricts that only owner can invoke the function:

function execute(address dest, uint value, bytes calldata func) external onlyOwner{ _requireFromEntryPointOrOwner(); _call(dest, value, func); }

The SmartAccount.sol#executeBatch has the same problem.

Tools Used

Manual

I Recommend removing the onlyOwner from SmartAccount.sol#execute and SmartAccount.sol#executeBatch, just keeping and using the checking _requireFromEntryPointOrOwner().

#0 - c4-judge

2023-01-18T00:38:58Z

gzeon-c4 marked the issue as duplicate of #390

#1 - c4-sponsor

2023-01-26T06:53:21Z

livingrockrises marked the issue as sponsor confirmed

#2 - c4-judge

2023-02-10T12:21:32Z

gzeon-c4 marked the issue as satisfactory

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter