Ethernaut: 6. 위임
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
contract Delegate {
address public owner;
constructor(address _owner) public {
owner = _owner;
}
function pwn() public {
owner = msg.sender;
}
}
contract Delegation {
address public owner;
Delegate delegate;
constructor(address _delegateAddress) public {
delegate = Delegate(_delegateAddress);
owner = msg.sender;
}
fallback() external {
(bool result,) = address(delegate).delegatecall(msg.data);
if (result) {
this;
}
}
}
delegatecall
는 중요한 함수입니다. 일반적으로 컨트랙트는 message calls을 만들어 기능을 호출합니다. delegatecall
은 기본적으로 계약의 컨텍스트를 다른 계약으로 전달하고 원하는 대로 수행하도록 하는 보다 전문적인 호출입니다. 이는 스토리지 변수에서 작동할 수 있는 라이브러리를 구현하거나 프록시가 시간이 지남에 따라 다양한 계약에 대리자를 호출하는 업그레이드 가능한 계약이 있는 경우에 유용합니다.delegatecall
동안 다음은 변경되지 않습니다.msg.sender
msg.value
address(this)
대리인 호출이 실제로 잘 작동하는 방식을 설명하는 이 문서를 참조하고 싶습니다. https://eip2535diamonds.substack.com/p/understanding-delegatecall-and-how?s=r .
이 예의 공격은 하나의 트랜잭션일 뿐입니다.
await sendTransaction({
from: player,
to: contract.address,
data: "0xdd365b8b"
})
이제
data
부분을 살펴보겠습니다. EVM은 함수 서명의 처음 4바이트를 보고 함수를 호출합니다. 함수 시그니처는 함수 프로토타입의 keccak256
(즉, sha3
)입니다. 이 경우 web3.utils.sha3('pwn()').slice(2, 2 + 4 * 2)
는 dd365b8b
를 제공합니다. 함수 매개변수가 있다면 각각 32바이트로 주겠지만 이 경우에는 매개변수가 없기 때문에 함수 서명만 데이터로 씁니다.이를 가지고 Delegation Contract를 호출하면 Fallback 기능으로 넘어갑니다. 거기에서
msg.data
를 매개변수로 하는 delegatecall이 이루어지므로 Delegate의 pwn
함수를 호출하게 됩니다.실제 익스플로잇은 스토리지와 관련이 있습니다. 두 계약 모두 스토리지의 첫 번째 슬롯에
address public owner
가 있습니다. delegatecall
를 사용하면 호출자의 저장소가 활성화되고 호출 수신자가 슬롯과 관련하여 이를 업데이트할 수 있습니다. 보시다시피 pwn
업데이트 owner
이것은 사실상 동일한 슬롯에서 호출자의 스토리지 값을 업데이트하며 이는 다시 소유자 주소입니다.따라서
pwn
내의 저장 변수 할당은 delegatecall
를 만든 계약에 영향을 미치고 우리는 소유자가 됩니다.
Reference
이 문제에 관하여(Ethernaut: 6. 위임), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/erhant/ethernaut-6-delegation-9n2텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)