Muito se houve falar dos perigos da injeção de SQL ou, como é mais conhecido o termo, SQL injection. Mas acho falho manterem como principal exemplo o ganho de acesso a áreas restritas de sites ou a possibilidade de estragos ao banco de dados, deixando de lado outras possibilidades ainda mais danosas. Por isso, e por achar que há pouca informação sobre uma técnica cujos danos eu julgo serem piores que os exemplos acima, preferi escrever sobre a possibilidade de introdução de código num site atacado.


Suponhamos que você tenha criado uma agenda online para uma empresa e que, nessa agenda, o usuário pode consultar seus compromissos. Para isso, você fez um código PHP parecido com:

Código:


$conexao = mysql_connect('mysql.exemplo.com', 'root', 'password123');
mysql_select_db('agenda', $conexao);
$consulta = mysql_query('SELECT CompromissoNome, CompromissoData, CompromissoImportancia FROM Compromisso WHERE UsuarioID = ' . $_GET['Usuario'], $conexao);
echo '<table><tr><td>Nome</td><td>Data</td><td>Importância</td></tr>';
while ($linha = mysql_fetch_row($consulta))
{
echo "<tr><td>{$linha[0]}</td><td>{$linha[1]}</td><td>{$linha[2]}</td></tr>";
}
echo '</table>';
...


Então, um funcionário resolve atacar a agenda porque quer tentar usar o site da empresa como um “zumbi”. Seu primeiro passo é verificar se a aplicação aceita injeção de SQL. Por saber que uma consulta aos compromissos por data retorna uma lista com três campos., ele faz o seguinte:


  • entra no site com sua senha;
  • consulta seus compromissos;
  • verifica que essa consulta é feita por uma URL do tipo: [Tens de ter uma conta e sessão iniciada para poderes visualizar este link]
    nisso, seu código SQL ficaria assim: SELECT CompromissoNome, CompromissoData,
  • CompromissoImportancia FROM Compromisso WHERE UsuarioID = 15;
    e o usuário receberia uma tabela com um compromisso por linha;
    o usuário então mudaria a URL para: [Tens de ter uma conta e sessão iniciada para poderes visualizar este link] UNION ALL SELECT 1, 2, 3;
    seu código SQL mudaria para: SELECT CompromissoNome, CompromissoData,
  • CompromissoImportancia FROM Compromisso WHERE UsuarioID = 15 UNION ALL SELECT 1, 2, 3;
    e o usuário receberia a mesma tabela, mas com uma linha adicional mostrando: 1 no campo
  • Nome, 2 no campo Data e 3 no campo Importância;
    isso já garante ao usuário que sua agenda aceita SQL Injection.

Outros testes deveriam ser feitos para colher mais dados como, por exemplo, se a conta que acessa o banco de dados tem privilégio FILE. Mas o usuário parte direto para o ataque assim:

descobre o DocumentRoot da agenda. Isso pode ser feito de várias formas. Infelizmente, uma que dá bastante resultado é acessar [Tens de ter uma conta e sessão iniciada para poderes visualizar este link] É impressionante o número de pessoas que não apagam esse tipo de página quando não precisam mais dela;
e altera novamente a URL para algo como [Tens de ter uma conta e sessão iniciada para poderes visualizar este link] UNION ALL SELECT "",2,3 INO OUTFILE "/var/www/agenda/zumbi.php";
seu código SQL ficaria: SELECT CompromissoNome, CompromissoData, CompromissoImportancia FROM Compromisso WHERE UsuarioID = 15 UNION ALL SELECT "",2,3 INO OUTFILE "/var/www/agenda/zumbi.php"
Isso cria um arquivo PHP na raiz do site que executa qualquer comando passado como parâmetro. Ele agora pode, sem precisar se logar à agenda, fazer do site da empresa um “zumbi”. Para testar, ele usa a URL [Tens de ter uma conta e sessão iniciada para poderes visualizar este link]
No próximo post falarei de práticas que aprendi para evitar SQL Injection. Mas já dá para perceber que não se pode usar o conteúdo de $_GET e $_POST diretamente, nem dar privilégios perigosos a usuários, não é?