diff --git a/.gemini/GEMINI.md b/.gemini/GEMINI.md index b284dfd..f9d8f8b 100644 --- a/.gemini/GEMINI.md +++ b/.gemini/GEMINI.md @@ -93,7 +93,24 @@ O repositório conta com um script de automação híbrido (`producao/scripts/de - **Causa**: O arquivo `snippets/modsecurity.conf` já define `modsecurity_rules_file`. Se você incluir esse snippet E também definir a diretiva `modsecurity_rules_file` no bloco `server` (ex: `ferreirareal.com.br.conf`), o Nginx falhará. - **Solução**: Use apenas `include snippets/modsecurity.conf;` no bloco server. A diretiva `modsecurity_rules_file /etc/nginx/modsec/main.conf;` deve ficar comentada ou removida do vhost. -### 2. Falhas Silenciosas de Rollback +### 2. Scripts de Diagnóstico e Recuperação (2026-02-08) + +Foram criados scripts auxiliares em `producao/scripts/` para situações de emergência ou validação profunda. Use-os com cautela: + +- **`restore_nginx.py`**: + - **Função**: Força o upload do `nginx.conf` local para o servidor e reinicia o serviço. + - **Uso**: `python producao/scripts/restore_nginx.py` + - **Quando usar**: Se o `deploy_pathfinder.py` falhar ou se o Nginx não subir por erro de configuração crítica (ex: variáveis faltando). +- **`fetch_logs.py`**: + - **Função**: Baixa logs específicos do servidor para análise local. + - **Uso**: `python producao/scripts/fetch_logs.py` + - **Quando usar**: Para investigar ataques ou erros sem precisar logar via SSH. +- **`verify_time_and_logs.py`**: + - **Função**: Verifica a data do servidor e os últimos logs de acesso. + - **Uso**: `python producao/scripts/verify_time_and_logs.py` + - **Quando usar**: Para confirmar se o timezone está correto (-0300) e se o Nginx está gerando logs novos. + +### 3. Falhas Silenciosas de Rollback - **Cuidado**: O script `deploy_pathfinder.py` executa um rollback automático se `nginx -t` falhar. - **O que acontece**: O script restaura o backup anterior e reinicia o Nginx. Isso faz o deploy parecer bem-sucedido (exit code 0), mas seus arquivos novos foram descartados. - **Verificação**: **SEMPRE** verifique o timestamp dos arquivos remotos após um deploy crítico para garantir que foram atualizados: diff --git a/README.md b/README.md index 685d838..73cb358 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ A configuração é modular para permitir manutenção rápida e alta disponibil - `snippets/`: Componentes reutilizáveis (SSL, Proxy, Cache, WAF, Headers). - `modsec/`: Configuração do ModSecurity, regras **OWASP CRS v4** e tunings específicos. - `dynamic/`: Arquivos modificados em tempo real (ex: `blacklist.conf` pelo Fail2Ban). -- `scripts/`: Scripts de utilidade (Ex: `install_modsecurity.sh`). +- `scripts/`: Scripts de automação e diagnóstico (`deploy_pathfinder.py`, `restore_nginx.py`, `fetch_logs.py`). --- @@ -78,9 +78,9 @@ O Pathfinder Proxy utiliza o **ModSecurity v3** compilado sob medida para o Ngin --- -## 🧠 Motor de Segurança PSDE "Elite" (7-Vector Matrix) +## 🧠 Motor de Segurança PSDE "Elite" (8-Vector Matrix) -Diferente de firewalls comuns, o Pathfinder utiliza uma **Matriz de Pontuação Combinatória** no `security_maps.conf` que analisa 7 vetores simultâneos: +Diferente de firewalls comuns, o Pathfinder utiliza uma **Matriz de Pontuação Combinatória** no `security_maps.conf` que analisa 8 vetores simultâneos: 1. **🛡️ Bot:** Bloqueio de 600+ user-agents maliciosos. 2. **🌐 URI:** Acesso a arquivos sensíveis e assinaturas de CVEs recentes. @@ -89,9 +89,10 @@ Diferente de firewalls comuns, o Pathfinder utiliza uma **Matriz de Pontuação 5. **🌍 Geo:** Risco por país (CN, RU, KP, IR) via **GeoIP2**. 6. **🚦 Protocol:** Violações como User-Agents vazios ou falsificados. 7. **🔗 Referer:** 400+ domínios de spam e phishing bloqueados instantaneamente. +8. **🤯 Header:** Detecção de anomalias em cabeçalhos customizados (ex: React2Shell CVE-2025-55182). ### 📈 Lógica de Decisão -- **Nivel 3 (ATAQUE_CRITICO)**: Payloads maliciosos, Referer Spam ou qualquer combinação de 3+ vetores. +- **Nivel 3 (ATAQUE_CRITICO)**: Payloads maliciosos, Referer Spam, Headers Corrompidos ou combinação de 3+ vetores. - **Nivel 2 (RISCO_ALTO)**: Combinação de 2 vetores de risco (ex: Bot + Geo-Risco). - **Nivel 1 (SUSPEITO)**: Detecção de sinais individuais. diff --git a/nginx/nginx.conf b/nginx/nginx.conf index f046377..fb947c6 100644 --- a/nginx/nginx.conf +++ b/nginx/nginx.conf @@ -1,4 +1,5 @@ -# NGINX Master Configuration - Pathfinder Proxy +# Nginx Master Configuration - Pathfinder Proxy +env TZ=America/Sao_Paulo; # Load essential modules load_module modules/ngx_http_modsecurity_module.so; @@ -89,7 +90,7 @@ http { access_log /var/log/nginx/access_json.log detailed_proxy; # Logging Human Readable - For Docker Logs / User - access_log /dev/stdout combined; + # access_log /dev/stdout combined; # SSL Settings (Global) ssl_session_cache shared:SSL:50m; diff --git a/scripts/fetch_logs.py b/scripts/fetch_logs.py new file mode 100644 index 0000000..e668537 --- /dev/null +++ b/scripts/fetch_logs.py @@ -0,0 +1,44 @@ +import paramiko +import os +import time + +SERVER_HOST = "172.17.0.253" +SERVER_USER = "itguys" +PASSWORD = "vR7Ag$Pk" + +def fetch_log(remote_path, local_path): + print(f"[*] Fetching {remote_path} -> {local_path}") + client = paramiko.SSHClient() + client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + + try: + client.connect(SERVER_HOST, username=SERVER_USER, password=PASSWORD) + + # Usando sudo cat para garantir acesso + stdin, stdout, stderr = client.exec_command(f"echo '{PASSWORD}' | sudo -S tail -n 50 {remote_path}", get_pty=False) + + # Captura a saída + content = stdout.read().decode('utf-8') + err = stderr.read().decode('utf-8') + + if content: + with open(local_path, 'w', encoding='utf-8') as f: + f.write(content) + print(f" [OK] Salvo em {local_path}") + else: + print(f" [!] Nenhum conteúdo ou erro: {err}") + + client.close() + except Exception as e: + print(f" [!] Erro: {e}") + +if __name__ == "__main__": + if not os.path.exists("logs"): + os.makedirs("logs") + + fetch_log("/etc/nginx/nginx.conf", "logs/remote_nginx.conf") + client = paramiko.SSHClient() + client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + client.connect(SERVER_HOST, username=SERVER_USER, password=PASSWORD) + fetch_log("/var/log/nginx/ferreirareal.com.br.access.log", "logs/ferreirareal.access.log") + fetch_log("/var/log/nginx/access.log", "logs/global.access.log") diff --git a/scripts/restore_nginx.py b/scripts/restore_nginx.py new file mode 100644 index 0000000..c0f3b17 --- /dev/null +++ b/scripts/restore_nginx.py @@ -0,0 +1,58 @@ +import paramiko +import os + +SERVER_HOST = "172.17.0.253" +SERVER_USER = "itguys" +PASSWORD = "vR7Ag$Pk" + +def restore_nginx(): + client = paramiko.SSHClient() + client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + client.connect(SERVER_HOST, username=SERVER_USER, password=PASSWORD) + + local_file = "producao/nginx/nginx.conf" + remote_tmp = "/tmp/nginx.conf" + dest_file = "/etc/nginx/nginx.conf" + + # 1. Upload to /tmp + print(f"[*] Uploading {local_file} -> {remote_tmp}") + sftp = client.open_sftp() + sftp.put(local_file, remote_tmp) + sftp.close() + + # 2. Check File Difference (Optional but good for log) + cmd = f"echo '{PASSWORD}' | sudo -S diff {remote_tmp} {dest_file}" + stdin, stdout, stderr = client.exec_command(cmd) + # print(stdout.read().decode()) # Might be large + + # 3. Move to /etc/nginx/ + print(f"[*] Overwriting {dest_file}...") + cmd = f"echo '{PASSWORD}' | sudo -S cp {remote_tmp} {dest_file}" + stdin, stdout, stderr = client.exec_command(cmd) + print(stdout.read().decode()) + print(stderr.read().decode()) + + # 4. Test Config + print("[*] Testing Nginx Config...") + cmd = f"echo '{PASSWORD}' | sudo -S nginx -t" + stdin, stdout, stderr = client.exec_command(cmd) + out = stdout.read().decode() + err = stderr.read().decode() + print(out) + print(err) + + if "successful" in err or "successful" in out: + # 5. Restart + print("[*] Restarting Nginx...") + cmd = f"echo '{PASSWORD}' | sudo -S systemctl restart nginx" + stdin, stdout, stderr = client.exec_command(cmd) + print(stdout.read().decode()) + print(stderr.read().decode()) + print("[*] DONE. Service should be UP.") + else: + print("[!] Config Test Failed. Not restarting.") + + client.close() + +if __name__ == "__main__": + restore_nginx() diff --git a/scripts/verify_time_and_logs.py b/scripts/verify_time_and_logs.py new file mode 100644 index 0000000..40f2452 --- /dev/null +++ b/scripts/verify_time_and_logs.py @@ -0,0 +1,35 @@ +import paramiko +import time + +SERVER_HOST = "172.17.0.253" +SERVER_USER = "itguys" +PASSWORD = "vR7Ag$Pk" + +def verify(): + client = paramiko.SSHClient() + client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + client.connect(SERVER_HOST, username=SERVER_USER, password=PASSWORD) + + with open("logs/verify_logs.txt", "w", encoding="utf-8") as f: + f.write("--- Server Date ---\n") + cmd = f"echo '{PASSWORD}' | sudo -S date" + stdin, stdout, stderr = client.exec_command(cmd) + f.write(stdout.read().decode()) + + f.write("\n--- Generating Request ---\n") + cmd = "curl -v -k -I https://127.0.0.1/robots.txt" + stdin, stdout, stderr = client.exec_command(cmd) + f.write(stdout.read().decode()) + f.write(stderr.read().decode()) + + time.sleep(2) + + f.write("\n--- Latest Log Entries ---\n") + cmd = f"echo '{PASSWORD}' | sudo -S tail -n 2 /var/log/nginx/access_json.log" + stdin, stdout, stderr = client.exec_command(cmd) + f.write(stdout.read().decode()) + + client.close() + +if __name__ == "__main__": + verify()