드디어 Web3를 시작하게 됐다.
과연 흥미를 붙여 계속 할 수 있을진 모르겠지만.... The Ethernaut을 천천히 풀어보며 공부해보려 한다....
일단 우여곡절끝에 지갑 생성 후 Level 1 Fallback을 풀었다.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Fallback {
mapping(address => uint256) public contributions;
address public owner;
constructor() {
owner = msg.sender;
contributions[msg.sender] = 1000 * (1 ether);
}
modifier onlyOwner() {
require(msg.sender == owner, "caller is not the owner");
_;
}
function contribute() public payable {
require(msg.value < 0.001 ether);
contributions[msg.sender] += msg.value;
if (contributions[msg.sender] > contributions[owner]) {
owner = msg.sender;
}
}
function getContribution() public view returns (uint256) {
return contributions[msg.sender];
}
function withdraw() public onlyOwner {
payable(owner).transfer(address(this).balance);
}
receive() external payable {
require(msg.value > 0 && contributions[msg.sender] > 0);
owner = msg.sender;
}
}
문제에서 요구하는건 두가지이다.
1. owner 강탈
2. 잔고 0으로 만들기
일단 1번을 시도하기 위해선
owner = msg.sender를 트리거 하면 된다.
해당 엔드포인트는 contribute()와 receive에서 보인다.
일단 contribute는 0.001 ether보다 작으면 msg.value를 contributions에 추가하는데 이게 contributions[owner]보다 크면 된다.
그러나 constructor()에서 초기 contributions값을 1000ether로 설정해 놓았기에 사실상 불가능한 포인트이다..
receive를 살펴보면은 msg.value > 0이고 contributions[msg.sender] > 0 이기만 하면 owner=msg.sender을 트리거 가능하기에 요기가 좀 더 좋아 보인다.
일단 the ethernaut에서는 console창을 통해 해당 ABI들을 트리거 가능하다.
ABI가 정확히 뭐냐면 나도 정확히는 모르겄지만 대충 코드 안에 저 함수들이나 그런걸 파싱에서 사용가능하게 해주는? 그런 것 같다. (자세힌 모름...)
여튼 예를 들어 contribute를 트리거 하기 위해선
await contract.contribute({'value':_ethers.utils.parseEther("0.0005")})
요런식으로 값을 넘길 수 있다. (0.0005 ether 넘기기)
receive()에선
msg.value > 0 이고 contributions[msg.sender] > 0 이여야 통과되는데 뭐 msg.value는 0보다 크게 넘긴다 치고 contributions가 0이상이 되려면 contribute()에서 조금만 보내주면 된다.
일단 receive는 payable이 붙어 있어 순수 이더 전송을 처리하는 함수기에 sendTransaction을 사용해 넘길 수 있다.
여기서 contribute에도 payable이 붙어 있기에 같이 작동 될 것이다.
await contract.sendTransaction({'value':_ethers.utils.parseEther("0.0001")})
0.0001은 0보다 커지기에 value가 넘어가고 owner = msg.sender를 트리거 할 수 있게 된다.
그 후 withdraw를 호출하면 잔고가 0이 되고 성공하게 된다.
await contract.withdraw()
참고로 아래 명령어를 통해 owner의 잔액도 확인 가능하다.
await getBalance(instance)
음 아직 제대로 다 이해는 못되는데 구글링 해가면서 해봐야지...
'Web3 > The Ethernaut' 카테고리의 다른 글
[The Ethernaut] Level 6. Delegation (0) | 2025.01.17 |
---|---|
[The Ethernaut] Level 5. Token (0) | 2025.01.17 |
[The Ethernaut] Level 4. Telephone (0) | 2025.01.17 |
[The Ethernaut] Level 3. Coin Flip (0) | 2025.01.16 |