===== Script en python para analizar múltiples ficheros desde terminal con VirusTotal =====
Script en python que permite enviar múltiples ficheros a virustotal para automatizar análisis de malware. Se necesita tener acceso a la [[https://www.virustotal.com/en/documentation/public-api/|API]] de virustotal por medio de la llave que ofrecen a cada usuario gratuitamente al crear una cuenta. Se debe editar la variable "key" del script.
**Dependencias**.
* Python2 + python simplejson.
* Acceso a la API de virus total ([[https://www.virustotal.com/en/documentation/public-api/]]).
**Limitación actual de la API**: cuatro consultas por minuto (consultar documentación).
**Sintaxis**.
bmmvtu.py --output
Argumentos:
-o --output Path of the file to write output to
-h --help Prints this help message
Ejemplos:
bmmvtu.py -o results.csv evil1.exe evil2.exe
bmmvtu.py --output results.txt folder/*
**Código de BMMVTU.py**: Batch/Mass/Multiple VirusTotal.com Uploader ([[http://blog.g0tmi1k.com/2011/10/bmmvtupy-batchmassmultiple/|Fuente]])
#!/usr/bin/python
#----------------------------------------------------------------------#
# Batch/Mass/Multiple VirusTotal.com Uploader (BMMVTU.py) v0.1 (2011-09-30)
#---Important----------------------------------------------------------#
# Python 2.6+ & simplejson needs to be installed before hand #
# Left a few debug commands & incomplete features in comments #
# #
# *** Do NOT use this for illegal or malicious use *** #
# YOU are using this script at YOUR OWN RISK. #
#This software is provided "as is" WITHOUT ANY guarantees OR warranty. #
#----------------------------------------------------------------------#
import getopt,hashlib,httplib,itertools,mimetypes,os,pprint,simplejson,sys,time,urlparse
#-----------------------------------------------------------------------
key = "def22a11de7bbff674094b877c1c1bab21fb3424b85720a70653958dcb7e8c2e" # Make sure to set this to your VirusTotal.com public API key.
sleepTime = 30 # VirusTotal.com only allows 20 requests every 5 minitues.
retry = 3 # The number of times to retry when something fails/Times to wait in the queue.
separator = "\t" # "," is commonly used for CSV files. TAB (\t) works well for pasting into spreadsheets.
#-----------------------------------------------------------------------
# Is it a valid file (Is it a file & its size)
def check_file(filename):
if not os.path.isfile(filename):
print "[-] Error: '%s' is not a valid file" % filename
fout.write("Error!" + separator + "not a valid file" + separator + filename + "\n")
return False
filesize = os.path.getsize(filename)
if filesize < 1 or filesize > 20971519:
print "[-] Error: Filesize (%s bytes)" % filesize
fout.write("Error!" + separator + "Filesize is wrong" + separator + filename + "\n")
return False
return True
# Get the results from VirusTotal.com
def get_report(resource):
json = post_multipart("https://www.virustotal.com/api/get_file_report.json", {'resource':resource, 'key':key})
return simplejson.loads(json)
# Checks the server response for the API (blocked or wrong key)
def result_status(result,resource):
while result == -2: # Exceeded the public API request rate
print "[-] Error: Exceeded the public API request rate (Waiting 60 second)"
time.sleep(60) # Wait a bit before re-trying
data = get_report(resource) # Check to see if MD5 is in the database
result = data['result']
if result == -1: # API key provided is incorrect
print "[-] Error: The API key provided is incorrect"
help()
sys.exit(1) # Quit, because we can't go further
return
# Request the file to VirusTotal.com
def send_file(filename):
files = [('file', filename, open(filename, 'rb').read())]
json = post_multipart("https://www.virustotal.com/api/scan_file.json", {'key':key}, files)
return simplejson.loads(json)
# The magic/behind the scene stuff/Under the bonnet
def do_files(filenames):
numFiles = len(filenames)
count = 0
for filename in filenames: # Do every file
try: # Keep going even if we get an error
count += 1
print "[>] Scanning %s/%s (%s)" % (str(count),str(numFiles),filename)
if check_file(filename) != True:
continue
md5sum = hashlib.md5(open(filename, 'rb').read()).hexdigest() # Find the file's MD5 value
data = get_report(md5sum) # Check to see if MD5 is in the database
result_status(data['result'],md5sum) # Check server response
if data['result'] != 1: # Not known to VirusTotal.com
for _ in itertools.repeat(None, retry): # Try xxx times to upload
print "[>] File not found. Submitting (%s)" % filename
data = send_file(filename) # Send the file to be scanned
if data['result'] == 1: # Have we successfully uploaded it?
break # Yes!
else: # No! Other? Fallback/Safey net
print "[-] Error: Submit failed (%s)" % filename # + str(pprint.pprint(data))
time.sleep(sleepTime) # Wait a bit before re-trying
if data['result'] != 1: # Result != 1 if upload wasn't successful
print "[-] Failed: Didn't submit (%s)" % filename
fout.write("Failed!" + separator + "Didn't submit" + separator + filename + "\n")
continue # Move on to the next file
for _ in itertools.repeat(None, retry): # Try xxx times to check
for o in data: # Read all the JSON objects
if o == "report": # Does VirusTotal.com have a report..
break # ...Yes! So quit
elif o == "scan_id": # ...No. Still scanning
scan_id = data['scan_id'] # Use the new scan ID value, rather than the MD5
print "[>] Waiting 60 seconds for VirusTotal.com to finish scanning (%s)" % scan_id
time.sleep(60) # Wait a bit before re-trying
elif data['result'] == 0: # ...No. Does VirusTotal.com know of it yet?
print "[>] Waiting in the queue"
time.sleep(sleepTime) # Wait a bit before re-trying
data = get_report(scan_id) # Check to see if MD5 is in the database
result_status(data['result'],scan_id) # Check server response
if data['result'] != 1: # Result != 1 if upload wasn't successful
print "[-] Failed: VirusTotal.com is still scanning or a large queue. Try again later or increase 'retry' (%s)" % filename
fout.write("Failed!" + separator + "still scanning or a large queue" + separator + filename + "\n")
#retry_files.append(scan_id)
continue
if count < numFiles: # If we are not using the last file...
time.sleep(sleepTime) # Sleep between requests so as not to overload VirusTotal.com
report = data['report']
permalink = data['permalink']
#scan_id = permalink.split('=')[1]
timeStamp = report[0]
reportEntries = report[1]
numEntries = len(reportEntries)
numDetects = 0
entryValues = dict.values(reportEntries)
for v in entryValues:
if v != u'':
numDetects += 1
output_string = md5sum + separator + timeStamp + separator + filename + separator + str(numEntries) + separator +str(numDetects) + separator
for k,v in sorted(reportEntries.iteritems()):
k = k.encode("ascii")
v = v.encode("ascii")
if v == "":
v = "-"
output_string += k + separator + v + separator
output_string += permalink
fout.write(output_string + "\n")
#pprint.pprint(data['report'])
except Exception as e:
print "[-] Error [1]: ", e
fout.write("Error!" + separator + str(e) + separator + filename + "\n")
# Perform an HTTP POST request
def post_multipart(url, fields, files=()):
content_type, data = encode_multipart_formdata(fields, files)
url_parts = urlparse.urlparse(url)
if url_parts.scheme == 'http':
h = httplib.HTTPConnection(url_parts.netloc)
elif url_parts.scheme == 'https':
h = httplib.HTTPSConnection(url_parts.netloc)
path = urlparse.urlunparse(('', '') + url_parts[2:])
h.request('POST', path, data, {'content-type':content_type})
return h.getresponse().read()
# Encoding the request
def encode_multipart_formdata(fields, files=()):
BOUNDARY = '----------ThIs_Is_tHe_bouNdaRY_$'
CRLF = '\r\n'
L = []
for key, value in fields.items():
L.append('--' + BOUNDARY)
L.append('Content-Disposition: form-data; name="%s"' % key)
L.append('')
L.append(value)
for (key, filename, value) in files:
L.append('--' + BOUNDARY)
L.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename))
content_type = mimetypes.guess_type(filename)[0] or "application/octet-stream"
L.append('Content-Type: %s' % content_type)
L.append('')
L.append(value)
L.append('--' + BOUNDARY + '--')
L.append('')
body = CRLF.join(L)
content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
return content_type, body
# Help screen
def help():
print "\n\nAbout:"
print " This is a Python script which makes use of VirusTotal.com's public API, to automate scanning multiple files."
print " To use this you will need a \"API key\" from VirusTotal.com (Free signup).\n\n"
print "bmmvtu.py --output \n"
print "Arguments:"
print " -o --output Path of the file to write output to"
print " -h --help Prints this help message\n\n"
print "Example:"
print " bmmvtu.py -o results.csv evil1.exe evil2.exe"
print " bmmvtu.py --output results.txt folder/*\n"
#-----------------------------------------------------------------------
print "[*] Batch/Mass/Multiple VirusTotal.com Uploader (BMMVTU) v0.1 (2011-09-30)"
# Process arguments
opts, args = getopt.getopt(sys.argv[1:], "o:h", ["output=", "help"])
for o, a in opts:
if o in ('-o', '--output'):
outputFileName = a
elif o in ('-h', '--help'):
help()
sys.exit(1)
else:
pass
# Check for valid number of arguments
if len(sys.argv) < 4:
print "[-] Error: Invalid number of arguments"
help()
sys.exit(1)
# Check for API key
if len(key) != 64:
print "[-] Error: Please provide a valid API key"
help()
sys.exit(1)
# Check the wait time
if sleepTime < 15:
print "[!] Warning: Its recommended to wait at least 15 seconds between requests"
if len(args) > 20:
print "[!] Warning: You will quicky max out your API request rate"
try:
fout = open(outputFileName, "w")
fout.write("md5sum" + separator + "timeStamp" + separator + "filename" + separator + "NumberOfAVs" + separator + "NumberOfDetects" + separator + ("" + separator + " " + separator)* 44 + "permalink\n")
#retry_files = list() # Retry these files (e.g. still waiting to be scanned)
do_files(args)
#do_files(retry_files)
fout.close()
except Exception as e:
print "[-] Error [0]: ", e
print "[*] Done!"
**Servicios similares a VirusTotal**.
* [[https://anubis.iseclab.org/|Anubis]] (Binarios desconocidos)
* [[http://wepawet.iseclab.org|Wepawet]] (Flash, JavaScript y ficheros PDF)
* [[http://www.team-cymru.org|Team Cymru]] (Múltiples motores de antivirus online)
* [[https://www.metascan-online.com/|Metascan]] (Múltiples motores de antivirus online)
* [[http://www.virscan.org/|Virscan]] (Múltiples motores de antivirus online)
* [[http://virusscan.jotti.org/es|Jotti's malware scan]] (Múltiples motores de antivirus online)