Virus Total API com café

Quem nunca ouviu falar do virus total ? Resolvi testar a API, com python, algo bem simples onde o único parâmetro fosse passar o arquivo que será escaneado.

A propiá documentação, mostra como usar cada recurso, com exemplos bem simples, não só em python, mas também em php e curl, mas não ensina como juntar tudo, não sei ao certo se a forma descrita a baixo é a correta ( se existir uma ), ou a mais rápida, porém me serviu bem, e é ela que estou usando atualmente, então sem mais delongas, vamos começar.

Resumo do projeto

A API Pública do VirusTotal permite que você faça upload e digitalização de arquivos, envie e analise URLs, acesse relatórios de verificação concluídos e faça comentários automáticos sobre URLs e amostras sem a necessidade de usar a interface do site HTML. Em outras palavras, ele permite que você crie scripts simples para acessar as informações geradas pelo VirusTotal.

O seu script faz uma requisição HTTP POST no site:

https://www.virustotal.com/vtapi/v2/file/

É retornado um JSON, com as informações solicitadas.

Limitações

A API lhe limite em 4 scans por minuto, caso esse exceda esse tempo a pagina lhe retornara um código HTTP 204, caso seja bem sucedido ele retornará um código 200.

A documentação sugere que você não faça upload de arquivos maiores que 32 mb, apesar de que são aceitos arquivos de até 128 mb.

Começando

Você precisa de um API key, então vá no site e clique em Junte-se a comunidade.

Scan de arquivos

Nessa etapa você precisa submeter o arquivo para scan, para isso temos que pegar o JSON do nosso HTTP POST que é encontrado na url da API mais a palavra scan.

Usando a biblioteca request, um exemplo de código é:

#! /usr/bin/env python

import requests

class VirusTotal(object):
    def __init__(self, codeKey, file):
        self.codeKey = codeKey
        self.url = 'https://www.virustotal.com/vtapi/v2/file/'
        self.file = file
    def send(self):
        self.params = {'apikey': self.codeKey}
        files = {'file': (self.file, open(self.file, 'rb'))}
        response = requests.post(self.url + 'scan',
        files = files, params=self.params)
        json_response = response.json()

Para testar instancie a nossa classe VirusTotal passando o nosso API KEY e o arquivo para scan:

vt = VirusTotal('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', 'file.txt')

A próxima etapa é chamar o metodo que envia o arquivo para upload.

resposta = vt.send()

Logo a saída será similar a:

{'permalink': 'https://www.virustotal.com/file/4313d3b.../analysis/1493410803/', 
'sha1': '50028644ad39f8cf5c2afc9bc6a27b21a3277cbf', 
'verbose_msg': 'Scan request successfully queued, come back later for the report', 
'response_code': 1, 
'md5': 'ca30bb74322aa540a9564aaac864983a', 
'resource': '4313d3b7be5b6775c827280a03124a....659e5d-1493410803', 
'scan_id': '4313d3b7be5b6775c8...d2659e5d-1493410803',
'sha256': '4313d3b7be5b6775c827280a0312...2659e5d'}

Permalink é o link que você pode acessar a sua analise, não será usado nesse script.

Temos os hashs tirados em SHA1, MD5, SHA256

verbose_msg que exibe uma mensagem de scan, que não será usado nesse script.

respose_code é um código que se for 0 o item procurado não estava no banco de dados do vírus total. Se o item ainda está na fila o resultado será -2 e se o poderia ser recuperado o retorno seria 1.

resource: Nada mais é que o sha256, mas que também pode ser qualquer qualquer um dos outros hashes.

O scan_id campo do objeto JSON permite consultar o relatório. Que também é o SHA256.

A documentação alerta que: os arquivos enviados usando a API têm a menor prioridade de varredura, dependendo da carga do VirusTotal, pode demorar várias horas antes do arquivo é verificado, por isso consultar o relatório em intervalos regulares até que o resultado aparece e não manter o envio do arquivo repetidamente.

Consultar Resultados

O script acima apenas coloca o arquivo na fila de upload, não exibe resultados, logo após o upload devemos consultar o resultado, a requisição de ser feita para: https://www.virustotal.com/vtapi/v2/file/report que é a nossa url antiga mais a palavra report, o outro parametro que precisamos é o resource, entao vamos tirar o hash sha256 com a biblioteca hashlib.

def hash(self):
    import hashlib 
    bufsize = 65366

    sha256 = hashlib.sha256()
    with open(self.file, 'rb') as f:
         while True:
             data = f.read(bufsize)
             if not data:
                break 
             sha256.update(data)
    return sha256.hexdigest()

Então vamos chamar nosso metodo:

resource = vt.hash()

O resultado será o hash do seu arquivo.

Agora que já temos o resourse e a url podemos montar a nossa consulta ao banco de dados do virus total.

def reports(self, resource):
    params = {'apikey': self.codeKey, 'resource': resource}
    headers = {"Accept-Encoding": "gzip, deflate", "User-Agent": "gzip"}
    url = self.url + "report"
    response = requests.get(url, params=params, headers=headers)
    json_response = response.json()
    return json_response

Basicamente esse metodo se conecta via post na url, passa um cabeçalho, recebe um json e retorna algo semelhante ao seguinte:

{'scan_date': '2017-05-06 05:45:45',
'scans': {
'Symantec': {'version': '1.3.1.0', 'result': None, 'update': '20170505', 'detected': False},
 'Comodo': {'version': '27043', 'result': None, 'update': '20170506', 'detected': False}, 'TrendMicro': {'version': '9.740.0.1012', 'result': None, 'update': '20170506', 'detected': False},
 .
 .
 .
 'Tencent': {'version': '1.0.0.1', 'result': None, 'update': '20170506', 'detected': False}, 'GData': {'version': 'A:25.12262B:25.9461', 'result': None, 'update': '20170506', 'detected': False}},
 'sha256': '37e87f86eabaeba56acd9f70ab93895fbbf738c9b2624ba0e4bb8b2c5d7eae69',
 'sha1': 'c5cd7d6a299fa666829bf70b4472398cf19cb49d',
 'scan_id': '37e87f86eabaeba56acd9f70ab93895fbbf738c9b2624ba0e4bb8b2c5d7eae69-1494085545', 'verbose_msg': 'Scan finished, information embedded',
 'total': 55,
 'md5': '45b6a54d33a39651098801a445766e1c',
 'resource': '37e87f86eabaeba56acd9f70ab93895fbbf738c9b2624ba0e4bb8b2c5d7eae69', 'response_code': 1,
 'positives': 0,
 'permalink': 'https://www.virustotal.com/file/37e87f86eabaeba56acd9f70ab93895fbbf738c9b2624ba0e4bb8b2c5d7eae69/analysis/1494085545/'}

Repare na saída do campo scan passa quais são os antivírus foram scaneados e qual a resposta se o malware for encontrado o detected recebe True se não recebe False o proximo passo então é tratar essa saída.

def decteccao(self, report):
    av = []
    if report['positives'] >= 1:
        scans = report['scans']
        for detect in scans.keys():
            if str(scans[detect]['detected']) == 'True':
                av.append(detect)
    return av

Criei um array vazio para armazenar todos os positivos, onde retornamos esse valor.

Pronto, agora o script já está funcionando, o ultimo ponto e chamar todos os metodos, com main()

 

def main(self):

    resource = vt.hash()
    report = vt.reports(resource)
    while report['response_code'] != 1:

        if report['response_code'] == 0:
            print("[+] Sending the file, status: %i" % report['response_code'])
            vt.send()
            report = vt.reports(resource)
            print("[*] Waiting for file parsing")
        elif report['response_code'] == -2:
            time.sleep(25)
            report = vt.reports(resource)
    print("[+] File uploaded successfully")

    antivirus = vt.decteccao(report)
    if len(antivirus) >= 1:
        print("[!] Malware foud in: \n")
        for av in antivirus:
            print("[!] AV: %s" % av)
    else:
        print("[?] Malware not found")

O código pega hash, passa para o metodo report , enquanto o arquivo não for upado ele fica em loop depois trata a saída. Então o script ficou:

# ! /usr/bin/env python

import requests
import time
import sys


class VirusTotal(object):
    def __init__(self, codeKey, file):
        self.codeKey = codeKey
        self.url = 'https://www.virustotal.com/vtapi/v2/file/'
        self.file = file

    def send(self):
        self.params = {'apikey': self.codeKey}
        files = {'file': (self.file, open(self.file, 'rb'))}
        requests.post(self.url + 'scan', files=files, params=self.params)

    def hash(self):

        import hashlib
        bufsize = 65366

        sha256 = hashlib.sha256()
        with open(self.file, 'rb') as f:
            while True:
                data = f.read(bufsize)
                if not data:
                    break
                sha256.update(data)
        return sha256.hexdigest()

    def reports(self, resource):
        params = {'apikey': self.codeKey, 'resource': resource}
        headers = {"Accept-Encoding": "gzip, deflate", "User-Agent": "gzip"}
        url = self.url + "report"
        response = requests.get(url, params=params, headers=headers)
        json_response = response.json()
        return json_response

    def decteccao(self, report):
        av = []
        if report['positives'] >= 1:
            scans = report['scans']
            for detect in scans.keys():
                if str(scans[detect]['detected']) == 'True':
                    av.append(detect)
        return av

    def main(self):

        resource = vt.hash()
        report = vt.reports(resource)
        while report['response_code'] != 1:

            if report['response_code'] == 0:
                print("[+] Sending the file, status: %i" % report['response_code'])
                vt.send()
                report = vt.reports(resource)
                print("[*] Waiting for file parsing")
            elif report['response_code'] == -2:
                time.sleep(25)
                report = vt.reports(resource)
        print("[+] File uploaded successfully")

        antivirus = vt.decteccao(report)
        if len(antivirus) >= 1:
            print("[!] Malware foud in: \n")
            for av in antivirus:
                print("[!] AV: %s" % av)
        else:
            print("[?] Malware not found")


if __name__ == '__main__':

    try:
        with open('.vt.key', 'r') as f:
            key = f.readline()
        f.close()
    except:
        sys.exit("[!] Configure o arquivo .vt.key com o seu API KEY")

    vt = VirusTotal(key, 'core.txt')
    vt.main()

 

 

Anúncios

2 comentários sobre “Virus Total API com café”

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s