domingo, 7 de novembro de 2010

Cookie SQL Injection - Explorando uma falha de segurança na prática

Quando converso com desenvolvedores Web eu percebo que são poucos que têm conhecimento de programação segura para Web. A algum tempo atrás eu trabalhava com Java e tinha/tenho muita preocupação com a questão de segurança. Cheguei até a tentar lecionar um curso de programação segura para Web em Java na uCon Security Conference, porém devido a falta de interesse o curso acabou não acontecendo. Acredito que conhecer, no mínimo, as formas de ataques mais básicas é fundamental para qualquer desenvolvedor Web. Um bom lugar para começar é conhecendo o projeto o Open Web Application Security Project (OWASP). Lá vocês podem encontrar uma vasta gama de informações sobre segurança na Web. Um sub-projeto interessante do OWASP é o que lista as 10 vulnerabilidades mais encontradas na Web.

Como mencionei no post anterior, o código em C que postei para melhorar a performance no acesso de aplicações Django usando o NGINX e Memcached tem uma falha de segurança que permite ataques de SQL Injection. Inicialmente eu pensei em realizar a correção no código e depois postar no blog. Mas depois me ocorreu que eu poderia mostrar como explorar esta falha. Achei que isso poderia ser bastante interessante para vocês verem como funciona esse tipo de ataque.

Bem, olhando o código escrito em C talvez não seja tão evidente a existência da falha. Pois normalmente os ataques de SQL Injection teem uma forma de entrada do código malicioso e saída da informação recolhida dentro do sistema. Normalmente esse problema é encontrado em aplicações Web onde é verificada a informação retornada em algum campo que é apresentado dentro do código HTML. Mas as falhas e aplicações se comportam totalmente diferentes em sistemas diferentes. A criatividade deve entrar em ação para tentar descobrir como interferir no sistema e obter uma resposta com sucesso. Ao analisar o comportamento da aplicação em funcionamento aparentemente não encontramos nenhuma forma de obter um retorno sobre qual o dado que está armazenado. O que conhecemos é o comportamento do sistema. Quando um visitante acessa a aplicação ele pode obter uma resposta da aplicação Web em Django ou do código em C onde existe a evidência de falha. Então sabemos que nossa atenção deve ser em cima de como fazer a requisição ir para o código vulnerável. Assim, lembrando do post anterior, todas as requisições passam pelo código em C onde é feita uma consulta a base de dados pelos dados existentes na sessão do usuário que no Django (e na maioria, se não, todos os tipos de aplicações web) armazena o Session Key no cookie do browser do usuário. O código realiza uma consulta a base de dados sobre a sessão e verifica o tamanho desses dados, caso seja maior que 60 caracteres (que foi o tamanho máximo identificado por mim para uma sessão de usuário não autenticado) a requisição é repassada para o Django e é entendido que o usuário está autenticado. Caso contrário, o usuário não está autenticado e a requisição é retornada a partir dos dados existentes no Memcached. Analisando esse fluxo, podemos perceber que a chave para o ataque é identificar como saber se a requisição vem do código em C ou do Django. E usar isso para obter uma resposta, já que este SQL executado (e que contém a vulnerabilidade) só é usado para isso. Assim procurei e achei a diferença entre as respostas do Django e do código vulnerável. Quando a resposta vem do Django, existe uma variável que aparece no cabeçalho da resposta a requisição HTTP. Ao descobrir isso, eu já sabia quando uma requisição vinha do Django e quando vinha do código em C e sabia que se o resultado retornado depois da execução do código SQL se fosse maior que 60 ele ia passar pra o Django e caso fosse menor ele mesmo iria responder. Assim, eu agora precisava só descobri como usar isso para obter informações sobre o sistema, no caso, informações importantes armazenadas na base de dados.

Primeiro eu precisava escolher que informação eu iria tentar obter, dentro do contexto teria que ser algo que estivesse no banco de dados da aplicação. Eu sei que toda aplicação Django com autenticação tem uma tabela chamada auth_user onde ficam armazenados os usuários, então escolhi atacar essa tabela e obter informações sobre os usuários da aplicação.

Bem, depois de descobrir onde deveria atacar eu precisei imaginar (usar a criatividade para) pensar em como fazer a resposta da execução do SQL ser maior que 60 caso a condição que eu verificasse fosse verdadeira ou falsa. Assim eu poderia usar a informação que a resposta veio do Django ou não para validar o que eu estaria perguntando ao banco de dados.

OFF-Topic: Resolvi ir tomar um banho e ficar pensando sobre como fazer isso. Minhas idéias fluem quando estou tomando banho e é lá onde eu tenho muitas ideias interessantes. Acho que quase todas que já postei ou vou postar neste blog surgiram quando eu estava tomando banho.

No final de todo o processo de pensar testar a avaliar o funcionamento eu escrevi este código. A ideia dele é fazer uma requisição a aplicação usando cada letra do alfabeto ou caractere válido para o campo que eu queria e fazer com que a resposta vá para o Django sempre que eu achar o caractere certo. Assim eu teria que iterar caractere por caractere para descobrir um-por-um. E foi isso que eu fiz.



Este código varre todas as possibilidades sobre cada caractere e vai validando cada entrada. No final podemos obter o nome de um usuário que é staff do sistema. Este mesmo código, sem muitas modificações pode ser usado para obter muitas outras informações. Ai vale a criatividade de cada um. Isso é apenas um exemplo simples.

A criatividade é um fator fundamental a qualquer pessoa que deseja realizar um ataque. Pois cada ataque requer um cuidado ou ação bem especifica. Cada sistema tem um funcionamento e foi implementado de uma forma totalmente diferente. Por isso que dificilmente um ataque que obteve sucesso sobre um sistema vai obter o mesmo sucesso sobre outro. O importante na questão de segurança é entender o fundamento do ataque e não decorar como foi feito. O fato da forma de atacar cada sistema ser diferente leva a que poucas pessoas realizem ou tenham sucesso ao tentar realizar esse tipo de atividade.

Espero que tenham gostado do post e ainda tenho muitas ideias que não postei aqui. Muita coisa ainda está por vir. A interação de vocês por meio de comentários é muito importante para minha motivação a continuar postando coisas aqui. Por isso, escrevam suas opniões, criticas ou elogios tudo isso é sempre bem-vindo.

Nenhum comentário:

Postar um comentário