generatePathTraversalTestCases(); $blocked = 0; $failed = []; foreach ($testCases as $testCase) { $request = $this->createAttackRequest( uri: '/api/files', method: Method::GET, queryParams: ['file' => $testCase['payload']] ); $decision = $this->wafEngine->analyzeRequest($request); if ($decision->shouldBlock()) { $blocked++; } else { $failed[] = $testCase['description']; } } if (!empty($failed)) { throw new \RuntimeException( "WAF failed to block " . count($failed) . " path traversal attacks:\n" . implode("\n", array_slice($failed, 0, 5)) ); } echo "✅ Blocked {$blocked}/" . count($testCases) . " path traversal attacks in file params\n"; } /** * Test WAF blocks path traversal to system files */ public function testBlocksSystemFileAccess(): void { $systemFiles = [ '/etc/passwd', '/etc/shadow', 'C:\\Windows\\System32\\config\\SAM', '/proc/self/environ', '/var/log/apache2/access.log', 'C:\\boot.ini', ]; $blocked = 0; $failed = []; foreach ($systemFiles as $file) { $request = $this->createAttackRequest( uri: '/download', method: Method::GET, queryParams: ['path' => $file] ); $decision = $this->wafEngine->analyzeRequest($request); if ($decision->shouldBlock()) { $blocked++; } else { $failed[] = "System file: {$file}"; } } if (!empty($failed)) { throw new \RuntimeException( "WAF failed to block system file access:\n" . implode("\n", $failed) ); } echo "✅ Blocked {$blocked}/" . count($systemFiles) . " system file access attempts\n"; } /** * Test WAF blocks encoded path traversal */ public function testBlocksEncodedPathTraversal(): void { $encodedAttacks = [ '%2e%2e%2f%2e%2e%2fetc%2fpasswd', // URL encoding '..%252f..%252fetc%252fpasswd', // Double URL encoding '..%c0%af..%c0%afetc%c0%afpasswd', // Unicode encoding '%2e%2e%5c%2e%2e%5cwindows%5csystem32', // Windows path encoded ]; $blocked = 0; $failed = []; foreach ($encodedAttacks as $attack) { $request = $this->createAttackRequest( uri: '/api/download', method: Method::GET, queryParams: ['file' => $attack] ); $decision = $this->wafEngine->analyzeRequest($request); if ($decision->shouldBlock()) { $blocked++; } else { $failed[] = substr($attack, 0, 50); } } if (!empty($failed)) { echo "⚠️ Warning: WAF missed " . count($failed) . " encoded path traversal attacks:\n"; foreach ($failed as $fp) { echo " - {$fp}\n"; } } echo "✅ Blocked {$blocked}/" . count($encodedAttacks) . " encoded path traversal attacks\n"; } /** * Test WAF blocks null byte injection */ public function testBlocksNullByteInjection(): void { $nullByteAttacks = [ '../../../etc/passwd%00.jpg', '../../boot.ini%00.txt', 'malicious.php%00.jpg', ]; $blocked = 0; foreach ($nullByteAttacks as $attack) { $request = $this->createAttackRequest( uri: '/upload', method: Method::POST, postData: ['filename' => $attack] ); $decision = $this->wafEngine->analyzeRequest($request); if ($decision->shouldBlock()) { $blocked++; } } echo "✅ Blocked {$blocked}/" . count($nullByteAttacks) . " null byte injection attacks\n"; } /** * Test WAF allows legitimate file paths */ public function testAllowsLegitimateFilePaths(): void { $legitimatePaths = [ 'documents/report.pdf', 'images/photo.jpg', 'uploads/user123/avatar.png', 'assets/css/style.css', 'public/downloads/manual.pdf', ]; $allowedCount = 0; $falsePositives = []; foreach ($legitimatePaths as $path) { $request = $this->createLegitimateRequest( uri: '/api/files', method: Method::GET, data: ['path' => $path] ); $decision = $this->wafEngine->analyzeRequest($request); if (!$decision->shouldBlock()) { $allowedCount++; } else { $falsePositives[] = $path; } } if (!empty($falsePositives)) { echo "⚠️ Warning: WAF has " . count($falsePositives) . " false positives:\n"; foreach ($falsePositives as $fp) { echo " - {$fp}\n"; } } else { echo "✅ No false positives detected ({$allowedCount}/" . count($legitimatePaths) . " legitimate paths allowed)\n"; } } /** * Test WAF blocks directory listing attempts */ public function testBlocksDirectoryListingAttempts(): void { $directoryAttacks = [ '.', '..', '../', '../../', './', '../../../', ]; $blocked = 0; foreach ($directoryAttacks as $attack) { $request = $this->createAttackRequest( uri: '/api/browse', method: Method::GET, queryParams: ['dir' => $attack] ); $decision = $this->wafEngine->analyzeRequest($request); if ($decision->shouldBlock()) { $blocked++; } } echo "✅ Blocked {$blocked}/" . count($directoryAttacks) . " directory listing attempts\n"; } /** * Run all path traversal tests */ public function runAllTests(): array { $results = []; try { $this->testBlocksPathTraversalInFileParams(); $results['file_params'] = 'PASS'; } catch (\Exception $e) { $results['file_params'] = 'FAIL: ' . $e->getMessage(); } try { $this->testBlocksSystemFileAccess(); $results['system_files'] = 'PASS'; } catch (\Exception $e) { $results['system_files'] = 'FAIL: ' . $e->getMessage(); } try { $this->testBlocksEncodedPathTraversal(); $results['encoded_attacks'] = 'PASS'; } catch (\Exception $e) { $results['encoded_attacks'] = 'FAIL: ' . $e->getMessage(); } try { $this->testBlocksNullByteInjection(); $results['null_byte'] = 'PASS'; } catch (\Exception $e) { $results['null_byte'] = 'FAIL: ' . $e->getMessage(); } try { $this->testAllowsLegitimateFilePaths(); $results['false_positives'] = 'PASS'; } catch (\Exception $e) { $results['false_positives'] = 'FAIL: ' . $e->getMessage(); } try { $this->testBlocksDirectoryListingAttempts(); $results['directory_listing'] = 'PASS'; } catch (\Exception $e) { $results['directory_listing'] = 'FAIL: ' . $e->getMessage(); } return $results; } }