以太Ethernaut靶场打靶—1 Fallback

以太Ethernaut靶场打靶—1 Fallback

    • 源码审计
    • 攻击流程

现在来到第一关,打靶主要还是先对智能合约进行审计如果没有学过的可以去https://cryptozombies.io/
进行学习,有代码经验的还是能很快入门

源码审计

pragma solidity ^0.6.0;

import '@openzeppelin/contracts/math/SafeMath.sol';

contract Fallback {

  using SafeMath for uint256;
  mapping(address => uint) public contributions;
  address payable public owner;

constructor() public {
    owner = msg.sender;    //构造当前拥有者
    contributions[msg.sender] = 1000 * (1 ether);  //初始1000
  }

  modifier onlyOwner {   //当前调用修饰
        require(
            msg.sender == owner,
            "caller is not the owner"
        );
        _;
    }
  
  function contribute() public payable { //
    require(msg.value < 0.001 ether); //判断当前发送者是否小于0.001
    contributions[msg.sender] += msg.value; //贡献为1000+值
    if(contributions[msg.sender] > contributions[owner]) {
      owner = msg.sender;
    }
  }

  function getContribution() public view returns (uint) {  //放回当前贡献者的值
    return contributions[msg.sender];
  }

  function withdraw() public onlyOwner { //所有者提取
    owner.transfer(address(this).balance);
  }

  fallback() external payable {     //fallback将owner 设置为msg.sender 
//fallback0.6.0后写法
    require(msg.value > 0 && contributions[msg.sender] > 0); //条件(漏洞所在)
    owner = msg.sender;
  }
}

靶场要求是要获得合约所有权并且转出余额
首先我们来到源码进行分析发现有两处可以拿到合同所有权
1

  function contribute() public payable { //每次转账只能小于0.001个eth,转多少个eth,就增加同贡献值,贡献值最多的人获得合约所有权
    require(msg.value < 0.001 ether); //判断当前贡献值是否小于0.001
    contributions[msg.sender] += msg.value; //贡献为1000+值
    if(contributions[msg.sender] > contributions[owner]) {
      owner = msg.sender;

2

    require(msg.value > 0 && contributions[msg.sender] > 0); //条件(漏洞所在)fallback函数,用于接收用户向合约发送的代币,如果转入的金额和代币的金额不等于0,将获得合约所有权
    owner = msg.sender;

要拿所有权后就可以通过withdraw()将余额提取出来;

而当前拥有者可以使用fallback()或者contribute()将当前拥有者替换为当前信息发送者。

contribute()显然发送值小于0.01要转10^6次才能达到1000贡献值。
fallback()条件是发送的值大于0,且当前贡献值大于0
显然fallback() 可触发条件,但是需要转账触发fallback()需要转账触发,且转两次第一次实现贡献值大于0,然后再转一次触发fallback()。

攻击流程

首先查看一下合约拥有者
以太Ethernaut靶场打靶—1 Fallback_第1张图片
我调用contribute向合约转1wei
以太Ethernaut靶场打靶—1 Fallback_第2张图片
使贡献值大于0,为满足发送值大于0执行contract.send(1);再转1wei满足后面条件触发fallback获得合约所有权
以太Ethernaut靶场打靶—1 Fallback_第3张图片
此时可以看看合约所有权地址已经变成我们的地址了
以太Ethernaut靶场打靶—1 Fallback_第4张图片
现在我们再通过函数withdraw()将余额提出来
以太Ethernaut靶场打靶—1 Fallback_第5张图片
然后提交实例
以太Ethernaut靶场打靶—1 Fallback_第6张图片

你可能感兴趣的:(Ethernaut靶场通关记录,以太坊,数字货币)