🛡️ Playbook de Pentesting | Altrupets Monorepo
Proyecto: altrupets/monorepo
Tecnologías: Flutter (Mobile), NestJS (Backend), Kubernetes (Minikube), Terraform, PostgreSQL
Metodología: Cyber Kill Chain + OWASP Testing Guide
📋 Fase 1: Reconocimiento (Reconnaissance)
1.1 Recolección de Información Pasiva
Actividad
Herramienta
Objetivo
OSINT del repositorio
GitHub, Repogrinder
URLs expuestas, emails, secretos filtrados
指纹识别
Wappalyzer, WhatWeb
Tecnologías detectables
DNS Enumeration
dnsenum, dig
Subdominios, registros MX/SRV
# Escaneo de puertos
nmap -sV -sC -p- < target-ip>
# Descubrimiento de servicios
curl -I http://< backend-url> /health
curl -I http://< mobile-api> /api
# Enumeración de endpoints
ffuf -u http://< target> /FUZZ -w wordlist.txt
1.3 Targets Identificados
Componente
URL/Puerto
Tecnología
Backend API
:3000
NestJS
Frontend Web
:4200
Angular/Django
Mobile App
API Gateway
Flutter
Kubernetes
:6443
Minikube
PostgreSQL
:5432
Database
Redis
:6379
Cache
📋 Fase 2: Análisis de Vulnerabilidades (Vulnerability Assessment)
2.1 Escaneo de Dependencias
# Node.js/NPM
npm audit
npm audit --json > npm-audit.json
# Dart/Flutter
flutter pub deps
dart analyze
# Containers
trivy image < backend-image>
grype < backend-image>
2.2 Escaneo de Configuración
# SAST - Static Application Security Testing
# Backend NestJS
npm run lint
eslint --ext .ts ./apps/backend
# Mobile Flutter
flutter analyze
dart analyze
# IaC Security
tfsec ./infrastructure/terraform
checkov -d ./infrastructure/terraform
# TruffleHog
trufflehog filesystem .
trufflehog github --repo altrupets/monorepo
# GitLeaks
gitleaks detect --source .
2.4 Vulnerabilidades Comunes en Este Proyecto
OWASP Top 10
Componente Afectado
Severidad
Check
A01:2021 Broken Access Control
Backend API
Alta
Verificar RBAC, JWT validation
A02:2021 Cryptographic Failures
Secrets Management
Alta
Revisar .env, Infisical config
A03:2021 Injection
Backend API, DB
Crítica
SQLi, NoSQLi, Command Injection
A04:2021 Insecure Design
Mobile App
Media
Binary patching, SSL pinning bypass
A05:2021 Security Misconfiguration
K8s, Terraform
Alta
RBAC, network policies, secrets
A06:2021 Vulnerable Components
Dependencies
Media
npm audit, trivy
A07:2021 Auth Failures
Backend, Mobile
Alta
JWT, OAuth, MFA
A08:2021 Data Integrity Failures
CI/CD
Media
Pipeline security
A09:2021 Logging Failures
Backend
Media
Log injection, PII exposure
A10:2021 SSRF
Backend API
Alta
URL parsing, file access
📋 Fase 3: Explotación (Exploitation)
3.1 Web Application Testing
# SQL Injection
sqlmap -u " http://api.example.com/user?id=1" --batch
# XSS
# Reflected
curl " http://api.example.com/search?q=<script>alert(1)</script>"
# Stored - analizar campos de input
# IDOR
# Manipular IDs en requests REST
GET /api/users/1 -> GET /api/users/2
# JWT Attacks
jwt_tool.py < token> -T
3.2 Mobile App Testing (Flutter)
# Extracción de APK
apktool d app.apk
# Análisis estático
jadx app.apk
# SSL Pinning Bypass
# Using Frida
frida -U -f com.altrupets.app -l ssl-pinning-bypass.js
# Root/Jailbreak Detection Bypass
frida -U -f com.altrupets.app -l root-bypass.js
# Enumeración de endpoints
ffuf -u https://api.altrupets.com/FUZZ -w raft-large-words.txt -mc 200,401,403
# Auth bypass
# JWT None Algorithm
{" alg" :" none" }
# Mass assignment
# Modificar parámetros JSON
{" role" : " admin" , " user_id" : 1}
3.4 Kubernetes Pentesting
# Enumeración
kubectl get pods --all-namespaces
kubectl get secrets --all-namespaces
# Pod escape
# If privileged: mount host filesystem
kubectl get pod < pod-name> -o yaml | grep -i privileged
# Service Account tokens
kubectl exec < pod-name> -- cat /run/secrets/kubernetes.io/serviceaccount/token
📋 Fase 4: Análisis de Tráfico (Traffic Analysis)
# Wireshark
# Capturar tráfico HTTP/HTTPS
# Filter: http.request.method == POST
# TCPdump
tcpdump -i any -w capture.pcap port 3000 or port 5432
# Mitmproxy para tráfico mobile
mitmproxy -p 8080
4.2 Análisis de Tráfico Cifrado
# Extraer certificados
# Android: /system/etc/security/cacerts
# SSL/TLS Analysis
# Verificar configuración TLS
testssl.sh https://api.altrupets.com
# heartbeat/heartbleed
nmap -p 443 --script ssl-heartbleed < target>
4.3 Indicators of Compromise (IoC)
Tipo
Indicador
Acción
DNS
*.evil.com
Bloquear en firewall
IP
192.168.1.100
Investigar origen
Hash
a1b2c3d4...
Agregar a blacklist
URL
/admin/exploit.php
Remover/delist
📋 Fase 5: Post-Explotación (Post-Exploitation)
5.1 Escalación de Privilegios
# Linux
# Enumeration
linpeas.sh
linenum.sh
# Kernel exploits
uname -a
searchsploit linux kernel < version>
# Sudo misconfigurations
sudo -l
# SSH pivoting
ssh -J jump-server target-host
# Kubernetes lateral movement
# Between pods
kubectl exec -it < pod-a> -- bash
# Service account abuse
# Kubernetes
# Backdoor via Deployment
kubectl expose deployment < name> --port=4444
# SSH keys
# Agregar public key a authorized_keys
# Data
# Identificar datos sensibles
find / -type f -name " *.env" -o -name " *.key"
# DNS Exfiltration
# Review DNS queries to attacker domain
📋 Fase 6: Reporte y Remediación
Rating
Score
Descripción
Critical
9.0-10.0
Immediate action required
High
7.0-8.9
Urgent remediation
Medium
4.0-6.9
Plan remediation
Low
0.1-3.9
Monitor
None
0.0
No action
6.2 Plantilla de Hallazgos
## Finding #X: [ Título]
### Severity: [ Critical|High|Medium|Low]
### CVSS: [ Score]
### Component: [ Backend|Mobile|K8s|Terraform]
### Description
[ Descripción detallada]
### Proof of Concept
[ Código/explotación]
### Impact
[ Impacto negocio/técnico]
### Remediation
[ Recomendación específica]
6.3 Priorización de Remediación
Prioridad
Tipo
Timeline
P1
RCE, SQLi, Auth bypass
24-48 hrs
P2
IDOR, XXE, SSRF
1 semana
P3
XSS, Info disclosure
2 semanas
P4
Best practices
Sprint actual
🔧 Herramientas Recomendadas
Herramienta
Uso
Nmap
Escaneo de puertos
ffuf
Fuzzing web
Wappalyzer
Fingerprinting
Herramienta
Uso
Burp Suite
Web proxy
OWASP ZAP
Web testing
sqlmap
SQL Injection
jwt_tool
JWT attacks
Metasploit
Exploitation
Herramienta
Uso
Frida
Dynamic analysis
Jadx
Decompilation
MobSF
Mobile SAST
Herramienta
Uso
kube-hunter
K8s penetration
kube-bench
CIS benchmark
kubectl
Enumeration
📋 Fase 7: Automatización DevSecOps (CI/CD Pipeline)
Objetivo: Automatizar las fases de Reconocimiento (Fase 1) y Análisis de Vulnerabilidades (Fase 2) dentro del pipeline de CI/CD para detectar vulnerabilidades base antes de cada despliegue a Staging/Producción.
7.1 Arquitectura Conceptual
┌─────────────────────────────────────────────────────────────────────────────┐
│ DEVSECOPS PIPELINE ARCHITECTURE │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────────┐ ┌──────────────────┐ │
│ │ BUILD │───▶│ TEST │───▶│SECURITY SCAN │───▶│ REPORT │ │
│ └─────────┘ └─────────┘ └─────────────┘ └──────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ STAGE GATES │ │
│ ├─────────────────┤ │
│ │ Critical: HALT │ │
│ │ High: HALT │ │
│ │ Medium: WARN │ │
│ │ Low: INFO │ │
│ └─────────────────┘ │
│ │
│ SECURITY SCAN STAGES: │
│ ├── 1. SCA (Trivy) → Dependency vulnerabilities │
│ ├── 2. DAST (OWASP ZAP) → Web application scanning │
│ ├── 3. Infra (Nmap) → Port/service discovery │
│ └── 4. Secrets (Gitleaks)│ Hardcoded secrets │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
7.2 GitHub Actions Workflow
# .github/workflows/security-scan.yml
name : 🛡️ DevSecOps Security Scan
on :
push :
branches : [main, develop, staging, production]
pull_request :
branches : [main, develop]
schedule :
- cron : ' 0 2 * * *' # Daily at 2 AM
env :
TRIVY_CACHE_DIR : .trivy-cache
ZAP_REPORT_DIR : .zap-reports
SARIF_DIR : .sarif-reports
jobs :
# ═══════════════════════════════════════════════════════════════════════
# STAGE 1: BUILD
# ═══════════════════════════════════════════════════════════════════════
build :
name : Build Application
runs-on : ubuntu-latest
outputs :
image-tag : ${{ steps.meta.outputs.tags }}
steps :
- name : Checkout code
uses : actions/checkout@v4
- name : Set up Docker Buildx
uses : docker/setup-buildx-action@v3
- name : Build Backend Image
uses : docker/build-push-action@v5
with :
context : ./apps/backend
push : false
tags : altrupets/backend:${{ github.sha }}
cache-from : type=registry,ref=altrupets/backend:buildcache
cache-to : type=registry,ref=altrupets/backend:buildcache,mode=max
- name : Generate image metadata
id : meta
run : |
echo "tags=altrupets/backend:${{ github.sha }}" >> $GITHUB_OUTPUT
# ═══════════════════════════════════════════════════════════════════════
# STAGE 2: TEST
# ═══════════════════════════════════════════════════════════════════════
test :
name : Run Tests
runs-on : ubuntu-latest
steps :
- uses : actions/checkout@v4
- name : Setup Node.js
uses : actions/setup-node@v4
with :
node-version : ' 20'
cache : ' npm'
- name : Install dependencies
run : npm ci
- name : Run unit tests
run : npm test -- --coverage
- name : Run linter
run : npm run lint
# ═══════════════════════════════════════════════════════════════════════
# STAGE 3: SECURITY SCANS
# ═══════════════════════════════════════════════════════════════════════
# ─────────────────────────────────────────────────────────────────────────
# 3A: SCA - Dependency Vulnerability Scanning (Trivy)
# ─────────────────────────────────────────────────────────────────────────
trivy-sca :
name : Trivy SCA Scan
runs-on : ubuntu-latest
needs : build
steps :
- uses : actions/checkout@v4
- name : Run Trivy vulnerability scanner (fs mode)
uses : aquasecurity/trivy-action@master
with :
scan-type : ' fs'
scan-ref : ' .'
format : ' sarif'
output : ' trivy-results.sarif'
severity : ' CRITICAL,HIGH,MEDIUM'
ignore-unfixed : true
- name : Upload Trivy results to GitHub Security
uses : github/codeql-action/upload-sarif@v3
with :
sarif_file : ' trivy-results.sarif'
category : ' trivy-sca'
- name : Check Trivy results
run : |
python3 .github/scripts/check-trivy.py trivy-results.sarif
# ─────────────────────────────────────────────────────────────────────────
# 3B: DAST - Dynamic Application Security Testing (OWASP ZAP)
# ─────────────────────────────────────────────────────────────────────────
zap-scan :
name : OWASP ZAP Scan
runs-on : ubuntu-latest
needs : test
if : github.event_name != 'schedule'
steps :
- uses : actions/checkout@v4
- name : Start application in background
run : |
# For staging/production URLs, use actual URL
if [[ "${{ github.ref }}" == "refs/heads/staging" ]]; then
echo "SCAN_URL=${{ secrets.STAGING_URL }}" >> $GITHUB_ENV
elif [[ "${{ github.ref }}" == "refs/heads/production" ]]; then
echo "SCAN_URL=${{ secrets.PRODUCTION_URL }}" >> $GITHUB_ENV
else
# Start local server for dev branches
echo "SCAN_URL=http://localhost:3000" >> $GITHUB_ENV
fi
- name : Wait for application to be ready
run : sleep 10
- name : Run OWASP ZAP Spider
uses : zaproxy/action-baseline@v0.9.0
with :
target : ' ${{ env.SCAN_URL }}'
spider : ' true'
- name : Run OWASP ZAP Active Scan
uses : zaproxy/action-full-scan@v0.9.0
with :
target : ' ${{ env.SCAN_URL }}'
max_spider_duration : 300
ajax_spider : true
- name : Generate ZAP Report
run : |
python3 .github/scripts/parse-zap.py zap_report.html
- name : Upload ZAP results
uses : actions/upload-artifact@v4
with :
name : zap-report
path : zap_report.html
# ─────────────────────────────────────────────────────────────────────────
# 3C: Infrastructure Scanning (Nmap)
# ─────────────────────────────────────────────────────────────────────────
nmap-scan :
name : Nmap Port Scan
runs-on : ubuntu-latest
needs : test
if : github.event_name == 'schedule' || contains(github.event.head_commit.message, '[infra-scan]')
steps :
- uses : actions/checkout@v4
- name : Install Nmap
run : sudo apt-get install -y nmap
- name : Run Nmap scan
run : |
# Scan only staging/production endpoints
NMAP_TARGETS="${{ secrets.STAGING_IP }} ${{ secrets.PRODUCTION_IP }}"
nmap -sV -sC -p- -oN nmap-results.txt $NMAP_TARGETS
- name : Check for critical open ports
run : |
python3 .github/scripts/check-nmap.py nmap-results.txt
- name : Upload Nmap results
uses : actions/upload-artifact@v4
with :
name : nmap-results
path : nmap-results.txt
# ─────────────────────────────────────────────────────────────────────────
# 3D: Secrets Detection (Gitleaks)
# ─────────────────────────────────────────────────────────────────────────
gitleaks :
name : Gitleaks Secrets Scan
runs-on : ubuntu-latest
steps :
- uses : actions/checkout@v4
with :
fetch-depth : 0
- name : Run Gitleaks
uses : gitleaks/gitleaks-action@v2
env :
GITLEAKS_CONFIG_PATH : .gitleaks.toml
GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
GITLEAKS_LICENSE_KEY : ${{ secrets.GITLEAKS_LICENSE }}
# ═══════════════════════════════════════════════════════════════════════
# STAGE 4: REPORT & GATEKEEPING
# ═══════════════════════════════════════════════════════════════════════
security-report :
name : Security Report
runs-on : ubuntu-latest
needs : [trivy-sca, zap-scan, nmap-scan, gitleaks]
if : always()
outputs :
total-critical : ${{ steps.summary.outputs.critical }}
total-high : ${{ steps.summary.outputs.high }}
steps :
- uses : actions/checkout@v4
- name : Download all artifacts
uses : actions/download-artifact@v4
with :
path : artifacts
- name : Generate summary report
id : summary
run : |
python3 .github/scripts/generate-report.py
- name : Post summary to PR
if : github.event_name == 'pull_request'
run : |
echo "## 🛡️ Security Scan Summary" >> $GITHUB_STEP_SUMMARY
echo "- Critical: ${{ steps.summary.outputs.critical }}" >> $GITHUB_STEP_SUMMARY
echo "- High: ${{ steps.summary.outputs.high }}" >> $GITHUB_STEP_SUMMARY
- name : Fail on Critical/High findings
if : needs.trivy-sca.result == 'failure' || needs.gitleaks.result == 'failure'
run : |
echo "❌ Critical security issues found - blocking deployment"
exit 1
# ═══════════════════════════════════════════════════════════════════════
# STAGE GATE CONFIGURATION
# ═══════════════════════════════════════════════════════════════════════
# ═══════════════════════════════════════════════════════════════════════
# STAGE GATE RULES:
# - CRITICAL: FAIL BUILD immediately
# - HIGH: FAIL BUILD unless explicitly acknowledged
# - MEDIUM: WARN only - allow deployment with notification
# - LOW: INFO only - no action required
# ═══════════════════════════════════════════════════════════════════════
#!/usr/bin/env python3
# .github/scripts/check-trivy.py
"""
Parse Trivy SARIF results and enforce stage gate policy.
CRITICAL/HIGH: Fail build
MEDIUM: Warn only
"""
import sys
import json
from pathlib import Path
def check_trivy_sarif (sarif_path : str ):
with open (sarif_path , 'r' ) as f :
data = json .load (f )
severity_counts = {'CRITICAL' : 0 , 'HIGH' : 0 , 'MEDIUM' : 0 , 'LOW' : 0 }
findings = []
for run in data .get ('runs' , []):
for result in run .get ('results' , []):
level = result .get ('level' , 'warning' )
rule_id = result .get ('ruleId' , 'unknown' )
message = result .get ('message' , {}).get ('text' , '' )
severity = 'MEDIUM'
if 'CRITICAL' in message .upper ():
severity = 'CRITICAL'
elif 'HIGH' in message .upper ():
severity = 'HIGH'
severity_counts [severity ] += 1
findings .append (f"[{ severity } ] { rule_id } : { message } " )
print ("\n === Trivy Scan Results ===" )
for sev , count in severity_counts .items ():
print (f"{ sev } : { count } " )
print ("\n === Findings ===" )
for f in findings [:10 ]:
print (f )
# Stage gate enforcement
if severity_counts ['CRITICAL' ] > 0 :
print ("\n ❌ BLOCKED: Critical vulnerabilities found!" )
sys .exit (1 )
if severity_counts ['HIGH' ] > 0 :
print ("\n ⚠️ WARNING: High vulnerabilities found!" )
print (" Set TRIVY_FAIL_ON_HIGH=false to allow with warning" )
if os .getenv ('TRIVY_FAIL_ON_HIGH' , 'true' ).lower () == 'true' :
sys .exit (1 )
print ("\n ✅ Scan passed - no blocking issues" )
sys .exit (0 )
if __name__ == '__main__' :
import os
sarif_file = sys .argv [1 ] if len (sys .argv ) > 1 else 'trivy-results.sarif'
check_trivy_sarif (sarif_file )
#!/usr/bin/env python3
# .github/scripts/generate-report.py
"""
Aggregate all security scan results into a unified report.
"""
import json
import os
from pathlib import Path
def generate_unified_report ():
report = {
'timestamp' : os .getenv ('GITHUB_RUN_ID' , 'unknown' ),
'scans' : {},
'summary' : {'critical' : 0 , 'high' : 0 , 'medium' : 0 , 'low' : 0 }
}
# Parse Trivy results
trivy_path = Path ('artifacts/trivy-results.sarif' )
if trivy_path .exists ():
with open (trivy_path ) as f :
data = json .load (f )
count = len (data .get ('runs' , [{}])[0 ].get ('results' , []))
report ['scans' ]['trivy' ] = {'findings' : count }
# Generate output
output = f"""
# 🛡️ Security Scan Report
## Summary
- Critical: { report ['summary' ]['critical' ]}
- High: { report ['summary' ]['high' ]}
- Medium: { report ['summary' ]['medium' ]}
- Low: { report ['summary' ]['low' ]}
## Scans Executed
{ chr (10 ).join (f"- { k } : { v ['findings' ]} findings" for k , v in report ['scans' ].items ())}
"""
print (output )
# Set outputs for GitHub Actions
with open (os .environ ['GITHUB_OUTPUT' ], 'a' ) as f :
f .write (f"critical={ report ['summary' ]['critical' ]} \n " )
f .write (f"high={ report ['summary' ]['high' ]} \n " )
if __name__ == '__main__' :
generate_unified_report ()
7.4 Gestión de Falsos Positivos
Strategy
Implementation
Use Case
Suppress file-level
.trivyignore
Ignore known safe dependencies
Suppress rule-level
trivy.yaml / .zapignore
Ignore specific CVE rules
Baseline file
ZAP baseline
Accept current findings, alert on new
Comment-based
// trivy:ignore
Suppress in code comments
Ticket integration
Auto-create issue
Track FP for review
# .trivyignore
# Format: CVE-ID
CVE-2021-44228
CVE-2021-45046
# Ignore dev dependencies
pkg:golang.org/x/net/http2
pkg:github.com/nats-io/nats-server/v2
<!-- .zap/baseline.xml -->
<!-- Baseline: Accept current findings -->
<OWASPZAPReport version =" 2.12.0" >
<site name =" https://staging.altrupets.com" >
<alerts >
<alertname >Missing Anti-CSRF Token">
<risk >Medium</risk >
<confidence >High</confidence >
<accepted >true</accepted >
<justification >API uses alternative CSRF protection</justification >
</alertname >
</alerts >
</site >
</OWASPZAPReport >
7.5 Próximos Pasos (Roadmap)
Phase
Task
Effort
Priority
v1 (This spike)
Trivy + Gitleaks in CI
2 hrs
P0
v1.1
Add OWASP ZAP baseline
4 hrs
P1
v1.2
Add Nmap for infra
4 hrs
P1
v2
Add SAST (Semgrep/CodeQL)
1 día
P2
v2.1
Add container scanning (Clair)
1 día
P2
v3
Integrate with Jira/Linear
2 días
P3
v3.1
Add notification (Slack/Teams)
4 hrs
P3
v4
Add interactive DAST (ZAP API)
1 semana
P4
v5
Add runtime protection (Falco)
1 semana
P4
7.6 Optimización de Rendimiento
# Tips para mantener < 15 minutos:
# 1. Cache de herramientas
- uses : actions/cache@v4
with :
path : .trivy-cache
key : trivy-${{ hashFiles('**/package-lock.json') }}
# 2. Scan en paralelo (jobs independientes)
# 3. Skip scans en dev branches (solo main/staging/production)
# 4. Usar baseline mode (solo diffs)
# 5. Timeout apropiado (max 5-10 min por scan)
# 6. Early exit en Critical findings
📋 Fase 8: Automatización de Pentesting (Toolkit Script)
Objetivo: Crear un script orquestador que ejecute automáticamente las Fases 1 (Reconocimiento) y 2 (Análisis de Vulnerabilidades) consolidadas en un único informe.
8.1 Estructura del Proyecto
pentest-toolkit/
├── automator.py # Script principal (entrypoint)
├── requirements.txt # Dependencias Python
├── config/
│ ├── nuclei-templates # Plantillas Nuclei
│ └── wordlists/ # Listas de palabras
├── scans/ # Output generado
│ └── {target}/
│ ├── subdomains/
│ ├── nmap/
│ ├── nuclei/
│ └── summary.md
└── scripts/
├── parse_nmap.py
└── generate_report.py
8.2 Script Principal (automator.py)
#!/usr/bin/env python3
"""
Pentest Automation Toolkit
==========================
Orquesta ejecución secuencial de herramientas de reconocimiento y escaneo.
Usage:
python automator.py --target example.com
python automator.py --target 192.168.1.1 --ports 1000
"""
import argparse
import subprocess
import os
import sys
import json
import time
import shutil
from pathlib import Path
from datetime import datetime
from typing import Optional
import concurrent .futures
class Colors :
"""Colores para output en consola."""
RED = '\033 [91m'
GREEN = '\033 [92m'
YELLOW = '\033 [93m'
BLUE = '\033 [94m'
CYAN = '\033 [96m'
BOLD = '\033 [1m'
END = '\033 [0m'
class PentestAutomator :
"""Orquestador principal de herramientas de pentesting."""
def __init__ (self , target : str , output_dir : str = "scans" , fast : bool = False ):
self .target = target
self .output_dir = Path (output_dir )
self .target_dir = self .output_dir / target .replace ('.' , '_' )
self .fast = fast
self .results = {
'target' : target ,
'timestamp' : datetime .now ().isoformat (),
'subdomains' : [],
'open_ports' : [],
'vulnerabilities' : [],
'nuclei_findings' : []
}
self ._setup_directories ()
self ._check_dependencies ()
def _setup_directories (self ):
"""Crea estructura de directorios."""
dirs = ['subdomains' , 'nmap' , 'nuclei' , 'web' ]
for d in dirs :
(self .target_dir / d ).mkdir (parents = True , exist_ok = True )
print (f"{ Colors .BLUE } [*] Output: { self .target_dir } { Colors .END } " )
def _check_dependencies (self ):
"""Verifica herramientas requeridas."""
tools = ['nmap' , 'subfinder' , 'nuclei' , 'httpx' ]
missing = []
for tool in tools :
if shutil .which (tool ) is None :
missing .append (tool )
if missing :
print (f"{ Colors .YELLOW } [!] Missing tools: { ', ' .join (missing )} { Colors .END } " )
print (f"{ Colors .CYAN } [*] Install with: apt-get install nmap && go install github.com/projectdiscovery/subfinder/... && go install github.com/projectdiscovery/nuclei/... && go install github.com/projectdiscovery/httpx/...{ Colors .END } " )
def _run_command (self , cmd : list , timeout : int = 300 , capture : bool = True ) -> tuple :
"""Ejecuta comando con manejo de errores y timeout."""
try :
result = subprocess .run (
cmd ,
capture_output = capture ,
text = True ,
timeout = timeout ,
cwd = self .target_dir
)
return result .returncode , result .stdout , result .stderr
except subprocess .TimeoutExpired :
print (f"{ Colors .RED } [!] Timeout: { ' ' .join (cmd [:3 ])} ...{ Colors .END } " )
return - 1 , "" , "Timeout"
except Exception as e :
print (f"{ Colors .RED } [!] Error: { e } { Colors .END } " )
return - 1 , "" , str (e )
def _log_progress (self , stage : str , message : str ):
"""Imprime progreso con formato."""
timestamp = datetime .now ().strftime ("%H:%M:%S" )
print (f"{ Colors .CYAN } [{ timestamp } ]{ Colors .END } { Colors .BOLD } { stage } :{ Colors .END } { message } " )
# ═══════════════════════════════════════════════════════════════════════
# STAGE 1: SUBDOMAIN ENUMERATION
# ═══════════════════════════════════════════════════════════════════════
def enumerate_subdomains (self ) -> list :
"""
Fase 1: Enumeración de subdominios usando subfinder + amass.
"""
self ._log_progress ("STAGE 1" , "Enumerating subdomains..." )
subdomains = set ()
# Subfinder - DNS enumeration
self ._log_progress ("STAGE 1" , "Running subfinder..." )
cmd = ['subfinder' , '-d' , self .target , '-silent' , '-recursive' ]
if self .fast :
cmd .extend (['-threads' , '10' ])
code , stdout , _ = self ._run_command (cmd , timeout = 300 )
if code == 0 and stdout :
found = [line .strip () for line in stdout .splitlines () if line .strip ()]
subdomains .update (found )
self .results ['subdomains' ].extend (found )
# Guardar resultados
output_file = self .target_dir / 'subdomains' / 'all.txt'
with open (output_file , 'w' ) as f :
f .write ('\n ' .join (sorted (subdomains )))
self ._log_progress ("STAGE 1" , f"Found { len (subdomains )} subdomains" )
return list (subdomains )
# ═══════════════════════════════════════════════════════════════════════
# STAGE 2: PORT SCANNING
# ═══════════════════════════════════════════════════════════════════════
def scan_ports (self , hosts : list = None ) -> list :
"""
Fase 2a: Escaneo de puertos con Nmap.
- Quick scan: puertos comunes
- Full scan: todos los puertos (solo si no es fast)
"""
if hosts is None :
hosts = [self .target ]
# Agregar subdominios si son IPs
resolved_hosts = []
for h in hosts :
if h .replace ('.' , '' ).isdigit ():
resolved_hosts .append (h )
all_hosts = list (set (resolved_hosts ))
if not all_hosts :
all_hosts = [self .target ]
self ._log_progress ("STAGE 2" , f"Scanning ports on { len (all_hosts )} hosts..." )
# Quick scan primero
nmap_args = [
'nmap' ,
'-T4' , # Fast timing
'--max-retries' , '2' ,
'--min-rate' , '1000' if self .fast else '500' ,
'-oG' , str (self .target_dir / 'nmap' / 'quick.gnmap' ),
'-oX' , str (self .target_dir / 'nmap' / 'quick.xml' )
]
# Puertos a escanear
if self .fast :
nmap_args .extend (['-p' , '22,80,443,3000,3306,5432,6379,8080,8443' ])
else :
nmap_args .extend (['-p-' ])
nmap_args .append (',' .join (all_hosts ))
self ._log_progress ("STAGE 2" , "Running Nmap quick scan..." )
code , stdout , stderr = self ._run_command (nmap_args , timeout = 600 )
# Parse resultados Nmap
open_ports = self ._parse_nmap_results ()
self .results ['open_ports' ] = open_ports
self ._log_progress ("STAGE 2" , f"Found { len (open_ports )} open ports" )
return open_ports
def _parse_nmap_results (self ) -> list :
"""Parsea resultados Nmap en formato Grepable."""
ports = []
gnmap_file = self .target_dir / 'nmap' / 'quick.gnmap'
if not gnmap_file .exists ():
return ports
with open (gnmap_file , 'r' ) as f :
for line in f :
if '/Open/' in line :
parts = line .split ()
for part in parts :
if '/' in part and 'Open' in part :
port_proto = part .split ('/' )[0 ]
ports .append (port_proto )
return ports
# ═══════════════════════════════════════════════════════════════════════
# STAGE 3: WEB DISCOVERY
# ═══════════════════════════════════════════════════════════════════════
def discover_web_services (self ) -> list :
"""
Fase 2b: Descubrimiento de servicios web con httpx.
"""
self ._log_progress ("STAGE 3" , "Discovering web services..." )
# Usar subdomains encontrados
subs_file = self .target_dir / 'subdomains' / 'all.txt'
if not subs_file .exists ():
# Usar target directo
targets = [self .target ]
else :
with open (subs_file , 'r' ) as f :
targets = [line .strip () for line in f if line .strip ()]
if not targets :
targets = [self .target ]
# httpx para detectar servicios web
cmd = ['httpx' , '-silent' , '-threads' , '50' , '-timeout' , '10' ]
cmd .extend (targets )
code , stdout , _ = self ._run_command (cmd , timeout = 300 )
web_services = []
if code == 0 and stdout :
web_services = [line .strip () for line in stdout .splitlines () if line .strip ()]
# Guardar
output_file = self .target_dir / 'web' / 'web_services.txt'
with open (output_file , 'w' ) as f :
f .write ('\n ' .join (web_services ))
self ._log_progress ("STAGE 3" , f"Found { len (web_services )} web services" )
return web_services
# ═══════════════════════════════════════════════════════════════════════
# STAGE 4: VULNERABILITY SCANNING
# ═══════════════════════════════════════════════════════════════════════
def scan_vulnerabilities (self , targets : list = None ) -> list :
"""
Fase 2c: Escaneo de vulnerabilidades con Nuclei.
"""
self ._log_progress ("STAGE 4" , "Running Nuclei vulnerability scan..." )
if targets is None :
web_file = self .target_dir / 'web' / 'web_services.txt'
if web_file .exists ():
with open (web_file , 'r' ) as f :
targets = [line .strip () for line in f if line .strip ()]
else :
targets = [self .target ]
if not targets :
targets = [f"http://{ self .target } " ]
# Nuclei scan
nuclei_args = [
'nuclei' ,
'-silent' ,
'-json' ,
'-o' , str (self .target_dir / 'nuclei' / 'results.json' ),
'-etags' , 'brainstorm,dos' , # Excluir noisy
'-severity' , 'critical,high,medium'
]
if self .fast :
nuclei_args .extend (['-c' , '25' , '-rate-limit' , '100' ])
else :
nuclei_args .extend (['-c' , '50' , '-rate-limit' , '200' ])
nuclei_args .extend (targets )
self ._log_progress ("STAGE 4" , f"Scanning { len (targets )} targets..." )
code , stdout , stderr = self ._run_command (nuclei_args , timeout = 900 )
# Parse resultados
findings = self ._parse_nuclei_results ()
self .results ['nuclei_findings' ] = findings
self ._log_progress ("STAGE 4" , f"Found { len (findings )} vulnerabilities" )
return findings
def _parse_nuclei_results (self ) -> list :
"""Parsea resultados Nuclei en formato JSON."""
findings = []
nuclei_file = self .target_dir / 'nuclei' / 'results.json'
if not nuclei_file .exists ():
return findings
with open (nuclei_file , 'r' ) as f :
for line in f :
try :
finding = json .loads (line .strip ())
findings .append ({
'target' : finding .get ('matched-at' , '' ),
'template' : finding .get ('template-id' , '' ),
'severity' : finding .get ('info' , {}).get ('severity' , '' ),
'name' : finding .get ('info' , {}).get ('name' , '' ),
'description' : finding .get ('info' , {}).get ('description' , '' )[:200 ]
})
except json .JSONDecodeError :
continue
return findings
# ═══════════════════════════════════════════════════════════════════════
# STAGE 5: REPORT GENERATION
# ═══════════════════════════════════════════════════════════════════════
def generate_summary (self ):
"""
Genera archivo summary.md consolidado.
"""
self ._log_progress ("STAGE 5" , "Generating summary report..." )
critical = [f for f in self .results ['nuclei_findings' ] if f ['severity' ].upper () == 'CRITICAL' ]
high = [f for f in self .results ['nuclei_findings' ] if f ['severity' ].upper () == 'HIGH' ]
medium = [f for f in self .results ['nuclei_findings' ] if f ['severity' ].upper () == 'MEDIUM' ]
report = f"""# 📊 Pentest Scan Summary - { self .target }
> **Fecha:** { self .results ['timestamp' ]}
> **Target:** { self .target }
---
## Executive Summary
| Métrica | Valor |
|---------|-------|
| Subdominios encontrados | { len (self .results ['subdomains' ])} |
| Puertos abiertos | { len (self .results ['open_ports' ])} |
| Servicios web | { len (self .results .get ('web_services' , []))} |
| **Vulnerabilidades críticas** | **{ len (critical )} ** |
| **Vulnerabilidades altas** | **{ len (high )} ** |
| Vulnerabilidades medias | { len (medium )} |
---
## 🔴 Critical Findings
"""
if critical :
for i , f in enumerate (critical , 1 ):
report += f"""
### { i } . { f ['name' ]}
- **Target:** `{ f ['target' ]} `
- **Template:** `{ f ['template' ]} `
- **Description:** { f ['description' ]}
"""
else :
report += "*No critical vulnerabilities found.*\n \n "
report += """
---
## 🟠 High Findings
"""
if high :
for i , f in enumerate (high , 1 ):
report += f"""
### { i } . { f ['name' ]}
- **Target:** `{ f ['target' ]} `
- **Template:** `{ f ['template' ]} `
"""
else :
report += "*No high vulnerabilities found.*\n \n "
report += f"""
- - -
## 📋 Open Ports
{chr(10).join(self.results['open_ports'][:50])}
{chr(10).join(self.results.get('web_services', []))}
---
## 📂 Files Generated
- `subdomains/all.txt` - All discovered subdomains
- `nmap/quick.gnmap` - Nmap grepable results
- `nuclei/results.json` - Nuclei JSON results
---
*Generated by PentestAutomator*
"""
# Guardar reporte
output_file = self.target_dir / 'summary.md'
with open(output_file, 'w') as f:
f.write(report)
print(f"\n{Colors.GREEN}[✓] Report saved to: {output_file}{Colors.END}")
# Print summary to console
print(f"\n{Colors.BOLD}{'='*50}{Colors.END}")
print(f"{Colors.RED}CRITICAL:{Colors.END} {len(critical)} {Colors.YELLOW}HIGH:{Colors.END} {len(high)} {Colors.BLUE}MEDIUM:{Colors.END} {len(medium)}")
print(f"{Colors.BOLD}{'='*50}{Colors.END}")
return output_file
# ═══════════════════════════════════════════════════════════════════════
# MAIN EXECUTION
# ═══════════════════════════════════════════════════════════════════════
def run(self):
"""Ejecuta el pipeline completo."""
print(f"\n{Colors.BOLD}{'='*60}{Colors.END}")
print(f"{Colors.BOLD} PENTEST AUTOMATOR - {self.target}{Colors.END}")
print(f"{Colors.BOLD}{'='*60}{Colors.END}\n")
start_time = time.time()
try:
# Stage 1: Subdomain enumeration
subdomains = self.enumerate_subdomains()
# Stage 2: Port scanning
open_ports = self.scan_ports()
# Stage 3: Web discovery
web_services = self.discover_web_services()
# Stage 4: Vulnerability scanning
if web_services:
vulnerabilities = self.scan_vulnerabilities(web_services)
else:
vulnerabilities = []
# Stage 5: Generate report
report = self.generate_summary()
elapsed = time.time() - start_time
print(f"\n{Colors.GREEN}[✓] Completed in {elapsed/60:.1f} minutes{Colors.END}")
except KeyboardInterrupt:
print(f"\n{Colors.YELLOW}[!] Interrupted by user{Colors.END}")
sys.exit(1)
except Exception as e:
print(f"\n{Colors.RED}[!] Error: {e}{Colors.END}")
sys.exit(1)
def main():
parser = argparse.ArgumentParser(
description='Pentest Automation Toolkit',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
python automator.py --target example.com
python automator.py --target 192.168.1.1 --fast
python automator.py --target subdomains.txt --input-type file
"""
)
parser.add_argument('--target', '-t', required=True,
help='Target domain or IP address')
parser.add_argument('--output', '-o', default='scans',
help='Output directory (default: scans)')
parser.add_argument('--fast', '-f', action='store_true',
help='Fast mode: reduced scan time')
parser.add_argument('--ports', '-p', type=int, default=0,
help='Number of top ports to scan (0 = all)')
parser.add_argument('--input-type', choices=['domain', 'ip', 'file'],
default='domain', help='Input type')
args = parser.parse_args()
automator = PentestAutomator(
target=args.target,
output_dir=args.output,
fast=args.fast
)
automator.run()
if __name__ == '__main__':
main()
8.3 Dependencias (requirements.txt)
# Python dependencies
requests>=2.28.0
colorama>=0.4.6
tqdm>=4.65.0
# Install system tools
# apt-get install nmap
# Install Go tools
# go install github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest
# go install github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
# go install github.com/projectdiscovery/httpx/cmd/httpx@latest
# go install github.com/projectdiscovery/naabu/v2/cmd/naabu@latest
# Install Nuclei templates
# nuclei -ut
8.4 Ejemplo de Output (summary.md)
# 📊 Pentest Scan Summary - altrupets.com
> ** Fecha:** 2026-03-15T14:30:00.000000
> ** Target:** altrupets.com
---
## Executive Summary
| Métrica | Valor |
| ---------| -------|
| Subdominios encontrados | 12 |
| Puertos abiertos | 8 |
| Servicios web | 6 |
| ** Vulnerabilidades críticas** | ** 2** |
| ** Vulnerabilidades altas** | ** 4** |
| Vulnerabilidades medias | 7 |
---
## 🔴 Critical Findings
### 1. Remote Code Execution via API
- ** Target:** ` https://api.altrupets.com/v1/exec `
- ** Template:** ` cve-2024-XXXX-rce `
- ** Description:** The application is vulnerable to RCE through...
---
## 🟠 High Findings
### 1. SQL Injection in /users endpoint
- ** Target:** ` https://api.altrupets.com/users `
### 2. JWT None Algorithm
- ** Target:** ` https://auth.altrupets.com `
---
## 📋 Open Ports
22/tcp OpenSSH 8.9
80/tcp Apache 2.4.52
443/tcp nginx 1.24.0
3000/tcp Node.js
5432/tcp PostgreSQL 15
6379/tcp Redis 7.0
8080/tcp Apache 2.4.52
8443/tcp nginx 1.24.0
https://altrupets.com
https://www.altrupets.com
https://api.altrupets.com
https://auth.altrupets.com
https://staging.altrupets.com
https://admin.altrupets.com
---
*Generated by PentestAutomator*
# Instalación de dependencias
apt-get update && apt-get install -y nmap golang-go
go install github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest
go install github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
go install github.com/projectdiscovery/httpx/cmd/httpx@latest
nuclei -ut
# Ejecución
python3 automator.py --target altrupets.com
python3 automator.py --target 192.168.1.1 --fast
python3 automator.py --target altrupets.com --output /pentest/results
# Output generado
scans/
└── altrupets_com/
├── subdomains/
│ └── all.txt
├── nmap/
│ ├── quick.gnmap
│ └── quick.xml
├── nuclei/
│ └── results.json
├── web/
│ └── web_services.txt
└── summary.md
8.6 Optimizaciones de Rendimiento
Técnica
Implementación
Paralelización
Ejecutar subfinder + nmap en paralelo
Fast flags
Nmap -T4 --min-rate 1000, Nuclei -c 25
Early exit
Detener si se encuentra RCE crítico
Cache
Reutilizar resultados de subfinder
Timeout
5 min subfinder, 10 min nmap, 15 min nuclei
⚠️ Nota: Este playbook debe ejecutarse solo con autorización explícita por escrito del propietario del sistema. Toda prueba debe estar dentro del scope definido.