1 de dezembro de 2008

SQL Injection e as funções de escape no php

Acredito que todos que acompanham este blog e até mesmo quem tenha qualquer contato com desenvolvimento WEB saiba o que é um SQL Injection e o que se deve evitar para combatê-lo, porém, todos os dias eu me deparo com técnicas ineficazes para tratamento de ataques de SQL Injection baseados na dupla php e MySQL.

A maioria destas técnicas para tratamento de SQL Injection fazem referência a funções de escape ou o popular magic_quotes do php, porém poucos devem saber que estas técnicas são ineficazes para evitar este tipo de ataque. A simples adição de uma barra invertida (" \ ") em uma string que contenha um apóstrofo (" ' ") não irá eliminar a possibilidade de exploração de ataques baseados em SQL Injection.

As funções de escape mais conhecidas são addslashes() e mysql_real_escape_string(). Estas funções irão fazer a seguinte transformação em uma string.

String normal = 'admin'
String com escape = \'admin\'

Agora o que poucos sabem é que o MySQL possibilita que você faça consultas de caracteres baseados na tabela ascii. Execute no MySQL a query: select ascii('a'); e você terá a o código da letra a que é 97. Agora faça o oposto, execute a query: select char(97); e você terá o caracter a. Isso quer dizer que podemos representar strings SQL usando os códigos ascii. Se usarmos a função concat() podemos montar uma query inteira usando os códigos ascii.

Execute a seguinte query no MySQL:

select concat(char(39), char(104), char(116), char(116), char(112), char(58), char(47), char(47), char(119), char(97), char(103), char(110), char(101), char(114), char(101), char(108), char(105), char(97), char(115), char(46), char(99), char(111), char(109), char(39))

O resultado será:

'http://wagnerelias.com'

Reparem que na string criada usando a função concat não é representado o apóstrofo (" ' "), com isso as funções de escape não teriam efeito algum. Portanto, cuidado com as funções de escape, muitas vezes elas não irão lhe salvar de um ataque de SQL Injection. Sempre que possível use Bind Variables implementando as Prepared Statements do MySQL.

22 comentários:

Ulisses Castro disse...

Opa! Bele artigo again Wagner, adicionando um pouco de info..

além da famosa funcao char(), ainda temos a funcão hex() e a unhex(), mas as vezes nem é preciso utilizá-las, bastando converter para hex em qualquer lugar e socar na consulta ex:

select concat(user,0xa,password) from 0x6d7973716c2e75736572;

sendo:
0x6d7973716c2e75736572 == mysql.user

As funcoes que citou não protejem contra ataques de SQL Injection sem dúvida.. mas olhando para o cenário que montou PHP + MySQL elas são de grande utilidade contra duas funcionalidades que eu poderia chamar de "chave" em um ataque, que são:

select concat(user,0xa,password) from 0x6d7973716c2e75736572 into outfile "/var/www";

OU pior...

select "" into dumpfile "/var/www";

Tanto dumpfile como outfile EXIGEM que sejam utilizado aspas, se não utilizar as funções que falou o servidor estará desprotegido contra um possível fuzzing para procurar diretórios que estejam com permissao incorreta e subir um backdoor...

:)

Fica as meus dois cents! :)

Grande abraço!

Ulisses Castro disse...

Putz no segundo exemplo do dumpfile era pra ter ficado:

select "" into dumpfile "/var/www"

duh! a página removeu meu codigo php :)

[]'s

Ulisses Castro disse...

aaaaaaarg!!! mal o spam...

select “codigoPHPaqui” into dumpfile “/var/www”

Elias Wagner disse...

Fala Ulisses, obrigado pelo complemento....

P.s.: Ainda bem que o wordpress limita a injeção de código, você não pode ver parâmetro... :)

Abs.

SQL Injection e as funções de escape no php disse...

[...] por Wagner Elias (weliasΘconviso·com·br) - referência [...]

João Marcus disse...

Por que não usar Prepared Statements de uma vez? Elas têm uma performance melhor quando a query é executada várias vezes, e são realmente seguras. Você não precisa se preocupar em fazer escape de nada.

Erick disse...

Cara muito bom o post, tem muitos programadores que acabam expondo sistemas com vulnerabilidades na internet, e soluções fáceis podem resolver o problema.

Falow, t+

Carlos André Ferrari disse...

então se eu não permitir a utilização dessas palavras (char, hex, unhex e dumpfile) e o escape na minha consulta já deve resolver o problema para praticamente todas as situações, certo?

Ribamar FS disse...

Agradecido por compartilhar seus conhecimentos.

Não sei porque usa:
"Você chegou até aqui procurando por "" através do www.google.com."

Eu não cheguei aqui via Google, portanto está furado.

Douglas Cunha disse...

Desenvolvo em PHP faz tempo. Sempre me preocupei em usar as funções de escape, mas nunca atentei para essa forma de ataque. Vou ficar mais esperto agora.

Muito bom o artigo. Aposto que como eu, muita gente via essas funções do MySQL (char, ascii...) com uma certa ingenuidade.

Elias Wagner disse...

João Marcos,

realmente as prepared statements são uma boa opção para tratar vulnerabilidades de SQL Injection, além do ganho de performance por elas manterem um plano de execução em cache. Eu recomendo também usar prepared statements, inclusive está no texto.

Quanto ao escape, ele tem outras necessidades, por exemplo a que foi comentada pelo Ulisses.

Obrigado pelo comentário.

Elias Wagner disse...

Carlos André,

eu não recomendo ficar validando, fazendo substituição de strings especificas, o melhor dos mundos é usar prepared statements e/ou fazer uma validação positiva, deixar passar apenas o conjunto de strings que você precisa e não trazem risco a aplicação.

Obrigado pelo comentário.

Elias Wagner disse...

Douglas,

realmente tem muitas coisas que acabam passando despercebidas. :)

Obrigado pelo comentário.

Keylly Eyglys disse...

Bem, achei seu post incompleto pois não falou quais os ataques que podem ser realizados mesmo realizando o escape nas aspas.

Serviu apenas para apresentar a função ascii e char do MySQL (que já deveria ser do conhecimento de muitos).

Elias Wagner disse...

Keylly,

sinto não ter atendido sua expectativa. eu falei dos riscos de usar as funções de escape e o que pode-se usar para bypassar estes controles. Não falei apenas das funções de ascii e char, as funções foram apresentadas como ferramenta para burlar os controles de escape.

Se você espera o passo-a-passo de como fazer isso, sinto muito, o post não é um how-to de como fazer SQL Injection, se você pegar um script e testar vai ver o que acontece.

Obrigado pelo comentário.

Ulisses Castro disse...

LOL Troll detected! o.O

Bom vendo todo mundo comentar sobre Prepared Statements e tal... é bacana e é fortemente recomendada MAAAAAAAS... lembrando que utilizando você estará delegando pro BD o processamento, portanto cuidado ao utilizá-la pois em certas circunstâncias pode acarretar em perda de performance...

Mais dois cents! :)

[s]

Making it easy! Executando query utilizando valores ascii. « Meninão disse...

[...] Entenda sobre essa e outras técnicas mais efetivas aqui. [...]

Goran Ivanisevic disse...

Horrível este post, a argumentação não tem nem pé nem cabeça. Pois, tem que ser muito doente para nem ao menos colocar entre aspas simples uma string. O SQL não vai rodar nas consultas "normais" !!!!
select abcdef ---- Simplesmente não roda
e mais se está sem aspas simples, porque não fazer direto?
select (drop table xyz)
se estiver entre aspas simples não vai adiantar nada usar char
select 'char(39)' --- Resultado: char(39)
péssimo post só fez eu perder o meu tempo...

Aconselho a estudar representação de tipos(string, inteiro, ponto flutuante, boolean...) porque o problema é que o autor não sabe commo se representa uma string dentro de uma consulta SQL ...

Elias Wagner disse...

O post realmente não deve estar bem escrito, pois você não entendeu nada.

O post tem o propósito falar sobre o bypass de magic_quotes e não sobre tipos em query SQL. Bom, mas pelo jeito você sabe muito. Não vou me estender tentando argumentar.

A propósito, algum problema com o seu nome?

diego fonseca disse...

Gostei muito do post ele abriu meus olhos para algumas coisa que eu ainda não tinha percebido!

obrigado!

diego fonseca disse...

Gostei muito do post serviu para tirar muitas duvidas sobre o sql injection!

Kaspesky disse...

Caro Goran,

Você precisa ponderar mais entes de postar, ou irá ficar como cachorro de lanchonet "pensando que todo sabua que sai é pra ele".

SQL Injection é uma coisa e SQL Interpretação é outra.

vlw