Files
ghaymah-dns-net-sec-tests/scripts/05_security_test.js
T

215 lines
8.7 KiB
JavaScript

// 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); });