Artigo de Segurança do MVP - Maio 2005

Testando suas Aplicações Web sobre Vulnerabilidades de Scripts Entre Sites

Publicado em: 6 de maio de 2005
Por Chris Weber, Casaba Security, LLC (chris@casabasec.com)

Já não se discute se ataques de scripts entre sites são reais e extremamente perigosos. Se você sabe tudo sobre XSS e apenas quer ver algumas idéias sobre teste, vá direto para a seção de testes. Se isto é novidade para você, por favor leia! Ataques de scripts entre sites ocorrem quando uma pessoa mal intencionada, o invasor, pode forçar um usuário inadvertido, a vítima, a executar script de cliente da escolha do invasor. O termo scripts entre sites não é preciso, pois não se trata somente de scripts e não precisa nem ser cross-site. É um nome que foi dado a esta descoberta e ficou. Vamos usar doravante a abreviatura comum XSS.

Invasões XSS envolvem três partes:

O invasor

A vítima

O Web site vulnerável que o invasor explora para agir sobre sua vítima

Dessas três partes, a vítima é a única que realmente executa o código do invasor. O Web site é meramente um veículo para a invasão e não é tipicamente afetado. Uma invasão pode ser feita de várias maneiras. Por exemplo, o invasor envia à vítima, por e-mail, IM, ou outro meio, um URL maliciosamente elaborado. Quando a vítima abre o URL num navegador da Web, o Web site libera a página e o script é executado no computador da vítima.

Com que se parece uma vulnerabilidade XSS?

Como desenvolvedor e testador Web, você sabe que o fundamento tecnológico das aplicações da Web consiste de http e HTML. O protocolo HTTP é o transportador para o HTML, o código usado para fazer o layout da página da Web e formatá-la.

As vulnerabilidades XSS existem quando uma aplicação da Web aceita input do usuário através de solicitações HTTP tais como um GET ou um POST e então re-afixa o input em algum lugar no código de output HTML. Eis o exemplo mais simples:

1. Solicitação Web como esta:
GET http://www.somesite.com/page.asp?pageid=10&lang=en&title=Section%20Title

2. O HTML retornado pelo servidor após fazer esta solicitação inclui:
<h1>Section Title</h1>
Você pode ver que o input do usuário passado ao parâmetro de cadeia de consulta "título" foi provavelmente colocado numa cadeia variável e inserido pela aplicação Web num tag <h1>. Ao fornecer o input o invasor controla o HTML.

3. Agora, se o site não filtra input pelo servidor (pois controles pelo cliente podem ser contornados), um usuário mal intencionado pode abusar disto de várias maneiras:
O invasor pode introduzir código escapando do tag <h1>:
http://www.somesite.com/page.asp?pageid=10&lang=en&title=Section%20Title</h1><script>alert('XSS%20attack')</script>
O output HTML desta última solicitação ficaria assim:
<h1>Section Title</h1><script>alert('XSS attack')</script>
Mesmo com este exemplo dos mais simples, há inúmeras coisas que um invasor poderia fazer com este link. Vamos examinar as ameaças potenciais e seguir para alguns métodos de teste mais avançados.

Até que ponto são sérias as ameaças das invasões XSS?

Com a habilidade de injetar código na página da Web gerada, ameaças potenciais são limitadas apenas pela imaginação. Um invasor pode usar as vulnerabilidades XSS para roubar cookie, para seqüestrar contas, executar ActiveX, executar conteúdo Flash, forçá-lo a fazer download de software e atuar no seu disco rígido e nos seus dados.

Tudo isto pode acontecer simplesmente fazendo você clicar em alguma URL. Quantas vezes por dia você clica numa URL de e-mail recebido de alguém que confia, através de uma sala de bate-papo ou de um site de notícias que você usa?

Invasões "phishing" geralmente exploram as vulnerabilidades XSS para se disfarçarem de sites legítimos. Você já viu muito disso, quando uma mensagem por e-mail de seu banco chega na sua caixa de entrada, informando-o que foram feitas algumas mudanças na sua conta e convidando-o a clicar em algum super hyperlink. Se você examinar mais de perto o URL, ele pode na verdade explorar uma vulnerabilidade no Web site de seu banco, e parecer com algo assim: http://mybank.com/somepage?redirect=<script>alert('XSS')</script>, onde o uso do parâmetro "redirect" foi explorado para efetuar a invasão.

Se você for realmente astuto, você pode atingir o administrador com uma invasão XSS, talvez enviando um e-mail intitulado "Help! This website URL keeps giving me an error!" Depois que o administrador abrir o URL, você pode fazer um grande estrago, como roubar as credenciais dele ou dela.

Tudo bem, entendemos os perigos - invadir os usuários, invadir os administradores, atrair má publicidade para a empresa. Agora vamos examinar mais de perto o ponto central deste artigo - testar seu site em relação a estes problemas.

Teste para vulnerabilidades XSS

Eu fui consultor de segurança em tempo integral por muitos anos e passei por este exercício muitas vezes. Posso resumir um bom plano de teste em duas palavras: seja minucioso. Para você e para mim, encontrar estas vulnerabilidades não se trata de vangloriar direitos sobre o Bugtraq ou o Vulnwatch; trata-se de fazer um bom trabalho. Se isso significa esquadrinhar cada simples parâmetro de cadeia de consulta, valor de cookie, e valor de dados POST na aplicação, quer dizer que vamos ter de trabalhar um pouco mais.

Sem dúvida, uma revisão de segurança completa envolve mais do que simplesmente procurar vulnerabilidades XSS; envolve também modelagem completa de ameaças, teste para overflows, liberação de informações, tratamento de erros, injeção SQL, autenticação e erros de autorização. O lado bom é que fazendo um trabalho minucioso em qualquer das áreas quase sempre se alcança outras. Como, por exemplo, ao testar vulnerabilidades XSS, você vai, com muita freqüência identificar também problemas de tratamento de erros e liberação de informação.

Estou assumindo que você faz parte de uma equipe que desenvolve e testa a aplicação para Web. Nessa posição privilegiada, você pode trabalhar a partir de uma perspectiva mista caixa preta/ caixa branca. Cada uma tem suas vantagens e, juntas podem até apoiar-se mutuamente.

1.

Tenha seu kit de ferramentas em ordem
O teste pode ser automatizado, mas não estamos tratando disso aqui. Ferramentas obrigatórias para teste manual focado incluem:

Paros proxy (http://www.parosproxy.org) para interceptar tráfego HTTP

Fiddler (http://www.fiddlertool.com/fiddler) para interceptar tráfego HTTP

Burp proxy (http://www.portswigger.net/proxy/)

TamperIE (http://www.bayden.com/dl/TamperIESetup.exe) para modificar GETs e POSTs

Assim, eu listei pelo menos três Web proxies aqui. Bem, examine alguns diferentes pois cada um tem seu caráter próprio. O ponto aqui é que você vai precisar interceptar as solicitações HTTP que o seu navegador da Web faz antes que eles sejam enviados, e então modificá-los para injetar seu teste de XSS. Cada uma destas ferramentas vai fazer esse serviço, e algumas também vão lhe mostrar o código fonte do HTML sendo retornado de você escolher interceptar as respostas do servidor.

Interceptar as solicitações GET e POST do cliente é extremamente importante. Isto vai lhe permitir contornar qualquer tipo de código de validação de input javascript do lado do cliente que possa ter sido introduzido. Observação para todos os desenvolvedores de Web - controles de segurança do lado do cliente não têm valor. A validação deve sempre ser feita no servidor.

2.

Mapeie o site e seu funcionamento - converse com os desenvolvedores e gerentes
Crie alguns diagramas simples de fluxo de dados que descrevam as páginas do site e seus objetivos. Este é um bom momento para marcar algumas reuniões com os desenvolvedores e gerentes de projeto para modelar ameaças. Use esse tempo para exercícios na aplicação o quanto possível. O site expõe serviços da Web? Há uma forma de autenticação? Há um quadro de mensagens? Uma página de configurações do usuário? Esteja certo de listar todas as páginas.

3.

Identifique e liste todos os pontos de entrada de dados por usuários
Leve o mapa do site um passo adiante. Geralmente eu crio um uma planilha para fazer isto. Para cada página, liste todos os parâmetros de cadeia de consulta, valores de cookies, cabeçalhos HTTP do cliente, valores de dados POST, e outras formas de input fornecidas por usuários anteriores transmitidos. Não esqueça de pesquisar serviços Web e solicitações SOAP similares, e identifique todos os campos que permitem input do usuário.
Liste todos os parâmetros de input separadamente pois você vai precisar testar cada um independentemente dos outros. Este é provavelmente o passo mais importante! Se você puder ler a planilha abaixo, verá que eu identifiquei um monte no site amostra. Consulte valores de cadeia como forwardURL e valores de dados de linguagem. POST como nome, senha, msgBody, msgTitle, e até alguns valores de cookies. Todos estes são interessantes e importantes para testar.

4.

Pense no todo e liste seus casos para teste
Pegue sua planilha e liste todas as maneiras diferentes que você vai tentar para testar as vulnerabilidades XSS. Vou falar sobre variações adiante, mas agora dê uma olhada na tela de minha planilha e perceba como eu listo a página com cada valor que ela permita e cada tipo para teste por valor. Este método de registrar os testes é o meu estilo e você pode com certeza criar o seu. Eu apenas gosto de registrar tudo, assim eu sei o que foi e o que não foi tentado.

5.

Comece a testar e preste atenção a saída
A parte mais importante de achar uma vulnerabilidade não é saber que você achou. É saber se você realmente sabe o que está se passando. Com XSS, examine o output HTML e localize onde seu input foi feito. Foi num tag HREF? Um tag IFRAME? É um CLSID? Um IMG SRC? Que tal o PARAM NAME de algum conteúdo Flash?
Já vi todos estes casos, e se você entender exatamente o que o input está fazendo, você será capaz de ajustar seu teste para identificar o problema. Isto quer dizer que você pode ter de afixar um colchete de encerramento > extra para escapar de um tag, o acrescentar aspas duplas a um elemento dentro de um tag. Ou você talvez terá que codificar seus caracteres com URL ou HTML, como transformar aspas duplas em %22 ou ".

6.

Hmmm não é tão fácil, este site é firme. E agora?
Talvez seu caso simples de teste de <script>alert('hi')</script> não esteja produzindo a caixa de alerta que você esperava. Repasse isso e fale com os desenvolvedores, se puder. Talvez eles estejam filtrando input para colchetes, aspas simples ou parênteses. Talvez eles estejam filtrando para a palavra "script". Novamente, estude como o input está produzindo o output e perceba exatamente o que cada um dos valores (cadeia de consulta, cookie, POST data) está fazendo. Um valor de cadeia de consulta como "pageId=10" pode até nunca chegar ao output , assim pode até não valer a pena ser testado. Ás vezes é melhor apenas tentar injetar caracteres simples como o colchet, aspas duplas, ou parênteses apenas para ver como a aplicação está filtrando esses caracteres. Aí você vai saber com que nível de filtragem está lidando. Você pode ajustar seus testes para codificar esses caracteres e tentar novamente, ou encontrar outras maneiras para injetar.

Variando os casos de teste

Nunca é demais repetir: Estudar como os valores de input chegam às páginas de output HTML é extremamente importante. Se eles não estiverem chegando, não perca seu tempo. Se estiverem, examine onde, pois você precisará variar seu teste de acordo. Eu uso algumas variações para identificar parâmetros que aceitam e exibem código scriptável. Existem muitos para listar aqui, mas aqui estão alguns:

1.

>"'><script>alert('XSS')</script>

2.

>%22%27><img%20src%3d%22javascript:alert(%27XSS%27)%22>

3.

>"'><img%20src%3D%26%23x6a;%26%23x61;%26%23x76;%26%23x61;%26%23x73;%26%23x63;%26%23x72;%26%23x69;%26%23x70;%26%23x74;%26%23x3a;alert(%26quot;XSS%26quot;)>

4.

AK%22%20style%3D%22background:url(javascript:alert(%27XSS%27))%22%20OS%22

5.

%22%2Balert(%27XSS%27)%2B%22

6.

<table background="javascript:alert(([code])"></table>

7.

<object type=text/html data="javascript:alert(([code]);"></object>

8.

<body onload="javascript:alert(([code])"></body>

Há muitas variações para serem tentadas. A chave é entender como o input está sendo processado e entregue na página de output. Como mostram estes exemplos, as variações freqüentemente envolvem preceder o código scriptável com ">"" a fim de tentar fechar tags que o Web site possa produzir n output. Eles envolvem ainda codificação URL do código numa tentativa de contornar filtros de input no lado do servidor. Além disso, uma vez que "<>" são comumente filtrados durante o input, também devem ser testados XSS que não necessitam colchetes, tais como "&{alert('XSS')};"

Persistente vs. dinâmico

Identificar um XSS bem sucedido é difícil, porque a invasão XSS pode não ser tão óbvia a princípio. Como exemplo arbitrário, ao adicionar uma nova mensagem ao site e injetar no valor "msgTitle", você pode não ver o código scriptável executar imediatamente após o dado ser submetido. Todavia, quando você visita o quadro de mensagem, o valor "msgTitle" pode ser usado no HTML da página e executado como código scriptável. A isto se pode referir como uma invasão XSS persistente que ocorre quando o valor contendo o código scriptável seria salvo para o cliente ou ao backend para ser executado depois.

Isto está em contraste com invasões XSS dinâmicas que executam imediatamente e apenas uma vez. Por exemplo, quando um link ou solicitação GTE for formada com código scriptável em um dos valores de cadeia de consulta que controla output na página, então aquele output pode ser exibido somente uma vez quando o link for clicado.

Conclusão

Teste para XSS é geralmente apenas uma pequena parte de uma revisão completa da segurança de uma aplicação da Web, mas justifica que seja feita minuciosamente. Após fazer isso por muitos anos, enfatizo que o uso de uma planilha ou algo mais para documentar todas as páginas no site, juntamente com todos os valores de input que cada página aceita (cadeia de consulta, cookie, POST data, SOAP) é um passo crítico antes mesmo de começar a testar. Igualmente importante é seguir o input e entender como ele é encaminhado na página de output HTML. Se você souber como a aplicação está usando o input, muita coisa será feita muito mais rápido. Não perca tempo tentando input que nunca é exibido como output. Fale com os desenvolvedores e gerentes de projeto e faça um bom trabalho modelando ameaça antes de começar.


Início da páginaInício da página