Escolar Documentos
Profissional Documentos
Cultura Documentos
Campus de Cajazeiras
Curso Superior de Tecnologia em Análise e Desenvolvimento de Sistemas
Disciplina: Segurança de Dados
Professor: Daladier Júnior Período: 6° - Manhã
Este aula é centrada na educação dos profissionais de segurança com os riscos associados a
esta situação, tentando dar entendimento, sucinto, de vários tipos de ataques que o invasor poderá
lançar, além de um resumo das várias estratégias que podem ser avaliadas e aprovadas para proteger
os ativos de informações valiosas.
SQL Injection é um subconjunto das vulnerabilidades das entradas não verificadas/não sanitizadas
dos usuários, a idéia é convencer o aplicativo a executar o código SQL, o qual não estava previsto.
Se o pedido for criar strings SQL ingenuamente na mosca e, em seguida, executá-los, é simples para
criar algumas surpresas [SITE_2].
As quatro principais categorias de ataques de injeção SQL em bancos de dados, são:
1. Manipulação SQL: Manipulação é o processo de modificar os comandos SQL, usando
diferentes operações, como UNIÃO. Outra forma de execução do SQL Injection usando o método
de manipulação é alterar a cláusula where de uma instrução SQL, para obter resultados diferentes.
2. Injeção de código: Injeção de código é um processo de inserção de novas instruções SQL ou
comandos de banco de dados, nas instruções SQL vulneráveis. Um dos ataques de injeção de
código é acrescentar um comando EXECUTE SQL Server, na instruções SQL vulneráveis. Este
tipo de ataque só é possível quando várias instruções SQL por solicitação do banco de dados são
suportados.
3. Injeção em chamadas de função: Injeção em chamada de função é o processo de inserção de
várias chamadas de função em banco de dados dentro de instruções SQL vulneráveis. Essas
chamadas de função poderiam estar fazendo chamadas ao sistema operacional ou manipular os
dados num banco de dados.
4. Estouros de buffer (Buffer Overflow): Buffer overflow é causado pelo uso de injeção em
chamadas de função. Para a maioria dos bancos de dados comerciais e open source, as correções
estão disponíveis. Este tipo de ataque é possível quando o servidor está sem patch.
Todas as tecnologias de programação do lado servidor ou outras tecnologias web são suscetíveis a
este ataque, segue uma lista rápida das tecnologias: JSP, PHP, ASP, JavaScript, XML, XSL, VB,
MFC, outras ferramentas e APIs baseadas em ODBC, linguagens baseadas na 3ª e 4ª geração,
como: C, OCI, Pro* C e COBOL, além de scripts Perl e CGI ,que acessam bancos de dados Oracle.
A detecção de injeção SQL é difícil porque ela pode estar presente em qualquer uma das muitas
interfaces que o aplicativo apresenta ao usuário e não pode ser facilmente detectável. Portanto,
identificar e corrigir esta vulnerabilidade efetivamente garante verificar cada entrada, que aceita a
aplicação do usuário.
Como mencionado antes, as aplicações web usam geralmente SGBDS para armazenar as
informações. As informações são armazenadas / recuperadas em SGBDS com a ajuda de instruções
SQL. Um erro comum feito pelos desenvolvedores é a utilização, informações fornecidas pelo
usuário na cláusula "Where" de uma instrução SQL ao recuperar a informação. Assim,
modificando a cláusula 'Where' com condições suplementares para esta cláusula vulnerável, onde
toda instrução SQL pode ser modificada. A tentativa bem sucedida para alcançar isto pode ser
verificada olhando para a saída gerada pelo servidor de banco de dados. Seguindo um exemplo de
modificação de uma cláusula Where poderia explicar melhor este assunto.
Muitos servidores web retornam o erro de sintaxe incorretos, juntamente com a parte da instrução
SQL que foi enviada ao servidor de banco de dados para execução. Esta situação constitui uma
oportunidade para o hacker gerar erros ao tentar várias combinações de entradas, para obter a
instrução SQL da mensagem de erro. Depois de obter a boa idéia sobre a instrução SQL existente
como este, o hacker pode tentar outras construções na injeção SQL.
As entradas maliciosas listadas acima podem ou não dar os mesmos resultados. Portanto, é
interessante tentar todas as entradas.
Todo atacante tenta obter informações a respeito do projeto de banco de dados do aplicativo de
destino, a fim de garantir a melhor oportunidade em lançar um ataque sistemático.
Vamos supor que há uma página ASP usada para o logon de usuário desenvolvida por um
programador muito ingênuo, em que não há tratamento personalizado de erro e o atacante descobriu
que a página é aberta para o ataque de injeção SQL, injetando " no campo username.
A página usa o seguinte comando SQL, para verificar as credenciais dos usuários no banco
de dados. Select * from users where username = '"+ Inp_username +"', password = '"+
Inp_password +" ";
Primeiro, o atacante gostaria de estabelecer os nomes das tabelas que a consulta funciona e os
nomes dos campos. Para fazer isso, o atacante usa a cláusula "having" da instrução 'select':
Inp_username: 'having 1 = 1 - Isto provoca o seguinte erro:
/mydir/process_login.asp, line 26
So the attacker now knows the table name and column name of the first column in the query.
Eles podem continuar através das colunas introduzindo cada campo dentro de uma cláusula
'GROUP BY', como se segue:
/mydir/process_login.asp, line 26
Seria útil poder determinar os tipos de cada coluna. Isto pode ser conseguido utilizando a mensagem
de erro de conversão de tipo, como este:
union select sum(users.username) from users--
Isso leva vantagem do fato que as tentativas de servidor SQL em aplicar a cláusula de soma
(SUM) antes de determinar se o número de campos nos dois conjuntos de linhas é igual. A tentativa
de calcular a "soma" dos resultados de um campo de texto resulta na mensagem:
Por outro lado, procuramos calcular SUM() de um tipo numérico, temos uma mensagem de erro
dizendo que o número de campos nos dois conjuntos de linhas não coincidem:
Inp_username: ' union select sum(id) from users --
Provider for ODBC Drivers error '80040e14' [Microsoft][ODBC SQL Server Driver][SQL Server]
All queries in an SQL statement containing a UNION operator must have an equal number of
expressions in their target lists.
/mydir/process_login.asp, line 26
Esta técnica pode ser usada para determinar o tipo de qualquer coluna de uma tabela no
banco de dados. Isso permite que o invasor crie uma consulta bem formada de inserção, como este:
Inp_username: ' ; insert into users values('attacker', 'foobar' , 66,3 ) –
Permitindo acesso ao atacante:
Desde que o atacante está interessado em nomes de usuários e senhas, que são propensos a ler os
nomes de usuário / senhas de uma tabela 'users'. Isso também ilustra outro ponto; instruções
Transact-SQL podem ser na mesma linha, sem alterar seu significado. O script a seguir irá
concatenar os valores:
começar declare @ ret varchar (8000)
begin declare @ret varchar(8000)
set @ret=':' select @ret=@ret+' '+username+'/'+password from users where username>@ret select
@ret as ret into foo endA declaração acima após a execução cria uma tabela 'foo', que contém "ret"
a única coluna, e coloca a nossa seqüência para ele. Normalmente, mesmo um usuário com poucos
privilégios será capaz de criar uma tabela em um simples banco de dados, ou o banco de dados
temporário.
O atacante, então, seleciona a seqüência da tabela, como antes:
ret "union select ret,1,1,1 from foo--
E então apaga, deleta ou dropa (em alusão ao DROP) a tabela, desta forma:
Inpusername: '; drop table foo--
4. Ataques
Nesta seção, veremos vários ataques que exploram essa vulnerabilidade. Existem quatro tipos de
ataques de SQL Injection. Vamos ver os ataques de cada tipo nesta seção. Todos estes tipos de
injeção de SQL são válidos para bancos de dados como MS SQL Server, Oracle, DB2, MySQL e
PostgreSQL.
Essa técnica daria ao atacante o acesso com os privilégios do primeiro usuário no banco de dados.
Este ataque poderia ser usado para passar pela tela de logon.
O código acima mostra uma instrução SQL usada para autenticação. Esta instrução SQL tem duas
entradas: strInputUsername e strInputPassowrd. Esta consulta tenta encontrar nome de usuário na
tabela de usuários que tem coluna Nome com valor igual a strInputUserName e valor na coluna
Password igual strInputPassword. Após a execução desta instrução na linha 2, se for encontrada
uma correspondência a seqüência StrAuthorizationChk terá o nome de usuário nele.
Programa de lógica nas linhas 3 a 7 é simplesmente declarar o usuário autenticado ou não. Se não
houver a validação da entrada, de modo que nunca depois de uma entrada pode haver quaisquer
caracteres. Assim, as entradas podem ser modificados de tal forma que mesmo que não se conhece
um usuário válido e sua senha, ele iria ficar autenticado. Ao introduzir os seguintes valores.
Para a maior parte na vida real, a injeção de SQL não é tão simples como o que é mostrado acima.
A maioria dos atacantes vezes iria ver alguma mensagem de erro e vai ter que fazer engenharia
reversa de suas consultas. Para isso é preciso saber interpretar as mensagens de erro e como
modificar a seqüência de injeção.
Depois de executar este ataque o pedido concede ao atacante acesso completo ao aplicativo com o
papel de SA como abaixo:
A maioria das aplicações web usam as instruções SELECT para recuperar dados do banco de dados.
Também em muitas sitações entradas de usuário se tornariam parte da cláusula WHERE das
instruções SELECT. Por exemplo:
SQL = "SELECT Title, Author, Publishing from Books WHERE ISBN = ‘ ” & strInputISBN & “ ‘
”
A instrução SQL acima tem uma seqüência strInputISBN do usuário. Numa básica UNIÃO SQL o
ataque de injeção de comandos SQL a string dará entradas que não irão retornar nenhum resultado
para a instrução SQL original, mas irá retornar as linhas do conjunto de resultados da instrução SQL
injetado usando UNION ALL. Se na entrada do usuário acima SQL da consulta é
‘UNION ALL SELECT Price, Quantity From Pricing_Table WHERE ‘ ’ = ‘ ‘
Como resultado da consulta formada pela aplicação a ser executada no banco de dados será:
SELECT Title, Author, Publishing from Books WHERE ISBN = ‘ ‘ UNION ALL SELECT Price,
Quantity From Pricing_Table WHERE ‘ ’ = ‘ ‘
O servidor de banco de dados tenta buscar através da tabela de Books um livro que tem um número
ISBN em branco, que é um caso muito improvável. Esta consulta original normalmente não
retornou nenhum resultado. Depois do banco de dados a segunda instrução SELECT é executada,
selecionando todos os valores de alguma outra tabela porque a cláusula WHERE é sempre satisfeita
para esta segunda consulta. Posteriormente, a cláusula UNION ALL é usada, mas não elimina todas
as linhas do conjunto de resultados e retorna todas as linhas para o hacker.
Muitas empresas liberam notícias para a imprensa (press releases) através do seu portal.
Normalmente o usuário requisita um comunicado de imprensa em uma URL, ficando assim:
http://www.somecompany.com/PressRelase.jsp?PressRealeaseID=5
A instrução SQL utilizada pela aplicação ficaria assim
Select title, description, releaseDate, body from pressRelease WHERE pressRelaseID=5
O servidor de banco de dados retorna todas as informações solicitadas correspondentes à quinta
notícias liberada à imprensa. Esta informação é formatada pelo aplicativo em uma página HTML e
fornecida ao usuário.
No caso do servidor de banco de dados não suportar múltiplas instruções SQL como Oracle. Depois
de descobrir informação, tais como tabelas de usuário podemos usar a técnica a seguir.
Continuando com o exemplo acima para identificar um usuário numaa tabela. A URL requisitada
ficaria assim:
http://www.somecompany.com/PressRelase.jsp?PressRealeaseID=5 AND
ascii(lower(substring((SELECT TOP 1 name from sysobjects WHERE xtype=’U’), 1,1)))>109
Está pedindo o nome da tabela do usuário em primeiro lugar no banco de dados. A função substring
irá retornar o primeiro caractere da tabela do usuário retornado pela consulta. A função lower irá
converter os caracteres para letras minúsculas. Finalmente ascii () irá retornar o valor ASCII do
carácter.
Se a aplicação retorna a 5ª notícia de imprensa em resposta a essa consulta, em seguida, nós
sabemos que a primeira letra da tabela de usuário inicia o primeiro caractere depois de 'm' (ASCII
109) no alfabeto. Fazendo várias solicitações, nós podemos determinar o valor ASCII preciso.
http://www.thecompany.com/pressRelease.jsp?pressReleaseID=5 AND
ascii(lower(substring((SELECT TOP 1 name FROM sysobjects WHERE xtype='U'), 1, 1))) > 116
Se nenhum notícia é devolvida, o valor ASCII é maior que 109, mas não superior a 116. Assim, o
caractere está entre "n" (110) e "t" (116).
Então vamos continuar com nossos esforços para determinar a primeira letra e estreitar ainda mais
para baixo:
http://www.thecompany.com/pressRelease.jsp?pressReleaseID=5 AND
ascii(lower(substring((SELECT TOP 1 name FROM sysobjects WHERE xtype='U'), 1, 1))) > 113
Outra afirmação falsa. Sabemos agora que o caractere está entre 110 e 113.
http://www.thecompany.com/pressRelease.jsp?pressReleaseID=5 AND
ascii(lower(substring((SELECT TOP 1 name FROM sysobjects WHERE xtype='U'), 1, 1))) > 111
Falso novamente. A escala é reduzida a duas letras: 'n' e 'o' (110 e 111).
5. Pegar primeiro caractere da tabela user – Passo 5
http://www.thecompany.com/pressRelease.jsp?pressReleaseID=5 AND
ascii(lower(substring((SELECT TOP 1 name FROM sysobjects WHERE xtype='U'), 1, 1))) = 111
O servidor retorna a notícia, assim que a afirmação é verdadeira! A primeira letra do resultado da
consulta (e o nome da tabela) é "o." Para recuperar a segunda letra, repita o processo "Conseguir o
primeiro caractere da tabela do usuário" passo 1-5, mas alterar o argumento segundo o substring ( )
de modo que o próximo caractere do resultado é extraído: (mudar sublinhado (underlined))
http://www.thecompany.com/pressRelease.jsp?pressReleaseID=5 AND
ascii(lower(substring((SELECT TOP 1 name FROM sysobjects WHERE xtype='U'), 2 , 1))) > 109
Se a mensagem de retorno de erro pelo servidor contém um parêntese, como neste caso em que a
mensagem de erro diz Unclosed quotation (Aspas não fechada) antes da seqüência de caracteres "),
Ou uma mensagem de erro pode dizer que está faltando parênteses. Neste caso de ausência de
parênteses, a seqüência de injeção pode precisar conter o parêntese na parte ruim de valor e na sua
cláusula where. Em alguns casos, um ou mais parênteses podem precisar serem adicionados.
Muitos desenvolvedores tendem a escrever consultas usando a cláusula LIKE. O uso da cláusula
LIKE se pode adivinhar, vendo % ou LIKE de palavras-chave nas mensagens de erro nos bancos de
dados.
Exemplo de consulta: SELECT product_name FROM all_products WHERE product_name like
'%Chairs%'
A consulta acima irá substituir a seqüência de entrada Chairs para a consulta e irá procurar todos os
registros que tenham uma seqüência de entrada qualquer, com os valores product_name. Se o
atacante injeta a seqüência mostrada acima, o atacante se obtém todos os dados sensíveis.
Ataque usando declaração UNION, como mostrado acima. Portanto, se a consulta original é
Exemplo de consulta: SELECT product_name FROM all_products WHERE product_name like
'&Chairs&' "
Em seguida, o ataque seria
SELECT product_name FROM all_products WHERE product_name like '' UNION ALL SELECT
9,9 FROM SysObjects WHERE ‘’ = ‘’
A consulta acima daria erros que indicam que não há incompatibilidade no número de colunas e
seus tipos de dados na união da tabela sysobjects e as colunas que são especificados usando 9. O
erro "Operand type mis-match" se dá principalmente porque os dados incompatíveis na cláusula
UNION causou a string injetada. Outro erro que podemos ver é "Todas as consultas em uma
instrução SQL que contém um operador UNION devem ter um número igual de expressões em sua
lista de destino" é porque o número de colunas não é compatível.
Após o julgamento de vários erros e uma declaração LIKE possa vir a suceder.
SELECT product_name FROM all_products WHERE product_name like '' UNION ALL SELECT
9,9, 9,’ Text’, 9 FROM SysObjects WHERE ‘’ = ‘’
Conjunto de resultados da consulta acima irá mostrar todas as linhas na tabela sysobjects e também
irá mostrar os valores de linha constante para cada linha na tabela sysobjects definida na consulta.
Às vezes pode haver mais de uma condição WHERE na instrução SQL que é adicionado após a
seqüência de injeção.
SELECT firstName, LastName, Title from Employees WHERE City = ’ “& strCity &” ‘ AND
Country = ‘INDIA’ “
Na primeira tentativa, após injetar a string, a consulta resultante seria semelhante a:
SELECT firstName, LastName, Title from Employees WHERE City = ‘NoSuchCity’ UNION ALL
Select OtherField from OtherTable WHERE 1 = 1 AND Country = ‘USA’
Muitos sites, como quadros de avisos, carrinho de compras, o registro do usuário tomam as entradas
do usuário e armazená-as e depois os exibe para outros usuários. O que significa, essencialmente, as
entradas de usuários são armazenados no backend, utilizando a instrução INSERT. O abuso das
declarações INSERT traz como resultado que atacante adiciona várias linhas no banco de dados
com dados corrompidos. Se o administrador monitora o conteúdo do banco de dados, então as
inserções podem ser detectadas. Ataques no backend utilizando declarações INSERT são um pouco
diferentes do Select.
4.3.2 Injetando no subselect
Normalmente, uma instrução INSERT fica assim: Insert into TableName Values (‘ValueOne’,
‘valueTwo’, ‘valueThree’);
A maioria dos bancos de dados usam procedimentos armazenados para executar muitas operações
de administração. Se o atacante for capaz de injetar string SQL com êxito, em seguida, o atacante
pode explorar esses procedimentos armazenados. O acesso aos procedimentos armazenados
depende dos privilégios de acesso do usuário do aplicativo no banco de dados. Na maioria das vezes
que um procedimento armazenado é executado com êxito, não pode haver nenhuma saída na tela
como faria no caso de uma instrução SQL normal.
Por exemplo:
5. Mitigação
Mitigação de vulnerabilidade de injeção SQL estaria tomando um dos dois caminhos, quer seja
através de procedimentos armazenados, junto com as declarações exigívéis ou com instruções
preparadas com comandos SQL dinâmicas. Independentemente da forma como é adotada a
validação de dados é necessária.
S/[^0-9a-zA-z//g
Escrever filtros específicos. Use números, números e letras tanto quanto possível. Se houver a
necessidade de incluir sinais de pontuação de qualquer natureza, converta-os em HTML e
codifique-os. De modo que " torne-se ou "" ou > torne-se ">". Por exemplo, se o usuário está
enviando o endereço de e-mail só permitem @,-,. E _ em adição de números e letras para ser usado
e só depois de terem sido convertidos para seus substitutos em HTML.
Este segmento de código cria um objeto PreparedStatement para selecionar os dados do usuário,
com base no endereço de e-mail do usuário. O ponto de interrogação ("?") indica esta afirmação
tem um parâmetro.
Certifique-se que o usuário de uma aplicação específica possua direitos mínimos no servidor de
banco de dados. Se o usuário do aplicativo no banco de dados utiliza ROOT / SA / dbadmin / dbo
no banco de dados, então, que certamente precisa ser revista se o usuário realmente precisa de uma
quantidade de privilégios da aplicação tão elevado ou eles podem ser reduzidos. Não dê a permissão
de usuário do aplicativo para acessar o sistema de procedimentos armazenados, que permitem o
acesso a esses que são criados pelos usuários.
Para garantir uma aplicação contra injeção de SQL, os desenvolvedores não devem permitir que os
dados fornecidos pelo cliente modifiquem a sintaxe das instruções SQL. Na verdade, a melhor
proteção é isolar a aplicação web, a partir do SQL, completamente. Todos os comandos SQL
necessários para a aplicação devem ser procedimentos armazenados e mantidos no servidor de
banco de dados. O aplicativo deve executar os procedimentos armazenados usando uma interface
segura, tais como demonstrações mobilizável do JDBC ou CommandObject do ADO.
Exemplo:
CallableStatement cs =
con.prepareCall ("{call (?,?,?)}"); accountlogin
cs.setString (1, theuser);
cs.setString (2, senha);
cs.registerOutParameter (3, Types.DATE);
cs.executeQuery ();
Data lastlogin = cs.getDate (3);
Ao utilizar o objeto de comando, os comandos de banco de dados podem ser emitidos. Estes
comandos podem ser, mas não estão limitados a, seqüências de consulta, dispostas em seqüências
de consulta, e os parâmetros associados com seqüências de consulta. O objeto comando pode abrir
uma nova conexão ou usar uma conexão existente para executar consultas.
Exemplo de código:
Sub ParameterExample()
Dim cmd As New ADODB.Command
Dim rs As New ADODB.Recordset
Dim prm As ADODB.Parameter
' Set the command's connection using a connection string.
cmd.ActiveConnection = "DSN=pubs;uid=sa"
' Set the command's text, and specify that it is an SQL statement.
cmd.CommandText = "byroyalty" //Name of the stored procedure
cmd.CommandType = adCmdStoredProc //Type is set to invoke a stored procedure
' Set up a new parameter for the stored procedure.
Set prm = cmd.CreateParameter("Royalty", adInteger, adParamInput, , 50)
’ This sets up template for parameter
cmd.Parameters.Append prm
' Create a recordset by executing the command.
Set rs = cmd.Execute
' Loop through the recordset and print the first field.
Do While Not rs.EOF
Debug.Print rs(0)
rs.MoveNext
Loop
' Close the recordset.
rs.Close
End Sub
O primeiro passo para garantir esse código é tirar a instrução SQL da aplicação web e colocá-la em
um procedimento armazenado no servidor de banco de dados.
Criar um procedimento armazenado, como mostrado abaixo no servidor de banco de dados usando
a interface do cliente.
Em vez de construir uma seqüência de instruções SQL para chamar o procedimento armazenado,
um CallableStatement é criado para executá-lo com segurança.
String query = "SELECT title, description, releaseDate, body FROM pressReleases WHERE
pressReleaseID = " + Request["pressReleaseID"];
SqlCommand command = new SqlCommand(query,connection);
command.CommandType = CommandType.Text;
SqlDataReader dataReader = command.ExecuteReader();
Bind
Support to Use of INTO/OUT
Database USERNAME Variables/P Access to
Multiple EXECUTE FILE
Serverparameter () repared system SP
statements command functions
statements
MS SQL Server
Oracle X X X X X
PostgrSQL X X
6.1 tabelas do servidor de banco de dados que são utilizados por atacantes
Sysobjects syscolumns
6.1.2 Oracle
Referências:
select id,titulo from noticias where id=1;select * from noticias where posicao=1 and posicao=1
order by data;