forked from SunWeb3Sec/DeFiVulnLabs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathApproveScam.sol
100 lines (80 loc) · 3.15 KB
/
ApproveScam.sol
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
import "forge-std/Test.sol";
contract ContractTest is Test {
ERC20 ERC20Contract;
address alice = vm.addr(1);
address eve = vm.addr(2);
function testApproveScam() public {
ERC20Contract = new ERC20();
ERC20Contract.mint(1000);
ERC20Contract.transfer(address(alice),1000);
vm.prank(alice);
// Be Careful to grant unlimited amount to unknown website/address.
// Do not perform approve, if you are sure it's from a legitimate website.
// Alice granted approval permission to Eve.
ERC20Contract.approve(address(eve),type(uint256).max);
console.log("Before exploiting, Balance of Eve:",ERC20Contract.balanceOf(eve));
console.log("Due to Alice granted transfer permission to Eve, now Eve can move funds from Alice");
vm.prank(eve);
// Now, Eve can move funds from Alice.
ERC20Contract.transferFrom(address(alice),address(eve),1000);
console.log("After exploiting, Balance of Eve:",ERC20Contract.balanceOf(eve));
console.log("Exploit completed");
}
receive() payable external{}
}
interface IERC20 {
function totalSupply() external view returns (uint);
function balanceOf(address account) external view returns (uint);
function transfer(address recipient, uint amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint);
function approve(address spender, uint amount) external returns (bool);
function transferFrom(
address sender,
address recipient,
uint amount
) external returns (bool);
event Transfer(address indexed from, address indexed to, uint value);
event Approval(address indexed owner, address indexed spender, uint value);
}
contract ERC20 is IERC20 {
uint public totalSupply;
mapping(address => uint) public balanceOf;
mapping(address => mapping(address => uint)) public allowance;
string public name = "Test example";
string public symbol = "Test";
uint8 public decimals = 18;
function transfer(address recipient, uint amount) external returns (bool) {
balanceOf[msg.sender] -= amount;
balanceOf[recipient] += amount;
emit Transfer(msg.sender, recipient, amount);
return true;
}
function approve(address spender, uint amount) external returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transferFrom(
address sender,
address recipient,
uint amount
) external returns (bool) {
allowance[sender][msg.sender] -= amount;
balanceOf[sender] -= amount;
balanceOf[recipient] += amount;
emit Transfer(sender, recipient, amount);
return true;
}
function mint(uint amount) external {
balanceOf[msg.sender] += amount;
totalSupply += amount;
emit Transfer(address(0), msg.sender, amount);
}
function burn(uint amount) external {
balanceOf[msg.sender] -= amount;
totalSupply -= amount;
emit Transfer(msg.sender, address(0), amount);
}
}