安全审查-Elevator破解
有道安全题叫Elevator,意思是说要攻击这个合约,修改里面的top变量,使得top的值为true。我们先看原题:// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface Building { function isLastFloor(uint256) external returns (bool); } contract Elevator { bool public top; uint256 public floor; function goTo(uint256 _floor) public { Building building = Building(msg.sender); if (!building.isLastFloor(_floor)) { floor = _floor; top = building.isLastFloor(floor); } } } 首先需要building.isLastFloor(_floor) == false,才能进到if内部,top = building.isLas...
安全审查-Elevator破解
有道安全题叫Elevator,意思是说要攻击这个合约,修改里面的top变量,使得top的值为true。我们先看原题:// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface Building { function isLastFloor(uint256) external returns (bool); } contract Elevator { bool public top; uint256 public floor; function goTo(uint256 _floor) public { Building building = Building(msg.sender); if (!building.isLastFloor(_floor)) { floor = _floor; top = building.isLastFloor(floor); } } } 首先需要building.isLastFloor(_floor) == false,才能进到if内部,top = building.isLas...
安全审查-谈谈Reentrancy攻击
在Defi的应用中,防止重入攻击是最基本的需求,曾经也有很多因为没有防御机制,造成重要损失的现实案例。可以先看一下没有防御机制的代码contract Reentrance { using SafeMath for uint256; mapping(address => uint256) public balances; constructor() public payable {} function donate(address _to) public payable { balances[_to] = balances[_to].add(msg.value); } function balanceOf(address _who) public view returns (uint256 balance) { return balances[_who]; } function withdraw(uint256 _amount) public { if (balances[msg.sender] >= _amount) { (bool result,) = msg.sender.c...
安全审查-谈谈Reentrancy攻击
在Defi的应用中,防止重入攻击是最基本的需求,曾经也有很多因为没有防御机制,造成重要损失的现实案例。可以先看一下没有防御机制的代码contract Reentrance { using SafeMath for uint256; mapping(address => uint256) public balances; constructor() public payable {} function donate(address _to) public payable { balances[_to] = balances[_to].add(msg.value); } function balanceOf(address _who) public view returns (uint256 balance) { return balances[_who]; } function withdraw(uint256 _amount) public { if (balances[msg.sender] >= _amount) { (bool result,) = msg.sender.c...
为什么bool比uint256消耗更多的gas
之前遇到有朋友这么问:“为什么bool比uint256消耗更多的gas”。首先要说明的是这个说法是不准确的,并不是简单的bool和uint256这个类型差异造成的。我们在看OpenZeppelin的ReentrancyGuard.sol的源码时,会看到下面的写法,我们从底层机制上分析// Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. //........
为什么bool比uint256消耗更多的gas
之前遇到有朋友这么问:“为什么bool比uint256消耗更多的gas”。首先要说明的是这个说法是不准确的,并不是简单的bool和uint256这个类型差异造成的。我们在看OpenZeppelin的ReentrancyGuard.sol的源码时,会看到下面的写法,我们从底层机制上分析// Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. //........
安全审计-转账的疑惑
在King这个题目中,只要转账金额大于当前King之前转账的金额时,你就成了新的King,同时你转的金额会全部贡献给前一个King。看代码contract King { address king; uint256 public prize; address public owner; constructor() payable { owner = msg.sender; king = msg.sender; prize = msg.value; } receive() external payable { require(msg.value >= prize || msg.sender == owner); payable(king).transfer(msg.value); king = msg.sender; prize = msg.value; } function _king() public view returns (address) { return king; } } 仔细分析代码,逻辑上没有问题。整个行为最多的就是转账。那先尝试从转账入手攻击。自己转大金额过去,...
安全审计-转账的疑惑
在King这个题目中,只要转账金额大于当前King之前转账的金额时,你就成了新的King,同时你转的金额会全部贡献给前一个King。看代码contract King { address king; uint256 public prize; address public owner; constructor() payable { owner = msg.sender; king = msg.sender; prize = msg.value; } receive() external payable { require(msg.value >= prize || msg.sender == owner); payable(king).transfer(msg.value); king = msg.sender; prize = msg.value; } function _king() public view returns (address) { return king; } } 仔细分析代码,逻辑上没有问题。整个行为最多的就是转账。那先尝试从转账入手攻击。自己转大金额过去,...
安全审计-private带来的危害
ethernaut上有道题叫Vault,要求获取到密码来解锁。先看代码contract Vault { bool public locked; bytes32 private password; constructor(bytes32 _password) { locked = true; password = _password; } function unlock(bytes32 _password) public { if (password == _password) { locked = false; } } } 乍一看,感觉逻辑和计算都没有问题。按照一般说法,这个密码设置为私有是没有任何问题的。那怎么解锁呢?暴利攻击肯定是行不通,逻辑上也没有漏洞。bytes32是可以用==来判断相等,也没有问题。那会不会数据的可见性的问题。我们来看看private的官方解释:Making something private or internal only prevents other contracts from reading or modifying the informati...
安全审计-private带来的危害
ethernaut上有道题叫Vault,要求获取到密码来解锁。先看代码contract Vault { bool public locked; bytes32 private password; constructor(bytes32 _password) { locked = true; password = _password; } function unlock(bytes32 _password) public { if (password == _password) { locked = false; } } } 乍一看,感觉逻辑和计算都没有问题。按照一般说法,这个密码设置为私有是没有任何问题的。那怎么解锁呢?暴利攻击肯定是行不通,逻辑上也没有漏洞。bytes32是可以用==来判断相等,也没有问题。那会不会数据的可见性的问题。我们来看看private的官方解释:Making something private or internal only prevents other contracts from reading or modifying the informati...