
Botnet command & control monitor
Hale é um monitor/espião de comando e controle (C&C) para botnets, com design modular para facilitar o desenvolvimento de novos módulos que monitoram novos protocolos usados por servidores C&C. Hale vem com monitores IRC e HTTP desenvolvidos com Twisted para lidar com escalabilidade de um grande número de conexões. Esses módulos possuem gramática de protocolo e configurações de bot configuráveis, mas também podem ser modificados para atender às suas necessidades. Todos os logs e arquivos capturados são salvos em um banco de dados e, no caso do IRC, os números de IP rastreados também.
Para ocultar a localização do operador, as conexões podem ser feitas através de proxies SOCKSv5, e isso é configurável através da interface web, onde também todos os logs estão disponíveis para navegação, juntamente com gráficos estatísticos e linhas do tempo. A interface foi desenvolvida com Django e a API de Visualização do Google. Alguns extras na interface web incluem suporte para uma API RESTful com suporte a OAuth e um mecanismo de busca.
A ideia principal do Hale é ajudar na caça a botnets e na pesquisa, colaborando através da criação de uma rede de sensores (monitores Hale). Para melhorar essa ideia, um bot XMPP está disponível para se conectar a um servidor XMPP centralizado, onde atualmente duas salas de grupo diferentes são usadas para coordenar entre sensores e uma sala para compartilhar logs e arquivos. A sala de coordenação faz uso de hashes de botnet que são gerados a partir das chaves únicas nas configurações do botnet, dessa forma, duas botnets não precisam ser monitoradas simultaneamente se tiverem o mesmo hash (identidade), melhorando a utilização. Para ajudar terceiros a usarem essa rede, um bot pode entrar na sala de coordenação e pedir a um sensor para começar a rastrear uma botnet se ela não estiver sendo rastreada, enviando as configurações para isso. Além disso, na sala de compartilhamento, bots de terceiros podem obter logs e arquivos capturados pelos sensores em tempo real. Para auxiliar no histórico de logs, a API web pode ser usada, suportando solicitações GET.
Hale tem as seguintes dependências:
Python == 2.6
Django == 1.2.1
Twisted == 10.1.0
GeoIP-Python == 1.2.4 (e lib C do GeoIP)
Whoosh == 0.3.18
django-haystack == 1.0.1-final
django-piston == 0.2.3rc1
pefile == 1.2.10-63
sleekxmpp == 0.9Rrc1
wsgiref == 0.1.2
zope.interface == 3.6.1
oauth2 == 1.2.0
httplib2 == 0.6.0
Além disso, o monitor requer um driver de backend de banco de dados correspondente ao banco de dados usado pelo Django. Quando essas bibliotecas estiverem instaladas, baixe o código-fonte daqui e extraia em qualquer lugar.
Primeiro, crie um banco de dados que será usado pelo Hale. O mecanismo do banco de dados pode ser de sua escolha. Se você estiver usando um banco de dados existente, pule esta etapa.
O próximo passo é instalar os drivers de backend de banco de dados Python correspondentes ao mecanismo do servidor.
Edite settings.py em hale/src/webdb/ e edite as seguintes configurações: ENGINE, NAME, USER, PASSWORD, HOST e PORT, onde a configuração do mecanismo é, por exemplo, django.db.backends.mysql se o mecanismo do seu servidor for MySQL. A configuração de nome é o nome do seu banco de dados usado ao criá-lo.
Se você não quiser iniciar sua própria interface web, pule esta etapa e vá para 8). Em settings.py, altere PATH_TO_APP para apontar para o caminho completo do aplicativo Django, por exemplo: '/home/..../Hale/src/webdb'. No diretório webdb, execute o seguinte comando: python manage.py syncdb. Se você receber algum erro aqui, provavelmente as configurações do banco de dados em settings.py estão incorretas. Além disso, durante a sincronização, defina o superusuário que será usado ao administrar os usuários.
Para suportar a pesquisa na interface web, execute python manage.py rebuild_index para permitir que o mecanismo de busca indexe pela primeira vez. Isso criará um diretório chamado . Para permitir que o servidor web escreva aqui, execute . Depois disso, execute e coloque isso como uma tarefa cron para atualizar os índices em um intervalo regular de sua escolha.
Alias /media /usr/local/lib/python2.6/dist-packages/django/contrib/admin/media/
<Location /media>
Order allow,deny
Allow from all
</Location>
WSGIDaemonProcess username processes=2 maximum-requests=500 threads=10
WSGIProcessGroup group
WSGIScriptAlias / /home/..../webdb/django.wsgi
e edite o nome de usuário e o grupo para os quais o daemon WSGI deve ser executado. WSGIScriptAlias deve ser definido como o caminho completo para o arquivo django.wsgi localizado no diretório webdb. O alias especificado acima é necessário para que a página de administração seja renderizada corretamente. Para poder enviar módulos através da interface web, execute chmod o+w webdb/modules.
Envie os módulos que serão usados de hale/src/modules/ ou escreva os seus próprios (consulte a seção Desenvolvimento). Envie o módulo desejado na interface de administração e edite, por exemplo, o nome do módulo para irc e o nome do arquivo para ircModule.py . Especifique regras de configuração para o módulo na seção correspondente localizada em hale/conf/modules.conf e coloque-as na caixa de texto. Adicione também as seções uniqueKeys para o módulo que está sendo enviado.
Antes de executar o monitor, edite hale.conf em hale/src/conf/ se desejar usar um servidor XMPP. Para ativar o bot XMPP, defina a configuração de uso como True e edite as informações de login para uma conta e servidor existentes ou inicie seu próprio servidor XMPP. Uma etapa importante ao iniciar um servidor XMPP é aumentar o tamanho máximo do stanza do valor padrão para algo como 10Mb. Caso contrário, a publicidade de malware não será possível. As configurações de canal em hale.conf são usadas para a sala de grupo de compartilhamento usada pelo bot, e a configuração coord é usada para a sala de grupo onde toda a coordenação entre sensores ocorre.
Edite hale.conf e defina as configurações do cliente e do servidor.
Para iniciar o monitor, vá para hale/src/ e execute python server.py. Se ele iniciar com erros, o arquivo settings.py do Django não está configurado corretamente ou faltam algumas bibliotecas. Com o cliente, é possível emitir comandos para o servidor, mas requer que o usuário se autentique no servidor; o acesso é concedido para usuários que são definidos como membros da equipe através da interface web. Quando o cliente estiver em execução, digite help ou ? para obter os comandos disponíveis. Digite help comando para obter mais informações sobre o comando específico. Iniciar um bot monitor é feito primeiro editando o arquivo hale/src/conf/modules.conf, por exemplo usando uma configuração IRC da seguinte forma:
[uniqueKeys]
irc = botnet, *grammar
[ircConf]
module = irc
botnet = irc.freenode.net
port = 6667
password = None
nick = nickname
username = agent007
realname = Spying
channel = #channelname
channel_pass = somepass
pass_grammar = PASS
nick_grammar = NICK
user_grammar = USER
join_grammar = JOIN
version_grammar = VERSION
time_grammar = TIME
privmsg_grammar = PRIVMSG
topic_grammar = TOPIC
currenttopic_grammar = 332
ping_grammar = PING
pong_grammar = PONG
Edite ou crie uma nova configuração especificando uma nova seção com nome único ([ircConf]). No topo do arquivo de configuração, há uma seção chamada uniqueKeys onde todos os campos exclusivos de um módulo são especificados e usados para gerar o hash do botnet; isso geralmente não deve ser alterado para preservar o rastreamento correto do botnet. Quando isso for feito, execute useconf section para carregar a configuração e, em seguida, inicie o bot com exec modulename id onde id é definido por você para identificar o botnet.
A interface web fornece acesso a todos os dados capturados no banco de dados, que podem ser acessados a partir da página inicial. Há também uma função de pesquisa que permite ao usuário pesquisar hashes de botnet e arquivos, números IP relacionados, IDs de botnet, módulos de botnet usados e hosts de botnet. Se o usuário tiver acesso para editar proxies ou módulos, isso pode ser feito na seção de administração; a URL para isso é http://.../admin. O administrador pode definir modos de usuário e também adicionar consumidores para a API web.
Implemente o módulo, por exemplo:
import moduleManager from utils import moduleInterface
@moduleManager.register("irc") def module_setup(config, hash): """ Função para registrar módulos, simplesmente implemente isso para passar a config e o hash para o objeto do módulo e retorne ele de volta. """
return IRC(config, hash)
class IRC(moduleInterface.Module):
def __init__(self, config, hash):
self.config = config
self.hash = hash
# deve ser implementado
def stop(self):
# parar execução
# deve ser implementado
def run(self):
# iniciar execução
# deve ser implementado
def getConfig(self):
return self.config
Adicione o decorador para a função de registro (neste caso, module_setup) que será chamada com a configuração atual como argumento e o hash da configuração composto pelas chaves únicas. Esta função pode ter qualquer nome. Passe as configurações para o objeto do módulo; o configHandler captura KeyErrors, então se configurações erradas forem enviadas para esta função, o configHandler notificará você sobre isso.
Também siga a convenção de nomenclatura nameModule.py e @moduleManager.register("name") e importe o moduleManager, caso contrário, o moduleManager notificará você sobre quaisquer erros.
O restante do código do módulo é omitido, mas deve criar um objeto factory do Twisted e iniciá-lo com o reactor no método run. Consulte os módulos existentes como exemplo. Para tutoriais sobre programação com Twisted, veja aqui. Existem também alguns utilitários para uso ao desenvolver módulos, isso é feito da seguinte forma:
Socksify:
# importar todos os utilitários
from utils import *
# no construtor, criar um novo objeto proxy
self.prox = proxySelector.ProxySelector()
# no método run, adicionar o seguinte após ter criado o método factory.
proxyInfo = self.prox.getRandomProxy()
if proxyInfo == None:
self.connector = reactor.connectTCP(host, port, factory)
else:
proxyHost = proxyInfo['HOST']
proxyPort = proxyInfo['PORT']
proxyUser = proxyInfo['USER']
proxyPass = proxyInfo['PASS']
socksify = socks5.ProxyClientCreator(reactor, factory)
if len(proxyUser) == 0:
self.connector = socksify.connectSocks5Proxy(host, port, proxyHost, proxyPort, "HALE")
else:
self.connector = socksify.connectSocks5Proxy(host, port, proxyHost, proxyPort, "HALE", proxyUser, proxyPass)
Tratamento de erros de conexão no objeto factory:
def clientConnectionFailed(self, connector, reason):
"""
Chamado em caso de falha de conexão com o servidor
"""
moduleCoordinator.ModuleCoordinator().putError("Erro ao conectar a " + self.config['botnet'], self.module)
def clientConnectionLost(self, connector, reason):
"""
Chamado em caso de perda de conexão com o servidor
"""
moduleCoordinator.ModuleCoordinator().putError("Conexão perdida com " + self.config['botnet'], self.module)
Isso enviará os erros para o bucket de erros, que pode ser acessado executando showlog no CLI.
Logging:
# no factory, criar o seguinte método para lidar com logs (note que o hash e a config devem ser enviados ao factory)
# e chamá-lo na classe protocol com: self.factory.putLog(data)
def putLog(self, log):
"""
Colocar log no manipulador de eventos
"""
moduleCoordinator.ModuleCoordinator().addEvent(moduleCoordinator.LOG_EVENT, log, self.hash, self.config)
# aplicar expressão regular para procurar URLs contendo possível malware
# e chamá-lo na classe protocol com: self.factory.checkForURL(data)
def checkForURL(self, data):
"""
Verificar URL no manipulador de eventos
"""
moduleCoordinator.ModuleCoordinator().addEvent(moduleCoordinator.URL_EVENT, data, self.hash)
# se o seu módulo deve detectar números IP de outros bots e pastores, implemente o seguinte método no factory
def addRelIP(self, data):
"""
Colocar possível IP relacionado ao botnet sendo monitorado
no manipulador de eventos.
"""
moduleCoordinator.ModuleCoordinator().addEvent(moduleCoordinator.RELIP_EVENT, data, self.hash)
O tratamento de IPs relacionados é feito aplicando uma expressão regular para ser usada no protocolo que o módulo irá suportar; no caso do módulo IRC, o código fica assim:
checkHost = data.split(':')[1].split(' ')[0].strip()
match = self.factory.expr.findall(checkHost)
if match:
self.factory.addRelIP(data.split('@')[1].split(' ')[0].strip())
onde a expressão regular é a seguinte:
self.expr = re.compile('!~.*?@')
2) Arraste o arquivo para o diretório modules. O moduleManager o importará automaticamente e verificará se há erros.
No modules.conf, edite a configuração
Envie o módulo para a interface web definindo o nome do módulo como, por exemplo, irc, nome do arquivo ircModule.py e, em seguida, adicione um exemplo de configuração para este módulo.
Ao enviar uma solicitação para rastrear um botnet, a solicitação é feita da seguinte forma para a sala de grupo de coordenação
sensorLoadReq
onde todos os sensores respondem com seu id e comprimento da fila (número de botnets monitorados)
sensorLoadAck id=353f6650859547ed06597dbfa1dcfd88 queue=0
O alimentador então escolhe um sensor com base nessas informações, como o menor comprimento de fila, e se estes forem iguais para vários sensores, o sensor com id ordenado alfabeticamente com o menor valor é escolhido.
Quando o alimentador escolheu um sensor, ele envia uma mensagem de chat privada para o sensor
startTrackReq config
onde config é uma representação em string da configuração, por exemplo
module=irc botnet=irc.freenode.net etc.
O sensor então responde com um reconhecimento junto com o hash da configuração que pode ser usado para distinguir os logs do botnet dos outros logs no canal de compartilhamento. Exemplo de reconhecimento:
startTrackAck hash
se ninguém mais estiver monitorando este botnet; caso contrário, um startTrackNack é recebido se o botnet já estiver sendo monitorado ou o sensor não tiver o módulo instalado para este botnet. O compartilhamento de malware é feito pelos sensores enviando uma mensagem como:
fileCaptured hash=353f6650... file content
onde o conteúdo é codificado em Base64 e vem imediatamente após o valor do hash do arquivo.
Para obter acesso à API, você precisa de uma chave de consumidor e uma chave secreta; elas podem ser criadas pelo administrador e são usadas com OAuth para autenticação. As seguintes URLs estão disponíveis para buscar dados em formato JSON:
http://.../api/botnet responderá com todos os botnets monitorados
http://.../api/botnet/botnethash responderá com o botnet com hash igual a botnethash
http://.../api/host/hostname responderá com todos os botnets monitorados com host igual a hostname
http://.../api/type/module responderá com todos os botnets monitorados com o módulo
http://.../api/botips/hash responderá com todos os IPs capturados pelo botnet com o valor hash
http://.../api/bologs/hash responderá com todos os logs do botnet com valor hash
http://.../api/bofiles/hash responderá com hashes de arquivos capturados pelo botnet com valor hash
http://.../api/file/hash retorna informações do(s) botnet(s) para aqueles que capturaram o arquivo com o hash especificado
http://.../api/ip/addr responderá com informações do(s) botnet(s) para aqueles que detectaram um IP com número addr
Observe que atualmente apenas solicitações GET são possíveis.
whoosh.index/chmod o+w whoosh.index/python manage.py update_indexExecute python manage.py runserver e acesse http://127.0.0.1:8000 para verificar se a configuração foi feita corretamente.
O comando runserver implanta um servidor de desenvolvimento que não é recomendado para uso em produção devido a problemas de desempenho. Em vez disso, implante a interface web instalando o mod_wsgi para Apache. Supondo que você esteja usando Ubuntu, execute apt-get install libapache2-mod-wsgi. Em /etc/apache2/sites-available/default adicione o seguinte: