vasão d
8Vamos a lógica
e Privacid

O programador, iniciante ou não, pensa em criar uma área restrita para o site, necessitando de um login e senha para os usuários. Isso é criado dentro do banco de dados (em SQL ou MDB, sendo este último o mais comum) em uma tabela chamada Users, com alguns campos, dentre eles: Usuário, Senha, Nome e Admin. Esses campos informarão exatamente o que o nome diz, ou seja, o login do usuário, a sua respectiva senha, seu nome e um campo flag indicando se é admin do site ou não. Se for admin, geralmente tem acesso a cliques extras, do tipo incluir, editar ou debilitar alguma informação.


Feito isso, ele cria dentro da sua pagina um bloco onde pede o login e senha para o usuário ter acesso a estas áreas. Geralmente, o formulário tem apenas os dois campos: usuário e senha. Estes dois campos são enviados para um script ASP, que validara ou não o login informado.
Se for valido, redireciona-o para a área restrita; senão, o internauta é levado de volta ao login ou, no máximo, é informado de que algum erro foi cometido.
Bonito, não? Teoricamente funciona.

8Vamos a pratica

Dentro desse script ASP, o programador colocou algo desse tipo:

Isso pega o usuário e senha informados no formulário:

cUser = trim(request("usuario"))
cSenha = trim(request("senha"))

 

O código abaixo verifica no banco de dados se o usuário e senha conferem (vamos supor que o banco já esteja aberto com o nome de objConn):

SQLOpen = "select usuario, senha,
nome, admin from Users where
usuario = '"& cUser &'" and senha = '"
& cSenha &'"
objRS.OpenSQLOpen, objConn

A seguir é verificado se encontrou um usuário com o login e senha informados:

If not objRs.bof then
response.write "Bem vindo" &
objRS.fields("nome")&"!"
else
response.write"Login invalido."
end if


Na pratica inocente, isso funciona. Funciona muito bem. Se a senha não for a correta, o usuário realmente não entra. Se um usuário foi digitado errado, também não da acesso.
Mas, na prática hacker, isso funciona melhor ainda, pois permite entrar como qualquer usuário no sistema. Até mesmo no usuário de admin..

8Vamos pensar um pouco


"select usuario , senha, nome, admin
from Users where
usuario = '" & cUser & "' and senha = '"
& cSenha &"'"

 

Essa string é do SQL. Em VB e ASP, sabemos que para contatenarmos uma string dentro de outra devemos usar aspas simples, em vez de aspas normais (duplas), pois as aspas normais são para a string mestra e as aspas simples são para a string interna.

Traduzindo a String acima, teríamos

select usuario, senha , nome, admin
from Users where usuario = 'geek' and
senha = 's3nh4'

 

Desta forma, trocamos as variáveis cUser e cSenha pelos seus respectivos conteúdos.
Repito, isso funciona muito bem quando usamos de forma inocente. Vale lembrar que de dez sites em ASP que pedem login e senha, oito têm essa forma de consulta, e estão sujeitos a algum tipo de invasão, dependendo do nível de acesso que permitem aos seus usuários.
"Você falou, falou, falou... Mas e daí!? Cadê o erro nisso?"

8Ok, Vamos ao erro

Se quando formos digitar um login, tivermos essa string de programação do SQL na cabeça, podermos formar outra facilmente, que injetaria um comando de SQL dentro do que o programador já fez.
Ou seja, se eu digitar Mario no username, o SQL ficará:

select usuario, senha, nome, admin from
Users where
usuario = 'Mario' and senha = 's3nh4'

Repare que as aspas simples continuam e fazem realmente parte do comando, que mostra ao SQL que aquele campo deve ser comparado com um dado do tipo string.
Agora, se digitarmos no usename Ma'rio (com uma aspa simples no meio), a página dará um erro, pois o comando ficaria desse tipo:

select usuario, senha, nome, admin from
Users where
usuario = 'Ma'rio and senha = 's3nh4'

Analisando, percebemos que quando vamos comparar o campo usuário, abrirmos uma aspa simples, colocamos o conteúdo.
Ma e fechamos a aspa simples. Para o SQL, a comparação terminou aí, o que vem depois deveriam ser comandos.

Mas não era.
Era a continuação de usename, a palavra rio e mais uma aspa simples, que deveria estar fechando a primeira (antes da palavra Ma), mas na realidade está abrindo uma nova string no SQL e, como não é comparado com nada, o SQL retorna erro de programação.


Então, já que o SQL aguarda ansiosamente por outra aspa simples para fechar aquela primeira, por que nós não aproveitamos e injetamos um comando nele? Imagine se usarmos a string 'or' I (isso mesmo: aspa simples = + espaço + or + espaço + aspa + simples + I). A string ficaria assim:

select usuario, senha, nome, admin
from Users where
usuario = " or'l' and senha = 's3nh4'

Lendo o comando, seria a mesma coisa que falar para o SQL: retorne o usuário que seja igual a vazio OU l. Lembrando que l em informática é a mesma coisa que True (verdadeiro). Lendo novamente retorne o usuário que seja igual a vazio (não existe nenhum) OU verdadeiro (opa...verdadeiro é verdadeiro, então achei). Nisso, a tabela pega todos os usuários, pois todos são validos. Agora falta só filtrar a senha.
Se usarmos a mesma string mágica na senha, nós seremos o primeiro usuário da tabela, pois:

select usuario, senha, nome, admin
from Users where
usuario = 'l' and senha = " or'l'

Retorne o usuário que seja igual a vazio (nenhum) OU verdadeiro (todos). E que tenha a senha igual a vazio (nenhum) OU verdadeiro (todos).
Isso traz todos os usuários da tabela, porém com o ponteiro no primeiro usuário.
Quando fazemos uma tabela de usuários e colocamos no ar, qual o primeiro usuário que incluímos? Nós mesmos, claro. E com nível de administrador. E é exatamente esse que viramos quando usamos essa falha.

Alguns outros casos, por exemplo, ocorrem quando queremos entrar com o username de uma determinada pessoa. No username, colocamos o nome dela corretamente, e na senha, como não sabemos, usamos essa string que nos foi enviada sabe lá por quem.

O SQL, muito esperto, entende que é para retornar o usuário com o nome informado e com a senha igual a vazio OU verdadeiro. Ou seja, na verdade, ele vai ignorar a senha, e apontará para o registro que o username é igual ao que foi informado no campo do formulário.

Outro ponto é quando não sabemos o nome do usuário, e o site tem muitos cadastros. Então, entramos como qualquer um, e com seus respectivos direitos. No usuário colocamos a string mágica e, na senha, chutamos qualquer coisa, por exemplo, 123456 (num site com mais de 200 cadastros, é 99% de certeza que alguém tenha usado essa senha). Então, o SQL apontará o registro para o primeiro usuário que tenha essa senha no seu cadastro.

Outras senhas usadas são: 123123, 123321, 121212, 111222, o próprio nome do site, abc, abcd, abcdef, abc123, 123abc, e coisas fáceis desse tipo.

E no caso do login pedido ser um e-mail, essa string não funcionara, pois talvez exista uma validação no campo do login para atestar que foi digitado tem um formato de e-mail (digo talvez, pois existem sites pedindo e-mail, login, mas que não validavam nada...).

Daí, usamos a string que passa por essas validações (como o campo de e-mail é grande, por não saber qual e-mail do usuário, é possível utilizar essa string maior. A string anterior é pequena para caber em qualquer campo de login e senha).

8A String que passa pelos e-mails

[email protected]'or'.ll' = '.ll

Dessa forma, caso verifique se existe @, esta string passará, pois tem uma @ só. Se verificar se tem alguma coisa antes da @, ela válida e também passa. Se verificarem de trás para frente na string, procurando por uma TLD válida (com um ponto na terceira ou quarta casa, de trás para frente), encontrarão o ponto (.) na terceira casa, que significa uma TLD brasileira (.br) ou de outros países.

E se ainda verificarem mais para trás, por domínios, encontrarão outros 2 pontos, o que torna esse e-mail pertencente a um domínio com subdomínio.

"Ok. Sou dono de um site em ASP, e uso essa forma de verificação. A gora que já me ferrou e que todo mundo vai me invadir, pode me dizer como conserto isso?"

Claro. É para isso mesmo que eu estou falando desse erro. Para alertar os sites que estejam com esse problema.

8Vamos a correção

O problema todo é que o script só verifica se achou ou não um usuário: não faz um check-up para atestar a veracidade do que foi encontrado. Então, bastaria adicionar o seguinte comando dentro daquele script:
Isso pega o usuário e senha informados no formulário:

cUser = trim(request("usuario"))
cSenha = trim(request("senha"))

Isso verifica no banco de dados se usuário e senha conferem (vamos supor que o banco já esteja aberto com o nome de objConn):

SQLOpen = "select usuario, senha,
nome, admin from Users
where usuario = '" & cUser & "' and
senha = '" & cSenha &"'"
objRS. Open SQLOpen, objConn

Verifica se achou um usuário com um login e senha informados:


if not objRS. Bof then
if objRS.fields("usuario") = cUsuario
and
objRS.fields("senha") = cSenha then
response.write "Bem vindo" &
objRS.fields("nome")&
"!"
else
response.write"Login inválido".
end if
else
response.write"Login inválido"
end if

Dessa forma, não há furos de aspas simples ou aspas normais, pois o IF não se confunde com isso.
Outra forma seria tratar o caractere das aspas simples dentro dos campos de usuário e senha, não deixando ele estar contido nestes campos. Mas isso é um pouco mais trabalhoso.
Vale ressaltar também que esse erro não afeta somente a Internet. Sistemas feitos em Delphi e Visual Basic com esse tipo de verificação de usuários também estão vulneráveis a esse erro. Portanto, não deixe de verifica-los também.



Imprimir Topo>>>
Hosted by www.Geocities.ws

1