Level 0 - Hello Ethernaut
来源:ethernaut.openzeppelin.com/level/0
Hello Ethernaut 是一道入门关,但它已经在教接下来全程都用得上的一个习惯: 别再相信 UI,打开控制台,看清楚合约真正暴露出了什么。
这一关算不上真正意义上的利用挑战。它更像是 Ethernaut 在教你 —— 它希望你怎么玩这套东西。
准备环境
如果页面以只读模式打开,说明 Ethernaut 还没看到你的钱包。处理方式很直接: 装一个 MetaMask,把它连上,切到 Sepolia 网络,然后给账户充一点测试 ETH。
这里不打算展开钱包的完整教程。这一关需要确保的,只有以下几点:
- MetaMask 已安装并已解锁
- 网络已经切到 Sepolia
- 账户里有足够支付 gas 的测试 ETH
切到 Sepolia 的顺序是: 先把"显示测试网络"打开,再从钱包主界面切换网络。





第一次接触时容易踩到的一个小点: 你的地址在以太坊主网和 Sepolia 上一般是同一个。变的是网络状态,而不是地址本身。每个网络的余额、交易、合约都是各自独立的。
Faucet 备注
大多数 Sepolia 水龙头平时都能用,直到突然不能用。最常见的麻烦来自反滥用策略: 有的水龙头拒绝全新钱包,有的要求登录账号,还有的会检查你主网上是否有一点点 ETH。
实操上的应对很简单:
- 先试一个正常的水龙头
- 如果被拒,换一个备选
- 如果钱包是全新的,基于浏览器的 Sepolia PoW 水龙头 通常是阻力最小的路径
可用资源:
- Alchemy faucets
- Google Cloud Web3 Sepolia faucet
- Coinbase Developer Platform faucets
- Infura faucet
- Sepolia PoW faucet
控制台才是真正的操作界面
钱包接上以后,把浏览器控制台打开。从这一刻起,Ethernaut 不再是一个网页,而像一个合约游乐场。
你应该立刻能看到关卡横幅、提示文字,以及当前关卡的合约地址。

第一个值得敲一下的辅助是 player:
player
它会返回当前连接账户的地址。

接着确认账户里确实有 gas:
await getBalance(player)

最后问问 Ethernaut 都提供了哪些辅助方法:
help()

这一条命令几乎把这个平台的工作面都告诉你了: player 地址、当前关卡地址、当前实例、合约包装器,以及几个顺手的工具方法。
真正重要的两个对象
到这一步,真正值得关心的对象只有两个。
ethernaut
它是全局的游戏合约包装器,而不是当前关卡的合约实例。它负责管理所有关卡以及通关校验。
ethernaut
await ethernaut.owner()

这一步主要起到熟悉作用。重点是让自己习惯一件事: 这些"游戏对象"就是普通的合约包装器,而不是某种只存在于 UI 里的、有魔法的抽象。
contract
它是你请求出来的当前关卡实例。真正用来解题的,是这个对象。
通关步骤
1. 连接站点
先在 MetaMask 里通过 Ethernaut 发起的钱包连接请求。

如果 MetaMask 询问网络权限,通过 Sepolia 这一项。

2. 请求一个关卡实例
点击 Get New Instance,在 MetaMask 里通过那笔交易。部署完成后,Ethernaut 会把实例地址打印到控制台。

3. 顺着合约留的面包屑走
这一关本质上是一次贯穿合约接口的引导式游览。合约会一路告诉你下一步该去哪儿,你要做的只是注意听它说什么。
整条交互链是:
await contract.info()
await contract.info1()
await contract.info2('hello')
await contract.infoNum()
await contract.info42()
await contract.theMethodName()
await contract.method7123949()
await contract.password()
await contract.authenticate('ethernaut0')

这里没有什么微妙之处。Ethernaut 是在教你: 读合约,而不是盯着按钮猜。
4. 提交已通关的实例
交互链跑完之后,点 Submit Instance,在 MetaMask 里通过这笔交易。


如果一切正常,Ethernaut 会把这一关标记为已通过。

看完源码之后,有些事就很明显了
通关之后,Ethernaut 会把源码公开出来。这才是这一关真正值得回味的地方。
下面是同一份合约,加上了内联注解:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Instance {
// 声明为 public 意味着 Solidity 会自动生成一个 password() 取值方法。
// 换句话说,这个"秘密"任何人都可以读到。
string public password;
// 这是一条面包屑。值 42 是为了把玩家引向 info42()。
uint8 public infoNum = 42;
// 又一条面包屑。因为它是 public 的,玩家其实也可以直接把它读出来。
string public theMethodName = "The method name is method7123949.";
// 这才是这一关真正的通关状态。
bool private cleared = false;
// 构造函数
// 关卡实例在部署时被赋予一个初始 password。
constructor(string memory _password) {
password = _password;
}
// 链条上的第一条提示。
function info() public pure returns (string memory) {
return "You will find what you need in info1().";
}
// 链条上的第二条提示。
function info1() public pure returns (string memory) {
return 'Try info2(),but with "hello" as a parameter.';
}
// 玩家第一次需要传入参数的地方。
// 只有传入 "hello",才能拿到下一条线索。
function info2(string memory param) public pure returns (string memory) {
if (keccak256(abi.encodePacked(param)) == keccak256(abi.encodePacked("hello"))) {
return "The property infoNum holds the number of the next info method to call.";
}
return "Wrong parameter.";
}
// infoNum 指向这里。
function info42() public pure returns (string memory) {
return "theMethodName is the name of the next method.";
}
// theMethodName 指向这里。
function method7123949() public pure returns (string memory) {
return "If you know the password,submit it to authenticate().";
}
// 如果传入的值与 password 一致,这一关就算通过。
function authenticate(string memory passkey) public {
if (keccak256(abi.encodePacked(passkey)) == keccak256(abi.encodePacked(password))) {
cleared = true;
}
}
// 检查这一关是否已被通关的辅助方法。
function getCleared() public view returns (bool) {
return cleared;
}
}
整个流程被刻意设计得很简单。一个函数指向下一个,直到合约最终告诉你: 读出 password,然后传进 authenticate()。
真正的关键就在这一行:
string public password;
整道题的精髓就在这里。合约把 password 写得像一个秘密,但只要它被声明成 public,Solidity 就会自动暴露出一个 getter。它不是隐藏的,也不是被保护的,更不是任何意义上的 private —— 你可以直接读,然后把它喂回 authenticate()。
这也是为什么这道看似简单的题依然值得认真做: 它逼你去注意,UI 里描述的样子,跟合约在链上真正暴露的内容,是两回事。
这一关真正想教的是什么
最显而易见的那句话当然是"public 状态本来就是公开的"。但底下其实还有一层更宽的意思:
- 把合约接口当成事实来源
- 不要因为某个变量"听起来像个秘密"就以为它真的是秘密
- 仔细读输出 —— 合约经常把下一步的提示直接摆在你面前
- 区分清楚: 什么是前端层隐藏的,什么是链上真正隐藏的
这是真正的智能合约审计习惯,不是游戏化的技巧。
这一关为什么仍然重要
题本身刻意简单,但它教的工作流,恰恰是后面每一关都会反复出现的:
- 接钱包
- 切到对的网络
- 给账户充值
- 摸清楚控制台里的辅助方法
- 读懂公开接口
- 创建实例
- 与合约交互
- 提交结果
一旦这套循环开始变得自然,后面的关卡也就不再那么生疏。
通关标准
只要做到下面这些,这一关就算过了:
- 钱包成功连接
- 切到 Sepolia,并有足够的 gas
- 成功创建关卡实例
- 顺着合约公开的提示链走完一遍
- 提交已解的实例
关键收获
- 这是一道入门关,而不是漏洞利用题。
- 浏览器控制台是这场游戏的一部分,不是可选项。
- public 变量并不是秘密。
- 读合约,通常比盯着 UI 猜要划算得多。
- 把钱包、网络与水龙头一次配好,后面省下的时间会非常可观。