Spoofing: Zoando o aplicativo G1 do iPhone

Spoofing: Zoando o aplicativo G1 do iPhone

Só pela zoeria, decidi "hackear" o aplicativo de notícia G1 do iPhone para exibir uma notícia falsa. Eu o escolhi como alvo por aparentar ser bem simples. Provavelmente, ele só deve enviar pedidos ao servidor da Globo querendo as notícias e receber um JSON ou HTML com os dados para exibí-los. Como só deve fazer isso, não precisariam ter colocado alguma camada de segurança ou algo que complicaria. A intervenção que desejo fazer é somente alternar os dados que o aplicativo receberá.

De cara, já sabemos que estaremos fazendo um man-in-the-middle attack, pois a intervenção estará entre o tráfego do celular e o servidor da Globo. Além disso, também caracteriza-se como um spoofing attack, pois vou estar redirecionando os pacotes para enviar dados falsos me passando pelo verdadeiro.

Hotspot

A primeira ideia em mente que me veio foi fazer um hotspot no meu computador. Com hotspot, eu estarei roteando por wi-fi a rede do meu computador, e então posso conectar o iPhone na rede repassada. Dessa forma, vou estar bem no meio da comunidade entre o iPhone e a internet. Eu sei que isso vai atingir uma quantidade bem limitada de pessoas (no caso, só as que se conectarem na minha rede), mas como estou fazendo isso apenas pela zoeira e aprendizado, não terá problema. Depois posso melhorar isso.
Dependendo do seu ambiente gráfico, da para criar um hotspot com alguns poucos cliques. No meu caso, basta ir para o painel "Networking" e clicar o botão "Create a Wireless Hotspot".

iptables

Feito isso, agora precisamos saber como intervir na conexão entre o iPhone a internet. Após algumas pesquisas aleatórias no Google, outra ideia que me veio em mente foi estudar o iptables, e vi que com ele eu posso fazer isso. Caso não saiba o que diabos é o iptables, explicando de forma bem resumida, é um framework que possibilita gerenciar regras de filtros e traduções (nat) de pacotes de rede.
Antes de mexer nos pacotes entre o iPhone e a internet, decidi fazer alguns testes locais para agir em passos menores e aprender a manipular o iptables. Então, peguei dois sites simples, o http://icanhazip.com/ (64.182.208.182) e o http://www.yaml.org/ (66.228.46.32). O primeiro retorna o meu IP e o segundo é a documentação de YAML. São duas páginas muito simples.
Só para ver o que retornam, usei curl:

macabeus@macabeus-acer ~ $ curl 66.228.46.32
<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.0.5</center>
</body>
</html>
macabeus@macabeus-acer ~ $ curl 64.182.208.182
177.98.176.247

Por alguma razão, talvez por questão de diretório ou de redirecionamento, ir direto ao IP do site YAML retorna 404, mas isso não vai interferir nos nossos testes, pois eu desejo apenas mudar o tráfego das páginas. Para fins de testes, desejo que ao inserir o IP do icanhazip vá para o site da YAML.
Após estudar e ver vários exemplos do iptables, cheguei ao seguinte comando:

sudo iptables -t nat -A OUTPUT -d 64.182.208.182 -j DNAT --to-destination 66.228.46.32

O -t nat é para escolher em qual tabela mexeremos. O iptables trabalha com 4 tabelas diferentes, e a que importa para nós é a nat. Ela é consultada quando um pacote é criado no sistema - ou seja, se o navegador for abrir um nova página, ou tenha chegado um novo pacote no hotspot, essa tabela será consultada. Como ela é consultada assim que o pacote é criado, eu tenho a liberdade de usar alguns parâmetros exclusivos dela.
O segundo parâmetro, -A OUTPUT, é para adicionar uma nova regra à nossa tabela, e no caso, estamos criando no chain OUTPUT. "Chains" são as subseções das tabelas, e define quando a regra será aplicada e algumas retrições, no caso, o que optei diz que será alterará pacotes gerados localmente antes do roteamento.
O terceiro parâmetro, -d 64.182.208.182, diz para qual pacote de destino essa regra deve ser aplicada. No caso, é o IP do icanhazip.
O quarto e quinto parâmetros trabalham juntos, -j DNAT --to-destination 66.228.46.32 especifica que vou redirecionar o pacote para esse IP de destino. Eu só posso usar essa regra caso esteja na tabela nat e na chain OUTPUT ou PREROUTING.

Após adicionar essa regra e testar os curl da vida obtive um resultado diferente, conforme o esperado!

macabeus@macabeus-acer ~ $ curl 66.228.46.32
<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.0.5</center>
</body>
</html>
macabeus@macabeus-acer ~ $ curl 64.182.208.182
<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.0.5</center>
</body>
</html>

Acessando o site do icanhazip pelo navegador obtenho o mesmo resultado, o que é fantástico! Podemos também ver a regra que acabamos de criar:

macabeus@macabeus-acer ~ $ sudo iptables -t nat -L --line-numbers
...
Chain OUTPUT (policy ACCEPT)
num  target     prot opt source               destination         
1    DOCKER     all  --  anywhere            !127.0.0.0/8          ADDRTYPE match dst-type LOCAL
2    DNAT       all  --  anywhere             icanhazip.com        to:66.228.46.32
...

Se a apagarmos, veremos que tudo voltará ao normal:

macabeus@macabeus-acer ~ $ sudo iptables -t nat -D OUTPUT 2
macabeus@macabeus-acer ~ $ curl 66.228.46.32
<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.0.5</center>
</body>
</html>
macabeus@macabeus-acer ~ $ curl 64.182.208.182
177.98.176.247

Pronto! Conseguimos redirecionar o caminho de uma página web através do iptables!

Bottle entra em ação!

Então decidi fazer um teste bem simples usando o Bottle. Caso não saiba, o Bottle trata-se de um super-micro e singelo framework web para Python. O Bottle roda todo em apenas um único script py e usa somente as bibliotecas padrões do Python, o que torna extremalmente fácil de se trabalhar em coisas simples - como é o nosso caso.

Então, após instalar pelo pip3, fiz e executei o singelo script:

from bottle import route, run


@route('/')
def hello():
    return 'Macabeus é eleito o galã do século pela TIME'

run(host='0.0.0.0', port=80, debug=True)

E adicionei essa regra ao nosso comparça, o iptables:

sudo iptables -t nat -A OUTPUT -d 64.182.208.182 -j DNAT --to-destination 127.0.0.1

E então...

macabeus@macabeus-acer ~ $ curl 64.182.208.182
Macabeus é eleito o galã do século pela TIME

...funciona! O resultado é mais bacana se abrir no navegador, e já podemos começar a vislumbrar a zoeira tomando forma.

Wireshark, o oráculo!

Agora precisamos substituir o IP do icanhazip, que é só de teste, para o que o aplicativo do G1 requisita. Também precisamos saber de que forma que ele se comunica com o servidor. Pode ser que o aplicativo desenhe tudo com base em JSONs, como pode ser que receba o HTML puro e seco e apenas renderiza como um navegador normal faria. Para desvendar esse mistério, precisamos consultar o oráculo Wireshark. Caso não o conheça, ele é um sniffer, ou seja, softwares que ficam analisando os pacotes enviado e recebidos pela placa de rede.

No caso, nós não iremos exatamente rodar um sniffer no iPhone - isso daria trabalho de mais, é inviável. É muito mais fácil e prático aproveitarmos o hotspot que criamos agora a pouco. Como o iPhone está se comunicando na internet através da placa de rede do notebook, podemos mandar o Wireshark sniffá-la, e assim ver todos os pacotes do iPhone que nos interessa!

Eu abri o Wireshark com sudo, cliquei em "Interface List" e selecionei apenas o "wlan".

Caso você seja um sniffador de primeira viagem, algumas dicas: tenha uma mão preparada para startar a aplicação a sniffar e a outra mão preparada para pausar o sniffer. Quanto mais cedo você pausar o sniffer, menos pacotes terão para te confundir. Outra dica é encerrar o máximo de aplicações que podem poluir o seu sniffer.

Após passear um pouco na lista de pacotes, encontro o que me interessa. Em vários pacotes encontro o meu iPhone se comunicando com o IP 186.192.82.114. Jogando-o no Google vejo que é o IP da globo.com, e colocando o browser para ir até esse IP vejo que de fato é o site da globo.com
Também vejo que o aplicativo sempre recebe apenas HTML, e exatamente o mesmo do próprio site do G1. Podia ser que o aplicativo já tivesse tudo pré-renderizado e apenas recebesse JSON com os dados a serem escritos, mas não é esse o caso. Ou seja: no Bottle vou precisar enviar uma página falsa do G1.

Essa imagem demonstra um pouco a forma de se garantir de que aquele pacote é realmente o que busco:

Claro que nem sempre precisa fazer isso. As vezes é desnecessário, e em outras é impossível. Podia ser que o elemento não fosse visível, por exemplo.

Em relação à segurança, o aplicativo até que fez algumas comunicações TLS - ou seja, usa protocolos seguros. Mas em grande parte a comunicação é apenas por TCP e HTTP. Desse modo, creio que não teremos problemas em relação à segurança do aplicativo, isso é, se ele tiver alguma.

Fazendo a página falsa para enviar ao aplicativo

Antes de fazer a página falsa, decidi fazer uns testes mais simples, no caso, só enviar aquele mesmo texto já escrito no Bottle para o aplicativo. Daquele comando do iptables eu já sabia que precisaria mudar a chain, de OUTPUT para PREROUTING. A primeira só lidara com pacotes criados localmente, enquanto a segunda lida com pacotes que estejam de passagem pelo computador. Também era óbvio que precisava mudar os IPs. Então adicionei a seguinte regra, achando que funcionaria:

sudo iptables -t nat -A PREROUTING -d 186.192.82.114 -j DNAT --to-destination 127.0.0.1

Porém, agora o aplicativo do G1 exibia mais nada e no console do Bottle dizia que chegou nada. Havia feito alguma besteira, e não sabia qual. Pensnado agora, é bem óbvia qual era a besteira. Te dou 5 segundos para identificá-la.
Encontrou? Ótimo! O valor de --to-destination está errado! Para o iPhone, o endereço do Bottle não é localhost. O Bottle é localhost para o meu computador - no caso, o roteador para o iPhone.
Para esse erro tão idiota, passei 3h tentando encontrá-lo, não consegui, pedi help a um amigo meu do laboratório, o Zavam, e ele conseguiu resolver em menos de 2 minutos.

Então a regra correta seria:

sudo iptables -t nat -A PREROUTING -d 186.192.82.114 -j DNAT --to-destination 10.42.0.1

A faixa de IPs que começam com 10 são reservados para redes privadas. No caso, a conexão de hotspot entre o iPhone o computador formam uma rede privada. E no caso, 10.42.0.1 é o IP de que gerencia essa rede privada, e aqui é o mesmo que está rodando o Bottle. Logo, podemos usar essa rota para redirecionar o pacote que iria para a Globo e mandá-lo ao Bottle.

Após essa correção... Funciona!

Para gerar uma página falsa do mesmo estilo do G1 não é difícil. Eu apenas fui no site mesmo do G1, reduzir o tamanho da janela do browser e vi que fica igual ao do aplicativo. Logo, é aquela página mesmo. Então salvei a página, coloquei na mesma pasta do script Python e usei o jinja para modificar o HTML e deixar do jeito que quero. O código ficou assim:

from bottle import route, run, jinja2_view


@route('/')
@jinja2_view('page.html')
def hello():
    return {
        'news_subject': 'galanteador',
        'news_title': 'Macabeus é eleito o galã do século pela TIME',
        'news_sub': 'Diretor de Game of Thrones revela que Macabeus aparecerá na próxima temporada - e não morrerá!'
    }

run(host='0.0.0.0', port=80, debug=True)

E ficou assim:

Finalmentes

Obtive o resultado esperado: consegui alterar os dados recebidos pela rede de um aplicativo no iPhone. No caso, com propósitos de teste, usei o aplicativo G1.
As técnicas usadas mostraram-se capazes de se fazer isso, porém, é possível melhorar. Ao invés de usar um hotspot, poderia-se tentar fazer alguma coisa no roteador para atingir todos que usassem aquele roteador. Também é preciso de mais análises para lidar com aplicativos que usem alguma camada de segurança.

Uma vantagem em usar o hotspot é ser uma abordagem mais simples. Se o intuito for realmente interceptar e modificar os pacotes de seu celular, seja por estar fazendo um bot ou estudando o tráfego de pacotes de um aplicativo, é um bom caminho.

Enfim... O que foi apresentado serve de introdução e ponto de partida. Em alguma situação real num aplicativo mais elaborado seria necessário mais estudos. Talvez, o próximo passo seja usar o Ettercap.