您现在的位置是:首页 >技术杂谈 >智能合约安全 | 合约无效化攻击网站首页技术杂谈
智能合约安全 | 合约无效化攻击
视频教程在我主页简介或专栏里
(不懂都可以来问我 专栏找我哦)
智能合约安全
合约无效化攻击
合约无效化攻击类同于web安全中的逻辑漏洞中的一种 我们这里拿一个典型的例子来讲解 有这样一份智能合约, 每个人可以向其中发送1 eth 第七个发送的人可以获取全部的7 eth 我们按照这个功能去编写代码
contract Games { function play() public payable {
require(msg.value == 1 ether);
if (address(this).balance == 7 * 10 ** 18) { // 当此人发送的是本轮中第七次eth, 则获得全部奖励
msg.sender.call{value:7 ether}("");
}
}
}
阅读代码, 乍一看好像没什么问题 require保证了每人每次只能发送1eth 功能也可以正常实现
合约自毁函数 selfdestruct
接下来就要引入一个关于 合约自毁 的概念:合约部署之后, 假设我们发现了bug, 需要更改,智能合约不像传统的服务器那样, 传统的服务器可以直接关停服务,甚至热更新(在不停止服务的情况下更改服务器代码),在区块链上的代码我们是无法更改的。那么假设我们的某个服务存在类似于”支付漏洞”的漏洞,我们必须要停止掉这个智能合约,这时候就需要用到合约自毁函数,函数签名 selfdestruct(address payable); 该函数接收一个可支付地址作为参数,函数会销毁该智能合约的部署,并将此时合约中存在的余额强制转给指定的地址
攻击实现
那么这个漏洞就很清楚了 只需要我们部署一个智能合约 并使用自毁函数强制转账 8 eth 给上述合约 由于上述合约中的 if(address(this.balance == 7 ether)), 这个条件永远不会被满足 该合约也就失去了作用
攻击代码如下
contract Attack { function draw() public payable {} // 用来存eth, 方便测试
function over(address addr) public {
selfdestruct(payable(addr));
}
}
先转账8eth到攻击合约中
然后在将目标合约的地址传给over函数调用
可以看到目标合约中的eth已经变成了8 这时候无论怎样向该合约传入eth 都已经无效了
漏洞防御
作为一名攻击者, 可能会觉得这种类型的攻击可能有些”鸡肋” 换一个角度, 如果你作为一名开发者, 一定是不希望这种事情的发生的 防御的话, 我们可以专门设置一个值, 只有在每次函数被调用时 才会增加, 判断的依据也使用这个值来判断
contract Games { uint blance = 0;
function play() public payable {
require(msg.value == 1 ether);
blance += 1;
if (blance == 7) { // 当此人发送的是本轮中第七次eth, 则获得全部奖励
msg.sender.call{value:7 ether}("");
}
}
}
总结
本篇主要引入 自毁函数 在攻击上的一些可能点, 其核心还是代码逻辑漏洞, 另外, 本篇中的漏洞代码也可以使用回滚攻击去”耍赖”, 感兴趣的同学可以自行尝试.