O Ransomware Tracker é um ficheiro .CSV que tem várias informações sobre endereços IP que possam ser uma fonte de Ransomware.
Após uma primeira análise desta fonte de informação, podemos verificar que: as primeiras linhas são o cabeçalho e não têm interesse. Desta forma, podemos desde logo verificar que todas as linhas cujo primeiro caracter é o ‘#’ não têm interesse para a recolha de dados;
cada linha tem um registo que nos interessa;
cada linha é constituída por vários “campos”, separados por vírgulas; a informação disponível dentro de cada campo está entre aspas (“ ”).
os dados de interesse na página são:
- Firstseen: data de descoberta do malware; está no formato “yyyy-mm-dd
hh:mm:ss”;
- Threat: tipo de vulnerabilidade;
- Malware: nome do malware em questão;
- Host: nome do host onde o malware foi descoberto; - URL: URL de origem do malware;
- Status: status do host no momento (isto é, se o host está offline ou online); - Registar: agente de registo (entidades especializadas no registo e gestão de nomes de domínios);
Página 36 de 99
- Endereço(s) IP: lista de endereços IP onde foi verificada a existência de
malware;
- ASN(s): autonomous system number (identificador único de cada rede na internet que pertence, por norma, ao ISP);
- Country: Código do país de origem do malware encontrado.
Na posse de todos estes dados, já podemos determinar que a função parse terá como objetivos:
fazer o pedido à pagina para receber a informação de todo o ficheiro CSV; ler a resposta da página;
dividir a resposta em linhas (pois cada linha é um registo de interesse);
para cada linha, chamar a função process.
Por outro lado, podemos, também, verificar que a função process, que processa cada linha que a função parse retorna, terá como objetivos:
retirar as vírgulas da linha;
separar a linha nas aspas e atribuir os dados de interesse a variáveis temporárias;
tratar os dados e guardá-los segundo a Data Harmonization:
- o primeiro campo irá ser o “time.source”;
- o segundo campo irá ser o “event_description.text”; - o terceiro campo irá ser o “malware.name”;
- se o quarto campo não for um IP, deve ser guardado como “source.domain_name”;
Página 37 de 99
Figura 8 - Teste inicial para o Ransomware Tracker
-o quinto campo irá ser o “source.url”; -o sexto campo irá ser o “source.status”; -o sétimo campo irá ser o “source.registry”; -o oitavo campo irá ser o “source.ip”; -o nono campo irá ser o “source.as_name”; -o décimo campo irá ser o “source.geo_cc”.
Conhecendo todos estes dados, já temos condições suficientes para fazer um teste inicial.
Ao construirmos o teste com os passos acima descritos no estudo da fonte, podemos construi-lo com a estrutura que é demonstrada na figura 8:
Neste caso, não há necessidade do nosso teste estar dividido entre as funções parse e
process, pois a função parse diz respeito apenas ao pedido, à condição inicial
(r.status_code == 200) e ao ciclo que percorre cada linha do ficheiro CSV. A função
process, neste caso, será apenas o que está dentro do “else” da condição, pois somente
Página 38 de 99
Após verificar que este teste está a funcionar corretamente e nos devolve os dados certos, podemos adaptá-lo à plataforma, ou seja, retirar os dicionários e substituir os mesmos por eventos.
Após o teste ser adaptado à plataforma, procedemos à criação de um caso de teste. Para podermos criar o caso de teste, precisamos de recolher alguns dados do ficheiro de teste antes de continuar, sendo essas as entradas e saídas de dados das funções parse e process que podem ser acedidas através de prints dentro deste teste inicial.
Neste caso, para a função parse, como entrada temos todo o ficheiro CSV, ou seja, a resposta da página quando se faz o primeiro pedido (para receber este ficheiro) e, como saída, temos cada linha.
Por outro lado, para a função process, como entrada temos, por exemplo, a linha de dados que é o resultado da função parse e, como saída, teremos os dados já tratados.
Ao dispor destes dados, podemos fazer o nosso caso de teste em que damos, às funções, os valores de entrada escolhidos e verificamos se os resultados são os esperados.
Página 39 de 99
Para tal, o caso de teste terá o aspeto das figuras 9 e 10:
Ao ver a figura acima, podemos verificar que, na função test_parse, é chamada a função parse para uma resposta falsa da página, através do patch da função que irá receber a resposta da página para que, quando o bot correr, não faça um pedido à pagina e, em vez disso, crie um objeto falso que está presente no objeto mock_url. Neste caso, o objeto falso tem que ser construído com dois atributos essenciais: o status code e o valor de retorno da função de que se faz patch.
Ao chamar a função parse com este mock_url, a função irá retornar uma linha e essa linha será comparada com o resultado esperado (presente na variável
LINE_TO_PROCESS): se forem iguais, o teste da função parse irá ser concluído com
sucesso.
Página 40 de 99
Para a função process, é usada a variável LINE_TO_PROCESS como entrada e os dados de saída são comparados com os dados introduzidos pelo autor numa das funções disponíveis no módulo de unittest, a função assertEqual(). Se os resultados introduzidos pelo autor forem iguais aos resultados da função process, o teste da função process irá ser concluído com sucesso.
Após o caso de teste ser validado, o bot está pronto a ser testado numa cópia local (localizada na workstation do autor) das partes essenciais da plataforma, para garantir que o bot se integra e funciona corretamente dentro da mesma e é feito um pedido de
Git Push, ou seja, de submissão do plugin na plataforma, que será posteriormente aceite
pelo gestor do projeto.
Página 41 de 99