From 938ee75182009b09814dcb6504b9d191ba84e105 Mon Sep 17 00:00:00 2001 From: xfhg <3227935+xfhg@users.noreply.github.com> Date: Wed, 18 Sep 2024 14:05:47 +0800 Subject: [PATCH 1/2] v1.0.X --- playground/policies/nginx_insecure.yaml | 268 ++++++++++++++++++++++++ playground/policies/test_none.yaml | 26 +++ playground/targets/scan/nginx.conf | 90 ++++++++ 3 files changed, 384 insertions(+) create mode 100644 playground/policies/nginx_insecure.yaml create mode 100644 playground/policies/test_none.yaml create mode 100644 playground/targets/scan/nginx.conf diff --git a/playground/policies/nginx_insecure.yaml b/playground/policies/nginx_insecure.yaml new file mode 100644 index 00000000..53fc11b3 --- /dev/null +++ b/playground/policies/nginx_insecure.yaml @@ -0,0 +1,268 @@ +Policies: + - id: "SCAN-001 Server Tokens" + type: "scan" + filepattern: "nginx.conf" + enforcement: + - environment: "all" + fatal: "true" + exceptions: "false" + confidence: "high" + metadata: + name: "Detect server_tokens on" + description: "Ensure that server_tokens is not enabled to avoid revealing version info." + msg_solution: "Set server_tokens to off in the nginx configuration." + msg_error: "server_tokens is enabled, exposing Nginx version." + tags: + - "security" + - "nginx" + score: "7" + _regex: + - "server_tokens\\s+on;" + + - id: "SCAN-002 SSL Protocols" + type: "scan" + filepattern: "nginx.conf" + enforcement: + - environment: "all" + fatal: "true" + exceptions: "false" + confidence: "high" + metadata: + name: "Detect insecure SSL/TLS protocols" + description: "Detect the use of insecure SSLv3 or TLSv1/TLSv1.1 protocols." + msg_solution: "Use secure TLS versions (TLSv1.2 or higher)." + msg_error: "Insecure SSL/TLS protocols detected." + tags: + - "security" + - "encryption" + - "tls" + score: "9" + _regex: + - "ssl_protocols.*(SSLv3|TLSv1(\\.1)?);" + - "ssl_protocols.*SSLv2;" + + - id: "SCAN-003 Missing HTTP Security Headers" + type: "scan" + filepattern: "nginx.conf" + enforcement: + - environment: "all" + fatal: "true" + exceptions: "false" + confidence: "high" + metadata: + name: "Detect missing HTTP security headers" + description: "Ensure that critical HTTP security headers are set in the nginx configuration." + msg_solution: "Add missing HTTP security headers (Strict-Transport-Security, Content-Security-Policy, etc.)." + msg_error: "Missing HTTP security headers." + tags: + - "security" + - "headers" + score: "8" + _regex: + - "^(?!.*add_header\\s+Strict-Transport-Security)" + - "^(?!.*add_header\\s+Content-Security-Policy)" + - "^(?!.*add_header\\s+X-Frame-Options)" + - "^(?!.*add_header\\s+X-Content-Type-Options)" + - "^(?!.*add_header\\s+Referrer-Policy)" + + - id: "SCAN-004 Missing SSL Certificates" + type: "scan" + filepattern: "nginx.conf" + enforcement: + - environment: "all" + fatal: "true" + exceptions: "false" + confidence: "high" + metadata: + name: "Detect missing SSL certificates" + description: "Ensure SSL certificates and keys are properly configured." + msg_solution: "Add SSL certificate and SSL certificate key to the nginx configuration." + msg_error: "Missing SSL certificate or key in the configuration." + tags: + - "security" + - "ssl" + score: "10" + _regex: + - "^(?!.*ssl_certificate|ssl_certificate_key)" + + - id: "SCAN-005 Weak SSL Ciphers" + type: "scan" + filepattern: "nginx.conf" + enforcement: + - environment: "all" + fatal: "true" + exceptions: "false" + confidence: "high" + metadata: + name: "Detect weak SSL ciphers" + description: "Ensure that weak SSL ciphers (DES, RC4, MD5) are not used." + msg_solution: "Use strong SSL ciphers in the nginx configuration." + msg_error: "Weak SSL ciphers detected (DES, RC4, MD5)." + tags: + - "security" + - "encryption" + - "tls" + score: "9" + _regex: + - "ssl_ciphers.*(DES|RC4|MD5);" + + - id: "SCAN-006 HTTP without HTTPS Redirection" + type: "scan" + filepattern: "nginx.conf" + enforcement: + - environment: "all" + fatal: "true" + exceptions: "false" + confidence: "high" + metadata: + name: "Detect missing HTTPS redirection" + description: "Ensure HTTP traffic is redirected to HTTPS." + msg_solution: "Add redirection from HTTP to HTTPS in the nginx configuration." + msg_error: "HTTP traffic is not redirected to HTTPS." + tags: + - "security" + - "https" + score: "9" + _regex: + - "listen\\s+80;" + - "server\\s*\\{[^\\{]*listen\\s+80[^\\{]*[^#]\\breturn\\s+301\\b.*https;" + + - id: "SCAN-007 Access Logs Disabled" + type: "scan" + filepattern: "nginx.conf" + enforcement: + - environment: "all" + fatal: "true" + exceptions: "false" + confidence: "medium" + metadata: + name: "Detect access_log off" + description: "Ensure access logs are enabled." + msg_solution: "Remove 'access_log off' to enable logging." + msg_error: "Access logs are disabled, which may hide important access data." + tags: + - "security" + - "logging" + score: "6" + _regex: + - "access_log\\s+off;" + + - id: "SCAN-008 Autoindex Enabled" + type: "scan" + filepattern: "nginx.conf" + enforcement: + - environment: "all" + fatal: "true" + exceptions: "false" + confidence: "high" + metadata: + name: "Detect autoindex on" + description: "Ensure directory indexing is not enabled." + msg_solution: "Disable 'autoindex on' to prevent directory listing." + msg_error: "Directory indexing is enabled, which may expose sensitive files." + tags: + - "security" + - "files" + score: "8" + _regex: + - "autoindex\\s+on;" + + - id: "SCAN-009 Large Buffer Size" + type: "scan" + filepattern: "nginx.conf" + enforcement: + - environment: "all" + fatal: "false" + exceptions: "true" + confidence: "medium" + metadata: + name: "Detect large buffer sizes" + description: "Ensure reasonable buffer sizes for client requests and headers." + msg_solution: "Review and reduce buffer sizes if needed." + msg_error: "Large buffer sizes detected, which may lead to memory exhaustion." + tags: + - "security" + - "performance" + score: "5" + _regex: + - "(client_body_buffer_size|client_max_body_size|client_header_buffer_size)\\s+[0-9]+[kK]?[mM]?\\s*;?\\b" + + - id: "SCAN-010 Missing client_max_body_size" + type: "scan" + filepattern: "nginx.conf" + enforcement: + - environment: "all" + fatal: "true" + exceptions: "false" + confidence: "high" + metadata: + name: "Detect missing client_max_body_size" + description: "Ensure that client_max_body_size is set to limit the size of client requests." + msg_solution: "Set a reasonable client_max_body_size in the nginx configuration." + msg_error: "client_max_body_size is not configured." + tags: + - "security" + - "request" + score: "8" + _regex: + - "^(?!.*client_max_body_size)" + + - id: "SCAN-011 Unsafe HTTP Methods" + type: "scan" + filepattern: "nginx.conf" + enforcement: + - environment: "all" + fatal: "true" + exceptions: "false" + confidence: "high" + metadata: + name: "Detect unsafe HTTP methods" + description: "Ensure unsafe HTTP methods (TRACE, DELETE, PUT) are not allowed." + msg_solution: "Disallow unsafe HTTP methods in the nginx configuration." + msg_error: "Unsafe HTTP methods (TRACE, DELETE, PUT) are allowed." + tags: + - "security" + - "http" + score: "9" + _regex: + - "allow_methods.*(TRACE|DELETE|PUT);" + + - id: "SCAN-012 Missing Timeouts" + type: "scan" + filepattern: "nginx.conf" + enforcement: + - environment: "all" + fatal: "true" + exceptions: "false" + confidence: "high" + metadata: + name: "Detect missing timeouts" + description: "Ensure timeouts (keepalive_timeout, client_body_timeout, etc.) are configured." + msg_solution: "Add reasonable timeout values to the nginx configuration." + msg_error: "Timeouts are missing, which may allow long-running connections to exhaust resources." + tags: + - "security" + - "performance" + score: "7" + _regex: + - "^(?!.*(keepalive_timeout|client_body_timeout|client_header_timeout|send_timeout))" + + - id: "SCAN-013 IP Spoofing" + type: "scan" + filepattern: "nginx.conf" + enforcement: + - environment: "all" + fatal: "true" + exceptions: "false" + confidence: "high" + metadata: + name: "Detect IP spoofing vulnerabilities" + description: "Ensure IP spoofing is not allowed by properly setting real IP headers." + msg_solution: "Ensure real IP headers are properly configured in the nginx configuration." + msg_error: "IP spoofing vulnerability detected." + tags: + - "security" + - "ip" + score: "9" + _regex: + - "set_real_ip_from\\s+\\d+\\.\\d+\\.\\d+\\.\\d+;" \ No newline at end of file diff --git a/playground/policies/test_none.yaml b/playground/policies/test_none.yaml new file mode 100644 index 00000000..ae8a1604 --- /dev/null +++ b/playground/policies/test_none.yaml @@ -0,0 +1,26 @@ +# The old COLLECT rule type from intercept v.16.X can be written as (check enforcement slot) + +Policies: + - id: "COLLECT-001 Private Keys" + type: "scan" + enforcement: + - environment: "all" + fatal: "false" + exceptions: "true" + confidence: "info" + metadata: + name: "Detect private keys" + description: "Generic long description for (metadata) policy" + msg_solution: "Generic solution message to production issue." + msg_error: "Generic error message for production issue" + tags: + - "security" + - "encryption" + score: "9" + _regex: + - \s*(-----BEGIN PRIVATE KEY-----) + - \s*(-----BEGIN RSA PRIVATE KEY-----) + - \s*(-----BEGIN DSA PRIVATE KEY-----) + - \s*(-----BEGIN EC PRIVATE KEY-----) + - \s*(-----BEGIN OPENSSH PRIVATE KEY-----) + - \s*(-----BEGIN PGP PRIVATE KEY BLOCK-----) diff --git a/playground/targets/scan/nginx.conf b/playground/targets/scan/nginx.conf new file mode 100644 index 00000000..fbcf0f31 --- /dev/null +++ b/playground/targets/scan/nginx.conf @@ -0,0 +1,90 @@ +user nginx; +worker_processes auto; + +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + # tcp_nopush on; + + keepalive_timeout 65; + # keepalive_timeout set too high can exhaust resources + + server_tokens on; # Insecure: reveals Nginx version to clients + + ssl_protocols SSLv3 TLSv1 TLSv1.1; # Insecure: weak and outdated SSL/TLS protocols + + server { + listen 80; + server_name example.com; + + # Insecure: No HTTPS redirection + # Redirect HTTP to HTTPS (missing) + # return 301 https://$host$request_uri; + + location / { + proxy_pass http://localhost:8080; # Reverse proxy to backend + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Insecure: Directory listing enabled + location /files/ { + autoindex on; # Insecure: Directory listing exposes files to the public + } + } + + server { + listen 443 ssl; + server_name example.com; + + ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt; + ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key; + + # Insecure: Missing security headers + # add_header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload" always; + # add_header X-Frame-Options DENY; + # add_header X-Content-Type-Options nosniff; + # add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self';"; + + location / { + proxy_pass http://localhost:8080; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Insecure: Allows unsafe HTTP methods + location /api/ { + limit_except GET POST { + allow all; # Insecure: TRACE, DELETE, PUT methods may be allowed + } + } + + # Insecure: Access log turned off + access_log off; # Insecure: Lack of logging hides potentially malicious activity + } + + # Insecure: Missing client_max_body_size limit for large requests + client_max_body_size 0; + + # Insecure: Weak SSL ciphers allowed + ssl_ciphers 'DES-CBC3-SHA RC4-MD5 RC4-SHA AES128-SHA'; +} \ No newline at end of file From 66366655c672311ffd6a56259bd4b83ff50fb381 Mon Sep 17 00:00:00 2001 From: xfhg <3227935+xfhg@users.noreply.github.com> Date: Wed, 18 Sep 2024 14:10:14 +0800 Subject: [PATCH 2/2] v1.0.X --- cmd/root.go | 2 +- cmd/sarif.go | 56 ++++++++++++++++++++++++++-------------------------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 3594317b..363ab032 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -116,7 +116,7 @@ func setupLogging() { log.Error().Msgf("Error gathering host info: %v\n", err) } - hostData, hostFingerprint, err := FingerprintHost(hostInfo) + hostData, hostFingerprint, err = FingerprintHost(hostInfo) if err != nil { log.Error().Msgf("Error generating fingerprint: %v\n", err) } diff --git a/cmd/sarif.go b/cmd/sarif.go index 6fef639b..34acc561 100644 --- a/cmd/sarif.go +++ b/cmd/sarif.go @@ -62,6 +62,34 @@ func sarifLevelToString(level SARIFLevel) string { } } +func selectEnforcementRule(policy Policy, environment string) Enforcement { + for _, rule := range policy.Enforcement { + if rule.Environment == environment || rule.Environment == "all" { + return rule + } + } + // If no matching rule is found, return a default rule or the first rule + if len(policy.Enforcement) > 0 { + return policy.Enforcement[0] + } + // If there are no rules at all, return a default rule + return Enforcement{ + Environment: "all", + Fatal: "false", + Exceptions: "false", + Confidence: "low", + } +} + +func calculateSARIFLevel(policy Policy, environment string) SARIFLevel { + selectedRule := selectEnforcementRule(policy, environment) + return PolicyToSARIFLevel( + selectedRule.Fatal == "true", + selectedRule.Exceptions == "true", + selectedRule.Confidence, + ) +} + // RipgrepOutput represents the structure of the ripgrep JSON output type RipgrepOutput struct { Type string `json:"type"` @@ -787,31 +815,3 @@ func GenerateAPISARIFReport(policy Policy, endpoint string, matchFound bool, iss return sarifReport, nil } - -func selectEnforcementRule(policy Policy, environment string) Enforcement { - for _, rule := range policy.Enforcement { - if rule.Environment == environment || rule.Environment == "all" { - return rule - } - } - // If no matching rule is found, return a default rule or the first rule - if len(policy.Enforcement) > 0 { - return policy.Enforcement[0] - } - // If there are no rules at all, return a default rule - return Enforcement{ - Environment: "all", - Fatal: "false", - Exceptions: "false", - Confidence: "low", - } -} - -func calculateSARIFLevel(policy Policy, environment string) SARIFLevel { - selectedRule := selectEnforcementRule(policy, environment) - return PolicyToSARIFLevel( - selectedRule.Fatal == "true", - selectedRule.Exceptions == "true", - selectedRule.Confidence, - ) -}