【智能合约】Ethernaut writeup(一)

Ethernaut 是一个部署在 Ropsten 测试网络上面的智能合约代码审计类题目,网址:

开头先推荐一个学习 solidity 语法的网站,跟着他做一个僵尸小游戏:https://cryptozombies.io
(我还没学完 :crazy_face:

配置

先说一下开始之前的配置,首先要下一个插件,叫 MetaMask,跟着提示安装就好了,然后我们需要获取点 以太币 来做题,因为我们用的是测试网络,所以有白嫖的方法 :grinning:



如果不能展示这个页面,可以试试换个浏览器试试,我就是 chrome 死活打不开,非说我在主网上,然后把之前生成账号的那 12 个单词保存下来,用 360 浏览器登上获取了五个(最多能拿五个)

在题目网站里面摁下 F12 打开控制台,然后输入 player,如果能展示出跟你 metamask 插件一样的地址的话,就说明环境没问题了

Hello Ethernaut

输入 player 就可以看到你的地址

image

getBalance(player) 查看以太币余额

image

chrome v62 以上的版本,可以用 await getBalance(player) 更简洁

image

ethernaut 可以查看合约

await ethernaut.owner() 可以看一下合约的拥有者

image

上面并不是这个游戏的关卡,只是一些简单的命令,让你了解了解

玩游戏时,不会直接与 ethernaut 合约进行交互。它会给你生成一个关卡实例。只要单击页面底部的蓝色按钮就可以生成。metamask 会弹一个框,确认就行

题目同时给出了源码,你可以从 info() 开始执行,根据提示,一步一步走

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;
  //上面声明了一系列的变量
  function Instance(string _password) public {
    password = _password;
  }//构造函数,password=_password
  function info() public pure returns (string) {
    return 'You will find what you need in info1().';
  }//info()函数返回一串字符串
  function info1() public pure returns (string) {
    return 'Try info2(), but with "hello" as a parameter.';
  }//info1()函数返回一串字符串
  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.';
    }//info2()接受一个字符串与‘hello’比较一样则返回上面的,否则返回下面的
    return 'Wrong parameter.';
  }
  function info42() public pure returns (string) {
    return 'theMethodName is the name of the next method.';
  }//info42()返回一串字符串
  function method7123949() public pure returns (string) {
    return 'If you know the password, submit it to authenticate().';
  }//method7123949()返回一串字符串
  function authenticate(string passkey) public {
    if(keccak256(passkey) == keccak256(password)) {
      cleared = true;
    }//authenticate()接受一个字符串参数
  }//与password进行比较,一样的话cleared改为true
  function getCleared() public view returns (bool) {
    return cleared;
  }//返回cleared的状态
}

就像这样

等他处理完就可以点击黄色按钮提交了

也可以直接看源码,想要通过的话,也就是想要改变 cleared 的话,需要调用 authenticate,并且传入 passkey 与 password 进行 hash 的比较。可以看前面第三行,password 的定义是 public 的,所以可以直接:

await contract.password()
await contract.authenticate("ethernaut0")

完成的标志