write-ups de CTF
Classe: Second-Order SQL Injection. O dado controlado pelo usuário é gravado no banco e só é interpretado como parte de uma consulta SQL depois, em outro ponto da aplicação.
Ao acessar http://crystal-peak.picoctf.net:58279/, observamos uma aplicação com a função de controlar despesas.
Criamos uma conta comum para explorar e entender melhor como a aplicação funciona.
Username: test
Password: test
Notei que existem algumas rotas interessantes, como /dashboard, /expenses e /inbox.
Ao acessar /expenses, podemos criar uma despesa e, em seguida, gerar um relatório dela.
Em /inbox, podemos visualizar o relatório e também fazer o download dele.
A partir daqui, vou utilizar o Burp Suite para facilitar a análise das requisições e respostas.
Inicialmente, suspeitei de XSS, então criei um usuário utilizando o nome:
<script>alert(1)</script>
Porém, não funcionou.
Também testei uma aspa simples (') para tentar quebrar uma possível consulta
SQL e obter um error-based, mas também não tive resultado.
O próximo passo foi testar a criação do usuário. Dessa vez, criei um usuário utilizando apenas: (')
Ao acessar o /inbox, recebemos um erro.
De cara, isso chamou bastante atenção. O que temos aqui é uma Second-Order SQL Injection (SQLi de segunda ordem).
Esse tipo de vulnerabilidade acontece quando o sistema armazena o tainted data fornecido pelo usuário no banco de dados e só executa esse conteúdo posteriormente, em outro ponto da aplicação.
Nesse caso, o cadastro do usuário funciona como o injection point/source,
enquanto o /inbox acaba funcionando como o sink/execution point,
onde o dado armazenado é utilizado em uma consulta SQL.
Sendo assim, agora ficou mais fácil entender o que estava acontecendo e testar o comportamento da consulta.
'ORDER BY 1-- -
'ORDER BY 2-- -
'ORDER BY 3-- -
'ORDER BY 4-- -
Depois dos testes, descobri que a consulta possuía 3 colunas, então podemos utilizar NULL padding e continuar a enumeração.
'UNION SELECT name,type,sql FROM sqlite_master-- -
A partir disso, conseguimos enumerar informações do banco e identificar as tabelas existentes.
Na primeira tabela que consultei, já encontrei o retorno da flag.
'UNION SELECT name,value,null FROM aDNyM19uMF9mMTRn-- -
A vulnerabilidade acontece porque a aplicação armazena diretamente a entrada fornecida
pelo usuário e posteriormente utiliza esse valor na construção de uma consulta SQL. O
problema não está apenas no cadastro em si, mas no fato de o dado contaminado continuar
armazenado e ser interpretado como parte da consulta quando o /inbox é
acessado. Por isso, trata-se de uma Second-Order SQL Injection, e não apenas de uma SQLi
convencional.
Do lado defensivo, a principal correção seria utilizar parameterized queries / prepared statements em todas as consultas que utilizam dados controlados pelo usuário, evitando string concatenation para montar SQL dinamicamente. Também seria importante aplicar validação de entrada, utilizar uma conta de banco com o menor privilégio possível e evitar retornar erros detalhados do banco para o usuário, já que nesse caso o erro acabou funcionando como um error-based oracle e facilitou a exploração.
Flag:
picoCTF{s3c0nd_0rd3r_1t_1s_3ad6ac82}