Client-Side SQL Injection

Ataques de injeção de SQL (SQL Injection) são velhos conhecidos de quem lida com a segurança de aplicações web. Quando explorado com sucesso, este tipo de ataque pode ser utilizado para recuperar, adulterar ou mesmo destruir informações armazenadas em uma base de dados SQL. Comumente, as informações manipuladas por uma aplicação web são armazenadas no lado servidor (server-side), por exemplo, utilizando um típico SGBD relacional, como: Oracle, PostgreSQL, MS SQL-Server, MySQL, etc.

Entretanto, o que muitos não sabem é que, após a agregação de novas features ao padrão HTML (criando o popularmente conhecido HTML5), tais informações também podem ser armazenadas localmente (isto é, no client-side), utilizando APIs de armazenamento desenvolvidas para proporcionar o chamado “Client-Side Storage”. De tal modo, surge também a possibilidade de execução de ataques de SQL Injection no client-side, criando o que podemos chamar de “Client-Side SQL Injection”.

Antes de partir para o ataque, propriamente dito, vamos entender um pouco o funcionamento do Client-Side Storage.

O que é Client-Side Storage

O termo Client-Side Storage é uma forma geral de se referir às diferentes, mas relacionadas, APIs integrantes do HTML5, que possibilitam o armazenamento de dados na máquina do usuário, em vez de no servidor. Existem dois motivos principais que justificam o desenvolvimento de tais APIs:

  • Tornar possível o uso da aplicação mesmo quando offline;
  • Melhorar o desempenho das operações realizadas.

Diferentemente dos cookies, as informações armazenadas no Client-Side Storage não são enviadas para o servidor em toda requisição realizada, dessa forma, o espaço de armazenamento disponível para este recurso pode ser bem maior que o espaço disponibilizado para os cookies. O espaço de armazenamento pode variar de 5MB a 25MB – para cada API disponível – ou pode ser, inclusive, ilimitado, dependendo do browser utilizado.

No momento, existem três APIs para o armazenamento local de dados, são elas: Web Storage, Web SQL Database e Indexed Database.

Vale ressaltar que, o acesso às informações armazenadas no Client-Side Storage (independente da API utilizada) é sempre restrito à “origem” que as armazenou, e que a manipulação desses dados é realizada, exclusivamente, através de Javascript.

APIs de armazenamento

Como já mencionado, existem três APIs distintas que possibilitam o armazenamento local de dados. Tais APIs são apresentadas, resumidamente, a seguir.

  • Web Storage

O Web Storage configura um modelo de armazenamento simples, onde os dados são armazenados no formato chave-valor, ambos Strings. Esta API fornece duas áreas distintas de armazenamento, são elas: Local Storage e Session Storage. Os dados colocados no Local Storage podem ser manipulados por toda a origem que as armazenou, e persistem na máquina do usuário por quanto tempo for necessário, mesmo após o browser ser fechado. Os dados colocados no Session Storage, por sua vez, somente podem ser manipulados pela janela/aba à qual estão associados, e persistem na máquina do usuário apenas durante o tempo de vida dessa janela/aba, ou seja, até ela ser fechada.

  • Web SQL Database

O Web SQL Database configura um modelo de armazenamento estruturado, com toda a funcionalidade – e complexidade – de um típico SGBD relacional baseado em SQL. Esta API garante eficiência e praticidade na realização de consultas e, além disso, fornece suporte a transactions – garantindo a consistência dos dados armazenados. As implementações atuais baseiam-se exclusivamente na biblioteca SQLite.

  • Indexed Database

O Indexed Database (ou IndexedDB) configura um modelo de armazenamento chave-valor avançado, onde o valor associado a uma chave pode assumir, inclusive, o formato de um Javascript Object. Dessa forma, os pares chave-valor funcionam como “registros”, e são armazenados em estruturas denominadas Object Stores – que podem corresponder, digamos, às tabelas do modelo relacional. Esta API também permite a criação de índices, baseados nas propriedades dos “registros” armazenados, que possibilitam a realização de consultas mais eficientes. Pode-se dizer que o IndexedDB é uma tentativa de agregar os pontos fortes das duas APIs anteriores, unindo simplicidade, eficiência e consistência. Vale ressaltar que, tal API também fornece suporte a transactions – garantindo a consistência dos dados armazenados.

Client-Side SQL Injection

Como já mencionado, a manipulação dos dados armazenados em client-side é realizada exclusivamente através de Javascript e, especificamente na API Web SQL Database, o código implementado para tal pode estar suscetível a ataques de injeção de SQL, decorrente do mau uso do método executeSql(). A interface que disponibiliza esse método encontra-se ilustrada abaixo:

interface SQLTransaction {
  void executeSql(in DOMString sqlStatement, in optional ObjectArray arguments, in optional SQLStatementCallback callback, in optional SQLStatementErrorCallback errorCallback);
};

O método executeSql() permite ao desenvolvedor inserir, de forma segura, os inputs fornecidos pelo usuário em um comando SQL – através da substituição de placeholders indicados pelo caractere “?” por elementos do ObjectArray recebido no parâmetro aguments. No entanto, perceba que o parâmetro arguments desse método é opcional, deixando a critério do desenvolvedor empregar, ou não, um comando SQL parametrizado (Prepared Statement). Dessa forma, o desenvolvedor pode, simplesmente, optar por concatenar os inputs fornecidos pelo usuário diretamente ao comando SQL, viabilizando assim a realização de um Client-Side SQL Injection.

De modo a exemplificar o ataque em questão, foi desenvolvida uma prova de conceito, apresentada a seguir.

Demonstração

Esta prova de conceito demonstra uma aplicação que pesquisa – no Twitter – tweets relacionados a um determinado assunto (definido pelo usuário) e armazena-os em um database local, denominado tweet_db. Os tweets recuperados podem ser inseridos no database local de duas formas distintas, são elas:

1) Os dados do tweet são concatenados a um comando SQL (modo inseguro);
2) Os dados do tweet são substituídos em um comando SQL parametrizado (modo seguro).

A imagem a seguir ilustra a aplicação desenvolvida para esta demonstração, já com alguns tweets arbitrários inseridos em sua base de dados local:

Observação: Para visualizar a estrutura (tabela) onde os dados são inseridos, pode-se utilizar o atalho Ctrl+Shift+i – nos browsers Chromium e Google Chrome – e, na aba Resources, acessar o item Web SQL.

Para demonstrar o Client-Side SQL Injection no database tweet_db, um tweet contendo um payload específico, e as hashtags #recife e #poc (para facilitar sua pesquisa) foi preparado pelo usuário @mfppessoa. A imagem a seguir ilustra o tweet preparado:

Em seguida, esse tweet é inserido através da opção Inserir Tweet (Inseguro). A imagem a seguir ilustra o resultado obtido:

Como pode ser observado, apesar de o tweet ter sido escrito pelo usuário @mfppessoa, foi possível armazená-lo na base de dados em nome do usuário @jctransito – conforme indicado no payload contido no mesmo. Tal resultado foi possível devido à forma com a qual a função de inserção foi implementada. A imagem abaixo ilustra o código referente à função de inserção insegura:

Como pode ser visto, nessa função de inserção o método executeSql() foi empregado de forma inadequada, concatenando os dados do tweet ao comando SQL, o que viabilizou a execução do Client-Side SQL Injection.

Por outro lado, ao realizar o mesmo procedimento desta vez através da opção Inserir Tweet (Seguro), o tweet preparado é inserido corretamente, constando como autor o usuário @mfppessoa. A imagem a seguir ilustra esse fato:

Por fim, a imagem a seguir apresenta o código referente à função de inserção segura, onde o método executeSql() foi empregado de forma correta, substituindo os dados do tweet em um comando SQL parametrizado.

Observação: O ataque em questão somente foi testado nos browsers Chromium e Google Chrome.

Comentários
Aceita-se formatação à la TWiki. HTML e scripts são filtrados. Máximo 15KiB.

 
Enviando... por favor aguarde...
Comentário enviado com suceso -- obrigado.
Ele aparecerá quando os moderadores o aprovarem.
Houve uma falha no envio do formulário!
Deixei uma nota para os admins verificarem o problema.
Perdoe-nos o transtorno. Por favor tente novamente mais tarde.
K_X_O_P_A_7 | 2014-10-20 01:45:24 | permalink | topo

Bom, muito bom!

Robson | 2014-07-22 03:28:00 | permalink | topo

Como sempre muito legal o artigo !

Parabéns Marcelo.

Aproveitando, eu andei lendo uns artigos antigos de vocês e fiquei muito interessado em conversar com o KIKO (Marco Carnut), até deixei um comentário pra ele num dos artigos, sobre o NASDEC e o ambiente-auto-limpante.

Sabe de algum canal para que eu pudesse conversar com ele ?

Novamente, obrigado