Unconfigured Ad Widget

Collapse

Anúncio

Collapse
No announcement yet.

Explorando CSRF em formulários

Collapse
X
 
  • Filter
  • Tempo
  • Show
Clear All
new posts

  • Font Size
    #1

    Matéria Explorando CSRF em formulários

    Olá, novamente!
    Há anos estou pretendendo criar um tutorial sobre CSRF. Alguém me pediu isso há 2 anos... mas, como dizem, antes tarde do que nunca.

    CSRF (cross-site request forgery, ou falsificação de requisição de um website para outro) é uma vulnerabilidade que se utiliza de formulários sem verificação por token (veremos a seguir como realizar a proteção).
    Trata-se de preparar páginas especiais (exploits) que simulam o envio de um formulário, muitas vezes a formulários de postagem, comentários, alteração de dados (como senhas), compras (etc), sem que o usuário tenha conhecimento (mas utilizando o navegador do próprio usuário alvo).
    O usuário alvo normalmente é o administrador de um website (cujos formulários já são conhecidos, como é o caso de um site rodando alguma CMS famosa, como Wordpress, Drupal ou Joomla. Ou algum site de compras, cuja vulnerabilidade foi confirmada.
    Constatada a vulnerabilidade, teremos que utilizar um pouco de engenharia social. Dado que não é necessário que a vítima faça nenhum download, não é tão difícil de se cair nesse golpe (até mesmo nós, da área da segurança).
    É claro, convém afirmar que, para que o ataque funcione, é necessário que o usuário já esteja logado. Por isso, também é interessante enviar os ataques de engenharia social por websites (principalmente aqueles com comentários moderados pelos administradores - é claro que estarão logados quando lerem seu comentário - visto que normalmente clicam nos links para verificar se não é propaganda para outro website do mesmo tipo do deles).


    Um simples clique não deve fazer tão mal... ou será que faz?

    Nosso alvo, neste tutorial, é um pseudosite utilizando Apenas usuários registrados e ativados podem ver os links., Clique aqui para se cadastrar..., que é um sistema de blogs em PHP interessante por não utilizar nenhum banco de dados SQL (guarda todo o seu conteúdo em arquivos comuns - mas isso não difere em muita coisa no nosso ataque; é apenas um detalhe interessante).
    Para testarmos, instalei o sistema em meu servidor local. Vamos acessar nosso alvo:


    Estudando o alvo
    Primeiramente, precisamos escrever nosso exploit. Para isso, precisamos ter acesso ao painel administrativo - não necessariamente o do site alvo, mas de qualquer outro site que utilize o mesmo sistema - ou até mesmo instalar o sistema na própria máquina para acessar seu painel.
    Vamos definir metas: o que queremos fazer?
    Já citei exemplos de coisas possíveis de serem feitas, mas isso é muito relativo. Vai depender imensamente do sistema alvo. Como este é um sistema de blog, vamos fazer o mais básico: criar um post.
    Com o sistema instalado em nossa máquina, vamos abrir o painel administrativo.


    E vamos abrir a página contendo nosso formulário alvo (no caso, a página de postagem).


    Vamos ver seu código fonte (Ctrl + U no Google Chrome/Chromium) e procurar por nosso formulário. Note que encontramos 2 formulários na página. Mas o primeiro, como vemos na imagem a seguir, se trata apenas do formulário de busca:


    O segundo formulário encontrado é mais interessante, afinal, é o nosso alvo.


    Tudo o que precisamos fazer agora é recriar o formulário, porém, com algumas modificações:
    • Os campos devem ser do tipo "hidden", ou seja, terão valores predeterminados e não serão exibidos na página.
    • O formulário deve estar totalmente oculto, e deve ser submetido (enviado) sem que o usuário precise clicar em nada, bastando apenas abrir a página exploit.
    • A saída do submit do formulário (a página que aparece depois que o formulário é submetido) também não pode aparecer.


    Captou? Agora vamos lá.

    Escrevendo o exploit
    Vamos criar a base, bem básica (redundância?), do nosso exploit. Claro, ele será feito em HTML.


    Note que inserimos também as tags style e script. A primeira será para esconder o frame (iframe, na realidade) para onde o action do formulário será enviado. O segundo, programaremos para que o formulário seja enviado automaticamente.
    Agora vamos montar o formulário. Perceba que todos os type são hidden (como vimos anteriormente) e os names são os mesmos encontrados no código-fonte original da página (parte branca da figura abaixo). Perceba, também, que inserimos nos parâmetros value o conteúdo dos campos, da forma que queremos que estejam (interessante ver que incluí códigos HTML no último campo, já que se tratava de um editor WYSIWYG, isto é, editor visual de textos (com botões para negrito, itálico etc)).
    Note, também, que o method do formulário do nosso exploit é o mesmo da página inicial. O mesmo vale para o parâmetro action, mas como ele é omitido no código original, geralmente ele é o mesmo endereço da página onde o formulário está sendo exibido.
    Obviamente, após testar o exploit em sua instalação local, você deverá trocar o domínio (e, se necessário, o caminho para o sistema) do parâmetro action, inserindo os dados do site alvo (na pŕatica, trocar localhost por Apenas usuários registrados e ativados podem ver os links., Clique aqui para se cadastrar...)


    Vamos também criar o frame para onde o formulário será submetido. Como a id que escolhemos para o frame é "escondido", temos que adicionar um parâmetro target na tag FORM de nosso formulário, cujo valor é a ID do frame que acabamos de criar.


    Agora vamos fazer o frame ficar invisível. Isso é extremamente fácil, basta conhecer um mínimo de CSS. Se não souber, basta seguir o padrão:
    Código:
    #id_do_que_deve_ser_escondido {
    	display: none;
    }


    Não é necessário tornar o formulário invisível, pois todos os seus campos já são invisíveis.

    Via Javascript, agora, vamos fazer com que, quando a página terminar de ser carregada, o formulário seja submetido. A parte "quando a página terminar de ser carregada" é de suma importância, já que estamos inserindo o código de submit do formulário antes que o form (e o iframe) sejam exibidos. Alternativamente, podemos incluir o código Javascript (sem o window.onload) após criarmos o form e o iframe, logo antes do fechamento da tag </body>, mas não acho muito organizado...


    Note que fizemos o Javascript procurar pelo elemento cuja id é "formulario", e realizar seu submit. Mas note, também, que não incluímos o parâmetro id no formulário. Simples: vamos inserí-lo.


    NComo todos os elementos da nossa página são invisíveis, nossa página está em branco, sem forma e vazia. Eu realmente sugiro que, para não causar muita suspeita, façamos aparecer algo. Assim, em caso de algum problema, não seremos tão suspeitos e poderemos enviar outro exploit. Você pode inserir qualquer coisa, como qualquer outra página. Como sou preguiçoso, vou apenas simular uma página de erro 404 (bem mal-feita).


    Tudo pronto com nosso exploit. Podemos hospedá-lo em qualquer servidor, ou mesmo no Apenas usuários registrados e ativados podem ver os links., Clique aqui para se cadastrar... (cuidado: eles banem contas por qualquer motivo (já me baniram por hospedar tutoriais sobre segurança...)). Claro, o link não ficará tão convincente utilizando o PasteHTML.

    Testando o exploit
    Antes de enviar nosso exploit para o alvo, precisamos executar os passos que ele terá que executar: acessar o link.


    A página de erro 404 que eu simulei (bem feia, por sinal) foi exibida. Vamos agora voltar à página inicial do sistema e ver o que fizemos:


    E é isso. Agora, você só precisa investir na engenharia social e enviar o link ao administrador por e-mail, comentário, formulário de contato, chat etc.

    Protegendo-se
    Para nossa proteção, um captcha já resolveria nosso problema. Mas, em certas ocasiões, captchas são inconvenientes. Neste caso, precisamos gerar um token, isto é, um código aleatório que será colocado em um campo oculto no formulário, gravado em uma sessão e, quando o formulário for enviado, verificado. Exemplo básico:

    index.php
    Código PHP:
    <?php
    session_start
    ();

    $token uniqid(); // geramos o token
    $_SESSION['csrf_token'] = $token// gravamos o token em uma session

    // agora vamos criar o formulário e inserir o token:
    ?>
    <form method="post" action="verificar.php">
    <input type="hidden" name="token" value="<?php echo $token?>" />
    Nome: <input type="text" name="nome" />
    <input type="submit" value="Submeter formulário" />
    </form>
    verificar.php
    Código PHP:
    <?php
    session_start
    (); // essa linha é importante

    if($_SESSION['csrf_token']!=$_POST['token']) { // se o token gravado em session não for igual ao token enviado do formulário
        
    echo 'Ataque CSRF detectado!!!'// exiba isso
    } else { // senão
        
    echo 'Tudo limpo. Seu nome é: '.htmlspecialchars($_POST['nome']);
    }
    Fácil, não? Mas para facilitar ainda mais, existe Apenas usuários registrados e ativados podem ver os links., Clique aqui para se cadastrar..., que já cuida da verificação por você. Veja o exemplo acima, como ficaria com o uso da mesma:
    index.php
    Código PHP:
    <?php
    session_start
    ();
    csrf::gen(); // isto irá gerar o token, mas não precisamos guardar em nenhuma variável
    include 'csrf.class.php'// incluímos a classe

    // agora vamos criar o formulário e inserir o token, chamado da classe:
    ?>
    <form method="post" action="verificar.php">
    <input type="hidden" name="token" value="<?php echo csrf::gen(); ?>" />
    Nome: <input type="text" name="nome" />
    <input type="submit" value="Submeter formulário" />
    </form>
    Código PHP:
    <?php
    session_start
    (); // essa linha é importante
    include 'csrf.class.php';

    if(!
    csrf::check($_POST['csrf'])) { // se o token gravado em session não for igual ao token enviado do formulário
        
    echo 'Ataque CSRF detectado!!!'// exiba isso
    } else { // senão
        
    echo 'Tudo limpo. Seu nome é: '.htmlspecialchars($_POST['nome']);
    }
    Coisa simples, mas pode evitar uma baita dor de cabeça, já que é difícil perceber que o ataque partiu de um CSRF.

    Isso é tudo. Até mais!
    Este material pode ser compartilhado, desde que os devidos créditos sejam dados.



    Notify-list · Twitter · Blog

    Nova lei: Invadir computadores protegidos é crime.
    Lógica: Se eu invadi, não é protegido. Logo, não é crime :-)
    Similar Threads
X
Working...
X