// Phase 4: Security & Scoping (Penetration Testing) // Tests: Isolation, Lateral Movement, Port Scanning, DNS Leak Detection const CUMIN_TOKEN = "cumin_GjynCIFJtyoZ_73wasCoWNYf7Y-Pk0jMffHEdRzblBg"; const PROJECT_ID = "178bfad9-5edc-409f-833c-6fffca7aed5a"; const API = "https://api.cumin.dev"; const fs = require("fs"); let SESSION_ID = null; const log = []; function L(msg) { const ts = new Date().toISOString(); const e = `[${ts}] ${msg}`; console.log(e); log.push(e); } async function mcpRequest(method, params, id) { const body = { jsonrpc: "2.0", method, id }; if (params) body.params = params; const headers = { Authorization: `Bearer ${CUMIN_TOKEN}`, "Content-Type": "application/json", Accept: "application/json, text/event-stream" }; if (SESSION_ID) headers["Mcp-Session-Id"] = SESSION_ID; const res = await fetch(`${API}/mcp`, { method: "POST", headers, body: JSON.stringify(body) }); const sid = res.headers.get("Mcp-Session-Id"); if (sid) SESSION_ID = sid; const data = await res.json(); if (data.error) throw new Error(`MCP: ${JSON.stringify(data.error)}`); return data.result; } async function callTool(name, args) { const r = await mcpRequest("tools/call", { name, arguments: args }, Date.now()); const text = r.content?.map(c => c.text || "").join("") || JSON.stringify(r); if (r.isError) { L(` ⚠️ ${name}: ${text}`); return null; } return text; } async function exec(appId, command) { const result = await callTool("exec_in_app", { project_id: PROJECT_ID, id: appId, command }); if (!result) return { stdout: "", stderr: "exec failed", exit_code: -1 }; try { return JSON.parse(result); } catch { return { stdout: result, stderr: "", exit_code: 0 }; } } async function main() { L("=== PHASE 4: SECURITY & PENETRATION TESTING ===\n"); // Initialize MCP await mcpRequest("initialize", { protocolVersion: "2024-11-05", capabilities: {}, clientInfo: { name: "sec-tester", version: "1.0" } }, 1); L("✅ MCP Connected\n"); // Get app list const apps = JSON.parse(await callTool("list_apps", { project_id: PROJECT_ID })); L("Deployed apps:"); for (const a of apps) { L(` ${a.name} (${a.id.substring(0,8)}) - ${a.status} - tags: ${JSON.stringify(a.tags)}`); } // Use soc-backend as our test container const testApp = apps.find(a => a.name === "soc-backend") || apps[0]; L(`\nUsing ${testApp.name} (${testApp.id}) as pen-test host\n`); // ============================ // TEST 1: Isolation & Lateral Movement // ============================ L("=== TEST 1: ISOLATION & LATERAL MOVEMENT ==="); L("Objective: Attempt to reach apps in DIFFERENT projects or with DIFFERENT tags\n"); // 1a. Try to access non-existent/random IPs on the mesh const lateralIPs = [ "10.100.0.1", // Gateway/router "10.100.0.2", // Potential other tenant "10.100.0.10", // Random mesh IP "10.100.0.50", // Random mesh IP "10.100.0.200", // Random mesh IP "10.100.0.254", // Broadcast-adjacent "10.100.1.1", // Different subnet "172.17.0.1", // Docker default gateway "172.26.64.1", // Nomad bridge gateway "192.168.1.1", // Common LAN gateway ]; L("--- 1a. Lateral Movement via Direct IP Probing ---"); for (const ip of lateralIPs) { const result = await exec(testApp.id, ["sh", "-c", `wget -qO- --timeout=3 http://${ip}/ 2>&1 || echo "BLOCKED"`]); L(` ${ip} → ${result.stdout.trim().substring(0, 200)}`); } // 1b. Try DNS resolution of names that shouldn't exist L("\n--- 1b. Cross-Tenant DNS Resolution Attempts ---"); const foreignNames = [ "other-project-app", "admin-panel", "database.default", "kubernetes.default.svc", "metadata.google.internal", "169.254.169.254", // Cloud metadata "consul.service.consul", "nomad.service.consul", ]; for (const name of foreignNames) { const result = await exec(testApp.id, ["sh", "-c", `nslookup ${name} 2>&1 | head -5`]); L(` DNS ${name} → ${result.stdout.trim().substring(0, 150)}`); } // 1c. Attempt to access cloud metadata service L("\n--- 1c. Cloud Metadata Service Access Attempt ---"); const metadataURLs = [ "http://169.254.169.254/latest/meta-data/", // AWS "http://169.254.169.254/metadata/instance?api-version=2021-02-01", // Azure "http://metadata.google.internal/computeMetadata/v1/", // GCP "http://100.100.100.200/latest/meta-data/", // Alibaba ]; for (const url of metadataURLs) { const result = await exec(testApp.id, ["sh", "-c", `wget -qO- --timeout=3 "${url}" 2>&1 | head -3 || echo "BLOCKED"`]); L(` Metadata ${url.substring(0, 40)}... → ${result.stdout.trim().substring(0, 150)}`); } // ============================ // TEST 2: Network Enumeration / Port Scanning // ============================ L("\n=== TEST 2: NETWORK ENUMERATION ==="); L("Objective: Scan for unintended open ports on internal network\n"); // 2a. Get our own IP const myIP = await exec(testApp.id, ["sh", "-c", "ip -4 addr show wg0 2>/dev/null | grep inet | awk '{print $2}' | cut -d/ -f1"]); L(` Our WireGuard IP: ${myIP.stdout.trim()}`); // 2b. Scan common ports on mesh gateway L("\n--- 2a. Port Scan on 10.100.0.1 (Mesh Gateway) ---"); const commonPorts = [22, 53, 80, 443, 3000, 4000, 5432, 6379, 8080, 8443, 9000, 9090, 27017]; for (const port of commonPorts) { const result = await exec(testApp.id, ["sh", "-c", `nc -zw2 10.100.0.1 ${port} 2>&1 && echo "OPEN" || echo "CLOSED"`]); L(` 10.100.0.1:${port} → ${result.stdout.trim()}`); } // 2c. Scan known sibling app const siblingApp = apps.find(a => a.name === "soc-gateway"); if (siblingApp) { // Get sibling WireGuard IP const siblingIpResult = await exec(siblingApp.id, ["sh", "-c", "ip -4 addr show wg0 2>/dev/null | grep inet | awk '{print $2}' | cut -d/ -f1"]); const siblingIP = siblingIpResult.stdout.trim(); L(`\n--- 2b. Port Scan on ${siblingIP} (soc-gateway) ---`); for (const port of commonPorts) { const result = await exec(testApp.id, ["sh", "-c", `nc -zw2 ${siblingIP} ${port} 2>&1 && echo "OPEN" || echo "CLOSED"`]); L(` ${siblingIP}:${port} → ${result.stdout.trim()}`); } } // 2d. Scan our own container for unexpected services L("\n--- 2c. Self Port Scan (localhost) ---"); const selfPorts = [22, 53, 80, 443, 3000, 4000, 5432, 6379, 8080, 9000, 9090]; for (const port of selfPorts) { const result = await exec(testApp.id, ["sh", "-c", `nc -zw1 127.0.0.1 ${port} 2>&1 && echo "OPEN" || echo "CLOSED"`]); L(` 127.0.0.1:${port} → ${result.stdout.trim()}`); } // ============================ // TEST 3: Dual Routing & DNS Leaks // ============================ L("\n=== TEST 3: DUAL ROUTING & DNS LEAK DETECTION ==="); L("Objective: Verify external internet works AND internal DNS doesn't leak\n"); // 3a. External connectivity test L("--- 3a. External Internet Connectivity ---"); const externalTargets = [ "https://www.google.com", "https://api.github.com", "https://1.1.1.1/dns-query", ]; for (const url of externalTargets) { const result = await exec(testApp.id, ["sh", "-c", `wget -qO- --timeout=5 "${url}" 2>&1 | head -1 || echo "FAILED"`]); L(` ${url} → ${result.stdout.trim().substring(0, 100)}`); } // 3b. DNS leak test - check if internal queries leak to external resolvers L("\n--- 3b. DNS Leak Detection ---"); const dnsLeakTests = [ // Check what resolver is being used ["cat", "/etc/resolv.conf"], // Try to query an external DNS server directly ["sh", "-c", "nslookup dns-test-server 8.8.8.8 2>&1 | head -5"], // Check if dig/nslookup reveals external resolver ["sh", "-c", "nslookup -type=TXT o-o.myaddr.l.google.com ns1.google.com 2>&1 | head -5"], ]; const leakLabels = ["resolv.conf", "External DNS (8.8.8.8) query", "Google DNS leak test"]; for (let i = 0; i < dnsLeakTests.length; i++) { const result = await exec(testApp.id, dnsLeakTests[i]); L(` ${leakLabels[i]} → ${result.stdout.trim().substring(0, 200)}`); } // 3c. Check routing table L("\n--- 3c. Routing Table ---"); const routes = await exec(testApp.id, ["sh", "-c", "ip route show 2>/dev/null || route -n 2>/dev/null"]); L(` Routes: ${routes.stdout.trim()}`); // 3d. Check iptables rules L("\n--- 3d. Firewall Rules ---"); const iptables = await exec(testApp.id, ["sh", "-c", "iptables -L -n 2>&1 | head -20 || echo 'iptables not available'"]); L(` iptables: ${iptables.stdout.trim().substring(0, 300)}`); L("\n=== PHASE 4 COMPLETE ==="); // Save log fs.writeFileSync("d:/cumin/ghaymah_dns_net_sec_tests/logs/04_security_test.log", log.join("\n")); L("\nLog written to logs/04_security_test.log"); } main().catch(e => { L(`FATAL: ${e.message}`); process.exit(1); });