← Volver al listado de tecnologías

Capítulo 3: Captura y Análisis de Tráfico HTTP/HTTPS

Por: Artiko
owasp-zaphttphttpsinterceptproxyanálisisseguridad

Capítulo 3: Captura y Análisis de Tráfico HTTP/HTTPS

En este capítulo aprenderás las técnicas fundamentales para interceptar, analizar y modificar el tráfico HTTP/HTTPS en tiempo real, una habilidad esencial para la auditoría de seguridad.

🎯 Objetivos del Capítulo

Al finalizar este capítulo serás capaz de:

🚦 Modos de Interceptación

Break Points (Puntos de Interrupción)

ZAP ofrece varios modos para interceptar tráfico:

# Modos de Break Points:
1. Break on all requests - Detener todas las peticiones
2. Break on all responses - Detener todas las respuestas
3. Break on specific URLs - Detener URLs específicas
4. Step through - Avanzar paso a paso
5. Continue - Continuar sin interrupción

Configuración de Break Points

// Activar Break Points
// Botón verde en la barra de herramientas o:
// Break → Break on all requests

// Configuración específica por URL
// Break → Add custom break point
URL Pattern: https://api.ejemplo.com/users/*
Method: POST
Break on: Request & Response

🔍 Interceptación de Peticiones

Interceptar Request Básico

# Ejemplo de request interceptado
GET /api/v1/users/profile HTTP/1.1
Host: api.ejemplo.com
User-Agent: Mozilla/5.0 (Android 11; Mobile)
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Accept: application/json
X-API-Key: abc123xyz789
Cookie: session_id=a1b2c3d4e5f6; user_pref=dark_mode

# Modificaciones posibles:
- Cambiar método (GET → POST)
- Modificar headers
- Alterar parámetros
- Inyectar payloads

Modificación de Peticiones

// Ejemplos de modificaciones comunes
interface RequestModifications {
  // 1. Bypass de validación cliente
  changeUserRole(): void {
    // Original: {"role": "user"}
    // Modificado: {"role": "admin"}
  }

  // 2. Manipulación de precios
  modifyPrice(): void {
    // Original: {"price": 100.00}
    // Modificado: {"price": 0.01}
  }

  // 3. IDOR (Insecure Direct Object Reference)
  accessOtherUser(): void {
    // Original: /api/users/123
    // Modificado: /api/users/456
  }

  // 4. SQL Injection testing
  injectSQL(): void {
    // Original: ?id=1
    // Modificado: ?id=1' OR '1'='1
  }
}

Manipulación de Headers

# Headers de seguridad importantes
Authorization: Bearer [TOKEN] → Bearer [MODIFIED_TOKEN]
X-Forwarded-For: 127.0.0.1 → X-Forwarded-For: 192.168.1.100
Origin: https://trusted.com → Origin: https://evil.com
Referer: https://app.com → Referer: https://attacker.com
X-API-Version: 1.0 → X-API-Version: 2.0
Content-Type: application/json → Content-Type: application/xml

📊 Interceptación de Respuestas

Análisis de Response

# Ejemplo de response interceptado
HTTP/1.1 200 OK
Content-Type: application/json
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Content-Security-Policy: default-src 'self'
Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Strict

{
  "user": {
    "id": 12345,
    "email": "[email protected]",
    "role": "standard",
    "api_key": "secret_key_12345",
    "balance": 1000.00
  }
}

# Análisis de seguridad:
- ✅ Headers de seguridad presentes
- ⚠️ API key expuesta en response
- ✅ Cookie con flags de seguridad
- ⚠️ Información sensible sin cifrar

Modificación de Respuestas

// Casos de uso para modificar respuestas

// 1. Bypass de restricciones del cliente
const bypassLimits = (response) => {
  // Original
  const original = {
    "premium": false,
    "max_downloads": 5,
    "features_enabled": ["basic"]
  };
  
  // Modificado
  const modified = {
    "premium": true,
    "max_downloads": 999,
    "features_enabled": ["basic", "advanced", "premium"]
  };
  
  return modified;
};

// 2. Revelar funcionalidad oculta
const revealHiddenFeatures = (response) => {
  response.ui_elements.admin_panel = true;
  response.ui_elements.debug_mode = true;
  return response;
};

// 3. Modificar validaciones
const alterValidation = (response) => {
  response.validation_rules.min_password_length = 1;
  response.validation_rules.require_2fa = false;
  return response;
};

🔐 Análisis de Autenticación y Sesiones

Tokens JWT

// Decodificar y analizar JWT
interface JWTAnalysis {
  header: {
    alg: string;  // HS256, RS256, none (vulnerabilidad)
    typ: string;
  };
  
  payload: {
    sub: string;      // Subject (user ID)
    iat: number;      // Issued at
    exp: number;      // Expiration
    role: string;     // User role
    permissions: string[];
  };
  
  signature: string;
}

// Herramienta de análisis en ZAP
const analyzeJWT = (token: string): void => {
  // Encode/Decode tab → Base64 Decode
  const parts = token.split('.');
  const header = atob(parts[0]);
  const payload = atob(parts[1]);
  
  console.log('Header:', JSON.parse(header));
  console.log('Payload:', JSON.parse(payload));
  
  // Verificar vulnerabilidades comunes
  checkAlgorithmConfusion(header);
  checkExpirationBypass(payload);
  checkPrivilegeEscalation(payload);
};

Análisis de Cookies

// Inspección de cookies de sesión
const analyzeCookies = (cookies) => {
  cookies.forEach(cookie => {
    console.log(`Cookie: ${cookie.name}`);
    console.log(`Value: ${cookie.value}`);
    console.log(`Flags:`);
    console.log(`  HttpOnly: ${cookie.httpOnly}`);  // Previene XSS
    console.log(`  Secure: ${cookie.secure}`);      // Solo HTTPS
    console.log(`  SameSite: ${cookie.sameSite}`);  // CSRF protection
    console.log(`  Domain: ${cookie.domain}`);
    console.log(`  Path: ${cookie.path}`);
    console.log(`  Expires: ${cookie.expires}`);
    
    // Detectar problemas
    if (!cookie.httpOnly) {
      console.warn('⚠️ Cookie sin HttpOnly - Vulnerable a XSS');
    }
    if (!cookie.secure) {
      console.warn('⚠️ Cookie sin Secure - Puede enviarse por HTTP');
    }
    if (cookie.sameSite === 'None') {
      console.warn('⚠️ SameSite=None - Vulnerable a CSRF');
    }
  });
};

🔍 Análisis de Parámetros

Identificación Automática

# Script Python para ZAP
from zapv2 import ZAPv2
import json

zap = ZAPv2(apikey='tu-api-key')

def analyze_parameters(url):
    # Obtener todos los parámetros de una URL
    params = zap.params.params(site=url)
    
    for param in params:
        print(f"Parámetro: {param['name']}")
        print(f"Tipo: {param['type']}")  # URL, POST, Cookie, Header
        print(f"Valores observados: {param['values']}")
        
        # Analizar el tipo de dato
        if looks_like_id(param['value']):
            test_idor(url, param)
        elif looks_like_sql(param['value']):
            test_sql_injection(url, param)
        elif looks_like_command(param['value']):
            test_command_injection(url, param)

def looks_like_id(value):
    # Detectar IDs numéricos o UUIDs
    import re
    return re.match(r'^\d+$', value) or \
           re.match(r'^[a-f0-9-]{36}$', value)

Fuzzing de Parámetros

// Configuración de Fuzzer en ZAP
const fuzzingConfig = {
  // Payloads para diferentes tipos de pruebas
  sqlInjection: [
    "' OR '1'='1",
    "1' AND '1'='2",
    "' OR '1'='1' --",
    "admin'--",
    "' UNION SELECT NULL--"
  ],
  
  xss: [
    "<script>alert('XSS')</script>",
    "<img src=x onerror=alert('XSS')>",
    "javascript:alert('XSS')",
    "<svg onload=alert('XSS')>",
    "'\"><script>alert('XSS')</script>"
  ],
  
  pathTraversal: [
    "../../../etc/passwd",
    "..\\..\\..\\windows\\system32\\config\\sam",
    "....//....//....//etc/passwd",
    "%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd"
  ],
  
  commandInjection: [
    "; ls -la",
    "| whoami",
    "& net user",
    "`id`",
    "$(whoami)"
  ]
};

// Aplicar fuzzing
function applyFuzzing(request, payloadType) {
  const payloads = fuzzingConfig[payloadType];
  
  payloads.forEach(payload => {
    // Reemplazar parámetro con payload
    const modifiedRequest = request.replace(
      /param=([^&]*)/,
      `param=${encodeURIComponent(payload)}`
    );
    
    // Enviar request modificado
    sendRequest(modifiedRequest);
  });
}

📦 Decodificación y Encoding

Herramientas de Encoding/Decoding

// Funciones de encoding/decoding disponibles en ZAP
interface EncodingTools {
  // Base64
  base64Encode(text: string): string;
  base64Decode(encoded: string): string;
  
  // URL
  urlEncode(text: string): string;
  urlDecode(encoded: string): string;
  
  // HTML
  htmlEncode(text: string): string;
  htmlDecode(encoded: string): string;
  
  // Hex
  hexEncode(text: string): string;
  hexDecode(hex: string): string;
  
  // Hash
  md5(text: string): string;
  sha1(text: string): string;
  sha256(text: string): string;
}

// Ejemplo de uso
const decodeChain = (encodedData: string) => {
  // Datos con múltiples capas de encoding
  let decoded = encodedData;
  
  // 1. URL decode
  decoded = decodeURIComponent(decoded);
  console.log('After URL decode:', decoded);
  
  // 2. Base64 decode
  decoded = atob(decoded);
  console.log('After Base64 decode:', decoded);
  
  // 3. Parse JSON
  const data = JSON.parse(decoded);
  console.log('Final data:', data);
  
  return data;
};

Análisis de Payloads Complejos

// Análisis de payloads serializados
const analyzeSerializedData = (data) => {
  // PHP serialized
  if (data.match(/^a:\d+:{/)) {
    console.log('PHP serialized object detected');
    // Buscar posible object injection
  }
  
  // Java serialized
  if (data.startsWith('rO0AB')) {
    console.log('Java serialized object detected');
    // Posible deserialización insegura
  }
  
  // .NET ViewState
  if (data.match(/^\/wEP/)) {
    console.log('.NET ViewState detected');
    // Verificar MAC validation
  }
  
  // Python pickle
  if (data.includes('pickle')) {
    console.log('Python pickle detected');
    // Riesgo de RCE
  }
};

🎯 Identificación de Vulnerabilidades

Patrones de Vulnerabilidades Comunes

interface VulnerabilityPatterns {
  // Información sensible en respuestas
  sensitiveData: RegExp[];
  
  // Headers inseguros
  insecureHeaders: string[];
  
  // Errores que revelan información
  informationDisclosure: RegExp[];
}

const patterns: VulnerabilityPatterns = {
  sensitiveData: [
    /api[_-]?key/i,
    /password/i,
    /secret/i,
    /token/i,
    /private[_-]?key/i,
    /ssn|social[_-]?security/i,
    /credit[_-]?card/i
  ],
  
  insecureHeaders: [
    'Server',           // Revela versión del servidor
    'X-Powered-By',     // Revela tecnología
    'X-AspNet-Version', // Revela versión de .NET
    'X-Debug-Token'     // Información de debug
  ],
  
  informationDisclosure: [
    /stack[_-]?trace/i,
    /sql[_-]?error/i,
    /exception/i,
    /at line \d+/i,
    /mysql_fetch/i,
    /ORA-\d{5}/i        // Oracle errors
  ]
};

Script de Análisis Automático

# Script para análisis automático en ZAP
import re
from zapv2 import ZAPv2

class TrafficAnalyzer:
    def __init__(self, zap):
        self.zap = zap
        self.vulnerabilities = []
    
    def analyze_message(self, msg_id):
        # Obtener mensaje completo
        msg = self.zap.core.message(msg_id)
        request_header = msg['requestHeader']
        request_body = msg['requestBody']
        response_header = msg['responseHeader']
        response_body = msg['responseBody']
        
        # Analizar request
        self.check_authentication(request_header)
        self.check_injection_points(request_body)
        
        # Analizar response
        self.check_security_headers(response_header)
        self.check_sensitive_data(response_body)
        self.check_error_messages(response_body)
        
        return self.vulnerabilities
    
    def check_sensitive_data(self, body):
        patterns = [
            (r'api[_-]?key["\']?\s*:\s*["\']([^"\']+)', 'API Key expuesta'),
            (r'password["\']?\s*:\s*["\']([^"\']+)', 'Password en texto plano'),
            (r'\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b', 'Posible tarjeta de crédito'),
            (r'\b\d{3}-\d{2}-\d{4}\b', 'Posible SSN'),
            (r'Bearer\s+([A-Za-z0-9\-_=]+\.[A-Za-z0-9\-_=]+\.?[A-Za-z0-9\-_.+/=]*)', 'JWT Token')
        ]
        
        for pattern, description in patterns:
            matches = re.findall(pattern, body, re.IGNORECASE)
            if matches:
                self.vulnerabilities.append({
                    'type': 'Information Disclosure',
                    'description': description,
                    'evidence': matches[0] if len(matches[0]) < 50 else matches[0][:50] + '...'
                })

🔄 Repetición y Modificación de Requests

Replay de Peticiones

// Función para replay con modificaciones
async function replayWithModifications(originalRequest) {
  const modifications = [
    // Test de autorización
    { header: 'Authorization', value: 'Bearer invalid_token' },
    { header: 'Authorization', value: '' },
    
    // Test de IDOR
    { path: '/users/123', newPath: '/users/999' },
    
    // Test de método HTTP
    { method: 'GET', newMethod: 'DELETE' },
    { method: 'POST', newMethod: 'PUT' },
    
    // Test de Content-Type
    { header: 'Content-Type', value: 'application/xml' }
  ];
  
  for (const mod of modifications) {
    const modifiedRequest = applyModification(originalRequest, mod);
    const response = await sendRequest(modifiedRequest);
    
    // Analizar diferencias
    analyzeResponse(response, originalRequest);
  }
}

// Resender en ZAP
// Click derecho en request → Open/Resend with Request Editor
// Modificar y enviar múltiples variaciones

Comparación de Respuestas

// Comparar respuestas para detectar diferencias
interface ResponseComparison {
  statusCode: {
    original: number;
    modified: number;
    different: boolean;
  };
  
  contentLength: {
    original: number;
    modified: number;
    difference: number;
  };
  
  responseTime: {
    original: number;
    modified: number;
    difference: number;
  };
  
  keywords: {
    added: string[];
    removed: string[];
  };
}

function compareResponses(original: string, modified: string): ResponseComparison {
  // Extraer información relevante
  const comparison: ResponseComparison = {
    statusCode: {
      original: extractStatusCode(original),
      modified: extractStatusCode(modified),
      different: false
    },
    contentLength: {
      original: original.length,
      modified: modified.length,
      difference: 0
    },
    responseTime: {
      original: 0,
      modified: 0,
      difference: 0
    },
    keywords: {
      added: [],
      removed: []
    }
  };
  
  // Calcular diferencias
  comparison.statusCode.different = 
    comparison.statusCode.original !== comparison.statusCode.modified;
  
  comparison.contentLength.difference = 
    comparison.contentLength.modified - comparison.contentLength.original;
  
  // Detectar cambios significativos
  if (comparison.statusCode.different) {
    console.log('⚠️ Cambio en status code - posible bypass');
  }
  
  if (Math.abs(comparison.contentLength.difference) > 100) {
    console.log('⚠️ Gran diferencia en tamaño - contenido diferente');
  }
  
  return comparison;
}

📊 WebSockets y Tráfico Especial

Interceptación de WebSockets

// Configuración para WebSockets
const wsInterception = {
  // Habilitar en ZAP
  enable: () => {
    // Tools → Options → WebSockets
    // ☑ Forward all WebSocket messages
    // ☑ Break on all WebSocket messages
  },
  
  // Análisis de mensajes
  analyzeMessage: (message) => {
    const parsed = JSON.parse(message.data);
    
    // Buscar datos sensibles
    if (parsed.token || parsed.sessionId) {
      console.warn('Token/Session en WebSocket');
    }
    
    // Modificar mensaje
    parsed.role = 'admin';
    return JSON.stringify(parsed);
  },
  
  // Inyección en WebSocket
  injectMessage: () => {
    return JSON.stringify({
      type: 'command',
      action: 'elevate_privileges',
      user: 'current'
    });
  }
};

GraphQL Interception

# Interceptar queries GraphQL
query GetUser {
  user(id: "123") {
    id
    email
    role
    # Modificar para obtener más datos
    password  # Añadir campo no autorizado
    apiKey    # Información sensible
  }
}

# Modificar mutations
mutation UpdateUser {
  updateUser(
    id: "123",
    # Cambiar role no autorizado
    role: "admin"  # De "user" a "admin"
  ) {
    success
    user {
      id
      role
    }
  }
}

🛠️ Herramientas Avanzadas de Análisis

Scripts Personalizados

# Script para análisis personalizado
from zapv2 import ZAPv2
import json
import base64

class CustomAnalyzer:
    def __init__(self):
        self.zap = ZAPv2(apikey='tu-api-key')
        self.alerts = []
    
    def analyze_traffic(self, target):
        # Obtener todo el tráfico
        messages = self.zap.core.messages(target)
        
        for msg in messages:
            self.analyze_authentication(msg)
            self.analyze_encryption(msg)
            self.analyze_business_logic(msg)
            self.analyze_rate_limiting(msg)
    
    def analyze_authentication(self, msg):
        # Verificar métodos de autenticación
        auth_header = self.extract_header(msg, 'Authorization')
        
        if not auth_header:
            self.alert('Sin autenticación', 'high')
        elif 'Basic' in auth_header:
            # Decodificar Basic Auth
            encoded = auth_header.split(' ')[1]
            decoded = base64.b64decode(encoded).decode()
            if ':' in decoded:
                user, password = decoded.split(':', 1)
                self.alert(f'Basic Auth detectado: {user}', 'medium')
        elif 'Bearer' in auth_header:
            token = auth_header.split(' ')[1]
            self.analyze_jwt(token)
    
    def analyze_jwt(self, token):
        try:
            # Decodificar JWT sin verificar
            parts = token.split('.')
            header = json.loads(base64.b64decode(parts[0] + '=='))
            payload = json.loads(base64.b64decode(parts[1] + '=='))
            
            # Verificar algoritmo
            if header.get('alg') == 'none':
                self.alert('JWT sin firma (alg: none)', 'critical')
            elif header.get('alg') in ['HS256', 'HS384', 'HS512']:
                self.alert('JWT con clave simétrica', 'info')
            
            # Verificar expiración
            import time
            if 'exp' in payload:
                if payload['exp'] < time.time():
                    self.alert('JWT expirado', 'medium')
            else:
                self.alert('JWT sin expiración', 'medium')
                
        except Exception as e:
            self.alert(f'Error analizando JWT: {e}', 'low')

Exportación de Datos

// Exportar tráfico filtrado
function exportFilteredTraffic(filter) {
  const messages = zap.search.messages(filter);
  const exportData = [];
  
  messages.forEach(msg => {
    exportData.push({
      timestamp: msg.timestamp,
      method: msg.method,
      url: msg.url,
      statusCode: msg.statusCode,
      requestHeaders: parseHeaders(msg.requestHeader),
      requestBody: msg.requestBody,
      responseHeaders: parseHeaders(msg.responseHeader),
      responseBody: msg.responseBody,
      alerts: msg.alerts
    });
  });
  
  // Exportar a diferentes formatos
  saveAsJSON(exportData, 'traffic_analysis.json');
  saveAsCSV(exportData, 'traffic_summary.csv');
  generateHTMLReport(exportData, 'report.html');
}

🔍 Casos de Uso Prácticos

Caso 1: Bypass de Autenticación

// Técnicas de bypass
const authBypassTechniques = {
  // 1. Eliminar header de autenticación
  removeAuth: (request: string): string => {
    return request.replace(/Authorization:.*\r\n/, '');
  },
  
  // 2. Usar token expirado
  useExpiredToken: (request: string): string => {
    const expiredToken = 'Bearer eyJ....[token_expirado]';
    return request.replace(/Authorization:.*/, `Authorization: ${expiredToken}`);
  },
  
  // 3. Modificar user ID en token
  modifyUserId: (token: string): string => {
    const decoded = decodeJWT(token);
    decoded.payload.user_id = 'admin';
    return encodeJWT(decoded);
  },
  
  // 4. Method override
  methodOverride: (request: string): string => {
    return request.replace('POST', 'GET')
                  .replace('Content-Type: application/json', 
                          'X-HTTP-Method-Override: POST');
  }
};

Caso 2: Escalación de Privilegios

// Intentos de escalación
const privilegeEscalation = {
  // Modificar role en request
  modifyRole: (body) => {
    const data = JSON.parse(body);
    data.role = 'admin';
    data.permissions = ['read', 'write', 'delete', 'admin'];
    return JSON.stringify(data);
  },
  
  // Añadir headers administrativos
  addAdminHeaders: (headers) => {
    headers['X-Admin-Token'] = 'true';
    headers['X-Privileged-User'] = '1';
    headers['X-Internal-Request'] = 'true';
    return headers;
  },
  
  // Manipular IDs de grupo
  changeGroup: (request) => {
    // De user_group=2 a user_group=1 (admin)
    return request.replace(/user_group=\d+/, 'user_group=1');
  }
};

📋 Checklist de Análisis

Lista de Verificación de Seguridad

Request Analysis:
  ☐ Autenticación presente y válida
  ☐ Autorización verificada
  ☐ Parámetros validados
  ☐ Sin información sensible en URL
  ☐ Headers de seguridad apropiados
  ☐ Método HTTP correcto
  ☐ Content-Type apropiado

Response Analysis:
  ☐ Status code apropiado
  ☐ Headers de seguridad presentes
  ☐ Sin información sensible expuesta
  ☐ Sin mensajes de error detallados
  ☐ Cookies con flags de seguridad
  ☐ CORS configurado correctamente
  ☐ Sin headers que revelen tecnología

Data Validation:
  ☐ Input sanitizado
  ☐ Output encoded
  ☐ Sin datos sensibles en logs
  ☐ Sesiones con timeout
  ☐ Tokens con expiración
  ☐ Rate limiting implementado

🎯 Ejercicios Prácticos

Ejercicio 1: Interceptación Básica

  1. Configura break points para todas las peticiones
  2. Navega a http://testphp.vulnweb.com
  3. Intercepta y modifica el User-Agent
  4. Cambia el método de GET a POST
  5. Analiza la diferencia en las respuestas

Ejercicio 2: Análisis de Autenticación

  1. Intercepta un login request
  2. Identifica el mecanismo de autenticación
  3. Modifica las credenciales
  4. Intenta bypass con técnicas comunes
  5. Documenta los hallazgos

Ejercicio 3: Fuzzing de Parámetros

  1. Identifica todos los parámetros de una aplicación
  2. Configura el fuzzer con payloads de XSS
  3. Ejecuta fuzzing en campos de entrada
  4. Analiza las respuestas para detectar vulnerabilidades
  5. Genera un reporte de los hallazgos

Ejercicio 4: WebSocket Analysis

  1. Encuentra una aplicación con WebSockets
  2. Intercepta los mensajes
  3. Modifica mensajes en tiempo real
  4. Intenta inyectar comandos
  5. Documenta el flujo de comunicación

🚨 Troubleshooting

Problema: “No se interceptan peticiones HTTPS”

# Verificar:
1. Certificado ZAP instalado correctamente
2. Proxy configurado en navegador/app
3. Break points activados

# Solución:
- Regenerar certificado
- Verificar configuración de proxy
- Revisar logs de ZAP

Problema: “Respuestas truncadas o corruptas”

# Causas comunes:
- Encoding incorrecto
- Compresión no manejada
- Timeout en la conexión

# Solución:
Tools Options Connection
- Aumentar timeouts
- Deshabilitar compresión
- Verificar encoding

📚 Resumen

En este capítulo aprendiste:

🚀 Próximo Capítulo

En el siguiente capítulo aprenderás sobre Auditoría de Apps Android, incluyendo:


← Capítulo 2: Proxy Móvil | Volver al Índice | Siguiente: Auditoría Android →