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

272 lines
14 KiB
JavaScript

const fs = require('fs');
const { RemoteTerminal } = require('./remote_exec');
const LOG_FILE = 'D:/cumin/ghaymah_dns_net_sec_tests/logs/ghaymah_execution.log';
const RESULTS_FILE = 'D:/cumin/ghaymah_dns_net_sec_tests/logs/ghaymah_test_results.json';
const testResults = [];
let logLines = [];
function log(phase, title, output = '') {
const ts = new Date().toISOString();
const header = `[${ts}] [${phase}] ${title}`;
console.log(header);
logLines.push(header);
if (output) {
console.log(output);
logLines.push(output);
}
logLines.push('');
fs.writeFileSync(LOG_FILE, logLines.join('\n'));
}
function recordResult(category, testName, status, details) {
testResults.push({
timestamp: new Date().toISOString(),
category,
testName,
status, // 'PASS' | 'FAIL' | 'BLOCKED' | 'INFO'
details
});
fs.writeFileSync(RESULTS_FILE, JSON.stringify(testResults, null, 2));
}
async function main() {
log('INIT', '=== STARTING COMPREHENSIVE GHAYMAH PLATFORM TESTS ===');
log('INIT', 'Target: Ghaymah Systems (deploy.ghaymah.systems)');
log('INIT', 'Project: dns-tcp-test (3f55ceef-78ae-40c8-a41b-0505db8c59ee)');
log('INIT', 'Client Container: client-terminal (tsl0922/ttyd:alpine)');
log('INIT', 'Target Container: test-redis (redis:alpine)');
const term = new RemoteTerminal();
await term.connect();
log('INIT', 'RemoteTerminal connected via WebSocket to Ghaymah pod!');
// Install netcat or tools if needed (busybox already has nc, nslookup, wget, ip, etc.)
log('PRE-FLIGHT', 'Checking container environment tools...');
const toolsCheck = await term.exec('which nslookup nc wget ip awk grep');
log('PRE-FLIGHT', 'Available tools in Alpine container:', toolsCheck.output);
// ══════════════════════════════════════════════════════════
// PHASE 3.1: CONTAINER ENVIRONMENT & NETWORK ARCHITECTURE
// ══════════════════════════════════════════════════════════
log('PHASE3-ENV', '=== PHASE 3.1: CONTAINER ENVIRONMENT & NETWORK DISCOVERY ===');
const whoami = await term.exec('whoami && id && hostname');
log('PHASE3-ENV', 'Container identity:', whoami.output);
recordResult('Environment', 'Container Identity', 'INFO', whoami.output);
const ipAddr = await term.exec('ip addr');
log('PHASE3-ENV', 'Network interfaces (ip addr):', ipAddr.output);
recordResult('Environment', 'Network Interfaces', 'INFO', ipAddr.output);
const ipRoute = await term.exec('ip route');
log('PHASE3-ENV', 'Routing table (ip route):', ipRoute.output);
recordResult('Environment', 'Routing Table', 'INFO', ipRoute.output);
const resolvConf = await term.exec('cat /etc/resolv.conf');
log('PHASE3-ENV', 'DNS Configuration (/etc/resolv.conf):', resolvConf.output);
recordResult('Environment', 'DNS Configuration', 'INFO', resolvConf.output);
// ══════════════════════════════════════════════════════════
// PHASE 3.2: INTERNAL DNS VERIFICATION
// ══════════════════════════════════════════════════════════
log('PHASE3-DNS', '=== PHASE 3.2: INTERNAL DNS VERIFICATION ===');
log('PHASE3-DNS', 'Objective: Prove App A discovers App B using internal DNS hostnames (not direct IP)');
// Pattern 1: Short hostname 'test-redis'
log('PHASE3-DNS', 'Test 1: nslookup test-redis');
const dns1 = await term.exec('nslookup test-redis');
log('PHASE3-DNS', 'Result (test-redis):', dns1.output);
const dns1Pass = dns1.exitCode === 0 && (dns1.output.includes('Address') || dns1.output.includes('10.'));
recordResult('Internal DNS', 'Short Hostname Resolution (test-redis)', dns1Pass ? 'PASS' : 'FAIL', {
command: 'nslookup test-redis',
output: dns1.output,
exitCode: dns1.exitCode
});
// Pattern 2: Search domain expansion via /etc/hosts or getent
log('PHASE3-DNS', 'Test 2: getent hosts test-redis');
const dns2 = await term.exec('getent hosts test-redis || ping -c 1 -W 2 test-redis');
log('PHASE3-DNS', 'Result (getent / ping test-redis):', dns2.output);
recordResult('Internal DNS', 'Resolver Lookup (test-redis)', dns2.exitCode === 0 ? 'PASS' : 'FAIL', dns2.output);
// Pattern 3: Namespace-qualified FQDN
// Search domain in resolv.conf was: d62f9886-fced-4cf2-98e4-5b62000d4f03.svc.cluster.local
const fqdn = 'test-redis.d62f9886-fced-4cf2-98e4-5b62000d4f03.svc.cluster.local';
log('PHASE3-DNS', `Test 3: nslookup ${fqdn}`);
const dns3 = await term.exec(`nslookup ${fqdn}`);
log('PHASE3-DNS', `Result (${fqdn}):`, dns3.output);
recordResult('Internal DNS', 'Kubernetes FQDN Resolution', dns3.exitCode === 0 ? 'PASS' : 'FAIL', dns3.output);
// Pattern 4: Mesh-style DNS patterns (if configured by mesh/service router)
const meshPatterns = [
'test-redis.mesh',
'test-redis.dns-tcp-test.mesh',
'test-redis.local',
'test-redis.internal'
];
for (const mName of meshPatterns) {
const dRes = await term.exec(`nslookup ${mName}`);
log('PHASE3-DNS', `Pattern ${mName}:`, dRes.output);
recordResult('Internal DNS Pattern Check', mName, dRes.exitCode === 0 ? 'PASS' : 'NXDOMAIN', dRes.output);
}
// ══════════════════════════════════════════════════════════
// PHASE 3.3: RAW TCP CONNECTIONS OVER PRIVATE NETWORK
// ══════════════════════════════════════════════════════════
log('PHASE3-TCP', '=== PHASE 3.3: RAW TCP CONNECTIONS (NON-HTTP) ===');
log('PHASE3-TCP', 'Target: test-redis on port 6379 over private network');
// Test TCP connectivity via DNS hostname
log('PHASE3-TCP', 'Test 1: TCP Port Probe via DNS Hostname (nc -z -w 3 test-redis 6379)');
const tcpProbe = await term.exec('nc -z -w 3 test-redis 6379');
log('PHASE3-TCP', 'TCP probe exit code:', tcpProbe.exitCode.toString());
recordResult('TCP Connectivity', 'TCP Port 6379 Probe via DNS Hostname', tcpProbe.exitCode === 0 ? 'PASS' : 'FAIL', {
command: 'nc -z -w 3 test-redis 6379',
output: tcpProbe.output,
exitCode: tcpProbe.exitCode
});
// Test Raw TCP Protocol Handshake: Redis PING -> PONG
log('PHASE3-TCP', 'Test 2: Raw TCP Handshake: Send PING\\r\\n -> Expect +PONG\\r\\n');
const pingCmd = 'printf "*1\\r\\n\\$4\\r\\nPING\\r\\n" | nc -w 3 test-redis 6379';
const tcpPing = await term.exec(pingCmd);
log('PHASE3-TCP', 'Redis PING response:', tcpPing.output);
const pingPass = tcpPing.output.includes('+PONG') || tcpPing.output.includes('PONG');
recordResult('TCP Protocol', 'Redis Raw TCP PING/PONG', pingPass ? 'PASS' : 'FAIL', {
command: pingCmd,
output: tcpPing.output,
exitCode: tcpPing.exitCode
});
// Test Raw TCP Data Exchange: SET key and GET key
log('PHASE3-TCP', 'Test 3: Raw TCP Data Exchange: SET ghaymah_test "OK_TCP_WORKS" && GET ghaymah_test');
const redisScript = `
printf "*3\\r\\n\\$3\\r\\nSET\\r\\n\\$12\\r\\nghaymah_test\\r\\n\\$11\\r\\nOK_TCP_PASS\\r\\n" | nc -w 3 test-redis 6379
printf "*2\\r\\n\\$3\\r\\nGET\\r\\n\\$12\\r\\nghaymah_test\\r\\n" | nc -w 3 test-redis 6379
`;
const tcpData = await term.exec(redisScript);
log('PHASE3-TCP', 'Redis SET & GET response:', tcpData.output);
const dataPass = tcpData.output.includes('OK_TCP_PASS');
recordResult('TCP Data Integrity', 'Redis State Storage & Retrieval via Raw TCP', dataPass ? 'PASS' : 'FAIL', {
output: tcpData.output,
exitCode: tcpData.exitCode
});
// ══════════════════════════════════════════════════════════
// PHASE 4.1: SECURITY & PENETRATION TESTING: ISOLATION
// ══════════════════════════════════════════════════════════
log('PHASE4-ISO', '=== PHASE 4.1: SECURITY ISOLATION & SCOPING ===');
log('PHASE4-ISO', 'Objective: Test lateral movement and cross-project isolation');
// Test 1: Cross-Project DNS Resolution
// auth-deploy belongs to project 'auth-deploy' (5bd7e471-6be2-40a8-aff9-268beb29c631)
// scanner-clean belongs to project 'scanner-clean' (19c3ee5e-68c3-4e34-94c9-d03ab6a9df51)
const crossProjectTargets = [
'auth-deploy',
'auth-deploy.mesh',
'auth-deploy.local',
'scanner-clean',
'scanner-clean.mesh'
];
for (const target of crossProjectTargets) {
const xRes = await term.exec(`nslookup ${target}`);
log('PHASE4-ISO', `Cross-project DNS lookup for '${target}':`, xRes.output);
const isolated = xRes.exitCode !== 0 || xRes.output.includes('NXDOMAIN') || xRes.output.includes("can't find");
recordResult('Isolation', `Cross-Project DNS: ${target}`, isolated ? 'BLOCKED (SECURE)' : 'LEAKED (VULNERABLE)', {
target,
output: xRes.output,
exitCode: xRes.exitCode
});
}
// Test 2: Cross-Tenant DNS Resolution
const crossTenantTargets = [
'kubernetes.default.svc',
'metadata.google.internal',
'admin-panel',
'backend.internal',
'database.default'
];
for (const target of crossTenantTargets) {
const ctRes = await term.exec(`nslookup ${target}`);
log('PHASE4-ISO', `Cross-tenant DNS lookup for '${target}':`, ctRes.output);
recordResult('Tenant Isolation', `Cross-Tenant DNS: ${target}`, ctRes.exitCode !== 0 ? 'BLOCKED' : 'RESOLVED', ctRes.output);
}
// Test 3: Lateral Movement via Internal IP Probing
log('PHASE4-ISO', 'Probing adjacent internal IP subnets (10.42.0.0/16, 10.43.0.0/16, 10.100.0.0/16)...');
const probeIps = [
'10.43.0.1', // Kubernetes API Service IP
'10.43.0.10', // CoreDNS Service IP
'10.42.5.1', // Local Pod Subnet Gateway
'10.100.0.1', // WireGuard/Mesh Gateway (if present)
'10.100.0.2',
'172.17.0.1', // Docker bridge
'169.254.169.254'// Cloud Metadata service
];
for (const ip of probeIps) {
const pRes = await term.exec(`nc -z -w 1 ${ip} 80 || nc -z -w 1 ${ip} 443 || nc -z -w 1 ${ip} 53`);
log('PHASE4-ISO', `IP Probe ${ip}: exit code ${pRes.exitCode}`);
recordResult('Network Isolation', `Direct IP Probing: ${ip}`, pRes.exitCode === 0 ? 'ACCESSIBLE' : 'BLOCKED', {
ip,
exitCode: pRes.exitCode
});
}
// ══════════════════════════════════════════════════════════
// PHASE 4.2: NETWORK ENUMERATION & PORT SCANNING
// ══════════════════════════════════════════════════════════
log('PHASE4-SCAN', '=== PHASE 4.2: NETWORK ENUMERATION ===');
log('PHASE4-SCAN', 'Scanning ports on test-redis...');
const portScanScript = `
for p in 22 53 80 443 3000 4000 5432 6379 8080 9000; do
nc -z -w 1 test-redis $p && echo "PORT $p OPEN" || echo "PORT $p CLOSED"
done
`;
const portScan = await term.exec(portScanScript);
log('PHASE4-SCAN', 'Port scan results on test-redis:', portScan.output);
recordResult('Network Enumeration', 'Port Scan test-redis', 'COMPLETED', portScan.output);
// ══════════════════════════════════════════════════════════
// PHASE 4.3: DUAL ROUTING & DNS LEAKS
// ══════════════════════════════════════════════════════════
log('PHASE4-LEAK', '=== PHASE 4.3: DUAL ROUTING & DNS LEAK DETECTION ===');
// Test 1: External HTTP egress
log('PHASE4-LEAK', 'Test 1: External internet egress via HTTP (httpbin.org/ip)...');
const extIp = await term.exec('wget -qO- https://httpbin.org/ip || wget -qO- http://ifconfig.me/ip');
log('PHASE4-LEAK', 'Public Egress IP response:', extIp.output);
const extPass = extIp.exitCode === 0 && extIp.output.length > 5;
recordResult('Dual Routing', 'Outbound Internet Access (Egress)', extPass ? 'PASS' : 'FAIL', extIp.output);
// Test 2: External DNS resolution
const externalDomains = ['google.com', 'github.com', 'cloudflare.com'];
for (const domain of externalDomains) {
const extDns = await term.exec(`nslookup ${domain}`);
log('PHASE4-LEAK', `External DNS resolution for ${domain}:`, extDns.output);
const dnsPass = extDns.exitCode === 0 && extDns.output.includes('Address');
recordResult('DNS Routing', `External DNS Resolution (${domain})`, dnsPass ? 'PASS' : 'FAIL', extDns.output);
}
// Test 3: Check for DNS Leak / Internal vs External Resolver Separation
log('PHASE4-LEAK', 'Testing DNS server handling of non-existent internal domain (leak check)...');
const leakTest = await term.exec('nslookup leak-test-nonexistent-internal-ghaymah.mesh');
log('PHASE4-LEAK', 'Leak test query output:', leakTest.output);
const leakSecure = leakTest.output.includes('NXDOMAIN') || leakTest.output.includes("can't find");
recordResult('DNS Leak Detection', 'Non-existent Mesh Domain Query', leakSecure ? 'SECURE (NXDOMAIN)' : 'ANOMALY', leakTest.output);
term.close();
log('DONE', '=== ALL GHAYMAH PLATFORM TESTS COMPLETED SUCCESSFULLY ===');
}
main().catch(err => {
console.error('FATAL ERROR:', err);
fs.writeFileSync(LOG_FILE, `FATAL: ${err.message}\n${err.stack}`);
});