Rafael Fidelis

I write about programming and random things

Como Eu Usei O Cartão De Crédito Do CEO Do Trampos.co Para Pagar Minha Assinatura Premium

| Comments

Falhas de segurança em aplicações web são muito comuns, existem validações que os desenvolvedores se esquecem de fazer, - e geralmente são validações básicas como controle de nível de acesso - e isso pode gerar grandes problemas no futuro de qualquer produto que esteja acessivel na web.

Essas falhas de segurança podem ser um problema ainda maior quando estão relacionadas a pagamentos com cartões de creditos, já que um atacante pode conseguir efetuar transações nos cartões dos usuários da aplicação, e é sobre isso que eu vou falar hoje.



Alvo: Trampos.co

O trampos.co um site de anuncio de vagas, muito conhecido e utilizado na cidade de São Paulo e Rio de Janeiro, principalmente por agências e startups. O site mantêm a posição 1,416(fonte: Alexa) no rank de sites mais acessados do pais, cerca de 200k de usuários cadastrados (fonte: inspect pelo meu id no sistema) e cerca de 400 cartões de créditos salvos no banco de dados (fonte: meu id de cartão no sistema).

O site também recebe muito trafego, o que o torna um alvo muito interessante.

http://i.imgur.com/jlbamIl.png Fonte: https://www.similarweb.com/website/trampos.co



Falhas

Eu acabei encontrando as falhas acidentalmente, quando eu fiz um pedido de um dos planos premium disponíveis(https://trampos.co/premium#planos) na plataforma, foi gerado um pedido no sistema e fui redirecionado para o formulário de pagamento, conforme a imagem abaixo: Essa url segue o formato: https://trampos.co/checkout/orders/:order_id Formulário de pagamento: Trampos.co

Chave primária sequencial

Em nossos sistemas geralmente estamos acostumados a utilizar id sequenciais como chave primária de nossa tabela(ex: id), já que a maioria dos SGBD convencionam esse padrão. O maior problema com ids sequenciais é a facilidade que atacantes tem para encontrar a localização de um determinado registro utilizando as ferramentas construídas pelos próprios desenvolvedores da aplicação: Endpoints

Sabendo que o id dos pedidos é sequencial, eu comecei a brincar no próprio browser, navegando para o id = 1, porém acreditando que o acesso aos pedidos(orders) de outros usuários seriam negados sem autenticação, e para minha surpresa NÃO, o recurso estava público, conforme o print abaixo:

[GET] https://trampos.co/checkout/orders/1 Formulário de pagamento: Trampos.co

Pronto, basta clicar em Comprar e esse pedido vai ser processado no cartão do usuário, gerando uma transação nunca autorizada pelo dono do cartão de crédito.

E com o id sequencial, eu poderia fazer um loop infinito até localizar todos os pedidos abertos com cartões associados, e efetuar a compra do pedido…imaginem agora, 600, 1000, 1500 pedidos sendo processados sem a autorização dos proprietários dos cartões, imagina o tamanho do problema para o trampos.co resolver depois, ein?

Como eu sou um desenvolvedor bacana, logo pensei: “Puta merda, o cu de alguém tá em risco por essa falha, vou ligar lá e avisar os caras”.

Liguei no escritório dos caras, um dos desenvolvedores me atendeu e eu reportei essa falha simples, porém extremamente danosa para ele. Assim que eu desliguei o telefone, tive a ideia de fazer um script ruby para salvar todas as páginas html de pedidos abertos, para depois poder calcular o tamanho do estrago que seria feito (supondo que todos os pedidos seriam processados e autorizados pelas operadoras), porém os desenvolvedores subiram um fix ~rapido~, daqueles pra apagar incêndio, saca? (eu sei que você sabe, ein!! hauhauhhua)

Esse fix nada mais foi que um redirect, impedindo o acesso ao recurso diretamente… (isso fudeu meu crawlerzinho) e aparentemente tudo estava resolvido….Mas é claro que não!



PagarMe e cartões de crédito

Com a primeira falha de acesso resolvida, decidi tentar encontrar alguma outra brecha no sistema (para fins didáticos mesmo, já que tava ali né?!)

Desde que eu cai pela primeira vez no formulário de pagamento do site já identifiquei que todo o processamento era feito através do Pagar.me(recomendo + 1), e como eu já sabia que o sistema salvava as referências dos cartões do usuários para One Click Buy(ou Compra com um clique mesmo :P) decidi criar um novo pedido e tentar pagar com um cartão fake, e conforme esperado a minha transação foi negada junto das operadas no Pagar.me, porém o trampos.co salvou esse cartão para compras futuras e me redirecionou novamente para a página do pedido, conforme o print abaixo:

Formulário de pagamento: Trampos.co

Agora, eu precisava encontrar alguma outra alternativa para efetuar o pagamento desse pedido, mas como? Pensei: “Bom, deixa eu ver como funciona esse request com um cartão salvo”, e foi ai que eu percebi um parâmetro inocente no corpo do request e no formulário HTML:

HTML Form: Trampos.co Formulário de pagamento: Trampos.co
pagar_me_card_id = 407

HUMMMM SHERLOCK, TEMOS ALGO AQUI SENHOR!

Sendo assim, o dedo já começou a coçar e como meu cartão com ID 407 era fake e inválido, eu precisava tentar com um cartão válido…e porque não tentar utilizar um do próprio sistema do trampos.co (levando em consideração que esse id também é sequencial)… Alterei o corpo do request e enviei: pagar_me_card_id = 1

1
curl 'https://trampos.co/checkout/orders/:order_id/payment' -H '(...)' --data 'pagar_me_card_id=1' --compressed

Alguns segundos aguardando ansiosamente, com os olhos penetrados no terminal como se ele fosse a resposta para tudo que aquele request representava…e então BOOOOOOM, meu pedido foi aceito pelo sistema e recebo o seguinte email:

Email de confirmação de Pagamento do trampos.co

Percebem? “Em nome de Tiago Yonamine”, pera….deixa eu ver algo aqui: (navega até http://trampos.co/sobre)

EITA CARAIO, ESSE É O CARTÃO DO CEO DA PORRA TODA

Duas coisas que eu pensei nessa hora:
1 - PQP FUDEU MUITO!
2 - Porra, pelo menos o primeiro teste em prod não foi feito com o cartão do desenvolvedor……meno male…

Com esse parâmetro em mãos, eu poderia tentar usar QUALQUER ID como pagar_me_card_id até encontrar um que autorizasse minhas transações, e dessa forma poderia pagar quantos planos premium eu conseguisse registrar (e lembre-se que isso tudo seria feito por um script, então no pior dos cenários eu poderia estourar o limite de cartão por cartão do sistema, já pensou? Nessa hora não passa nem átomo no cu, é rapaz, melhor ficar ligeiro!)



Keep it simple safe

Depois de ter acesso a essa falha, consigo imaginar mais ou menos como deve estar o código do endpoint /orders/:order_id/payments no backend, algo como:

1
2
3
4
5
# cartão do sistema somente salva os dados básico do cartão # referencia do mesmo cartão no banco de dados do Pagar.me
card = Card.find_by(id: params[:pagar_me_card_id])

pagar_me_card = PagarMe::Card.find_by_id(card.pagar_me_id)
transaction = PagarMe::Transaction.new(card: pagar_me_card)

Essa falha poderia ter sido facilmente evitada de uma forma extremamente simples:

1
2
3
card = current_user.cards.find_by(id: params[:pagar_me_card_id])
# ou
card = Card.find_by(id: params[:pagar_me_card_id], user_id: current_user.id)

Pronto, todos os requests irão procurar o cartão no contexto do usuário logado, salvando o dia novamente o/



Prestenção

Como você pode perceber, uma simples falha de permissão poderia ter se tornado uma grande problema para o trampos.co, e sua aplicação? Está segura? Tire algumas horas para verificar seus endpoints e tenha certeza que o controle de acesso está corretamente implementado!



Responsible Disclosure

Entrei em contato com a empresa responsável pelo site no dia 03/02/2016 e notifiquei a falha:

Dia que entrei em contato: 03/02/2016
Dia que corrigiram: 03/02/2016
Dia que responderam:09/05/2016
Meios de contato: Através de telefone conversei com o CEO e um programador do site.



Notas Finais

Uma outra solução que tornaria esse ataque MUITO MENOS(bem menos mesmo) efetivo seria usar guid para identificar os recursos no banco de dados - ou mesmo como chave primária - dessa forma é praticamente impossível que alguma ferramenta consiga extrair ou acessar os dados da sua API tão facilmente.

Também devo citar que achei a política de report de vulnerabilidade do Trampos.co nada ideal, basicamente nem me agradeceram e nem fizeram questão de me notificar sobre a correção da falha, é triste ver uma empresa tratar profissionais de segurança assim.

Umas das referências que usei pra escrever esse post: https://m4dwolf.wordpress.com/2016/02/21/food-hacking-2/ (recomendo bastante!)

Comments