Ethernaut: 20. 거부
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import '@openzeppelin/contracts/math/SafeMath.sol';
contract Denial {
using SafeMath for uint256;
address public partner; // withdrawal partner - pay the gas, split the withdraw
address payable public constant owner = address(0xA9E);
uint timeLastWithdrawn;
mapping(address => uint) withdrawPartnerBalances; // keep track of partners balances
function setWithdrawPartner(address _partner) public {
partner = _partner;
}
// withdraw 1% to recipient and 1% to owner
function withdraw() public {
uint amountToSend = address(this).balance.div(100);
// perform a call without checking return
// The recipient can revert, the owner will still get their share
partner.call{value:amountToSend}("");
owner.transfer(amountToSend);
// keep track of last withdrawal time
timeLastWithdrawn = now;
withdrawPartnerBalances[partner] = withdrawPartnerBalances[partner].add(amountToSend);
}
// allow deposit of funds
receive() external payable {}
// convenience function
function contractBalance() public view returns (uint) {
return address(this).balance;
}
}
이 수준에서 익스플로잇은
call
기능과 관련이 있습니다: partner.call{value:amountToSend}("")
. 여기서 call
는 빈 msg.data
및 amountToSend
값으로 파트너 주소에 만들어집니다. call
를 사용할 때 전달할 가스의 양을 지정하지 않으면 모든 것을 전달합니다! 주석 라인에서 알 수 있듯이 호출을 되돌려도 실행에 영향을 주지 않지만 해당 호출에서 모든 가스를 소모하면 어떻게 됩니까?그것이 공격입니다. 호출이 메시지 데이터 없이 이루어지기 때문에
fallback
함수를 작성하고 거기에 무한 루프를 넣습니다.contract BadPartner {
fallback() external payable {
while (true) {}
}
}
그런 다음 출금 파트너를 이 계약 주소로 설정하면 완료됩니다.
call
는 나머지 가스의 최대 63/64를 사용할 수 있습니다(EIP-150 참조). 가스의 1/64가 나머지 재료를 완성하기에 충분하다면 잘한 것입니다. 그래도 안전을 위해 전달할 가스의 양을 지정하십시오.
Reference
이 문제에 관하여(Ethernaut: 20. 거부), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/erhant/ethernaut-20-denial-2pn2텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)