-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path08TxOrigin.sol
More file actions
74 lines (59 loc) · 1.99 KB
/
08TxOrigin.sol
File metadata and controls
74 lines (59 loc) · 1.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/*
#Phishing with tx.origin
##What's the difference between msg.sender and tx.origin?
If contract A calls B, and B calls C,
in C msg.sender is B and tx.origin is A.
##Vulnerability
A malicious contract can deceive the owner of a contract into calling a function that only the owner should be able to call.
*/
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
/*
Wallet is a simple contract where only the owner should be able to transfer
Ether to another address. Wallet.transfer() uses tx.origin to check that the
caller is the owner. Let's see how we can hack this contract
*/
/*
1. Alice deploys Wallet with 10 Ether
2. Eve deploys Attack with the address of Alice's Wallet contract.
3. Eve tricks Alice to call Attack.attack()
4. Eve successfully stole Ether from Alice's wallet
What happened?
Alice was tricked into calling Attack.attack(). Inside Attack.attack(), it
requested a transfer of all funds in Alice's wallet to Eve's address.
Since tx.origin in Wallet.transfer() is equal to Alice's address,
it authorized the transfer. The wallet transferred all Ether to Eve.
*/
contract Wallet {
address public owner;
constructor() payable {
owner = msg.sender;
}
/*
function transfer(address payable _to, uint _amount) public {
require(tx.origin == owner, "U are not Owner");
(bool sent ,) = _to.call{value: _amount}("");
require(sent, "Failed to send Ether");
}
*/
/*
##Preventative Techniques
Use msg.sender instead of tx.origin
*/
function transfer(address payable _to, uint256 _amount) public {
require(msg.sender == owner, "Not owner");
(bool sent, ) = _to.call{ value: _amount }("");
require(sent, "Failed to send Ether");
}
}
contract Attack {
address payable public owner;
Wallet wallet;
constructor(Wallet _wallet) {
wallet = Wallet(_wallet);
owner = payable(msg.sender);
}
function attack() public {
wallet.transfer(owner, address(wallet).balance);
}
}