Advertisement
Guest User

Untitled

a guest
Jun 5th, 2012
282
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.96 KB | None | 0 0
  1. #!/usr/bin/env python
  2.  
  3. __description__ = 'Program to search VirusTotal reports with search terms (MD5, SHA1, SHA256) found in the argument file'
  4. __author__ = 'Didier Stevens'
  5. __version__ = '0.0.4'
  6. __date__ = '2012/06/05'
  7.  
  8. """
  9.  
  10. Source code put in public domain by Didier Stevens, no Copyright
  11. https://DidierStevens.com
  12. Use at your own risk
  13.  
  14. History:
  15.  2012/04/25: start
  16.  2012/04/27: added serialization of reports
  17.  2012/05/23: emergency fix pkl init bug
  18.  2012/05/26: 0.0.3 added force option and key option; added environment variable; added requested field
  19.  2012/06/05: 0.0.4 added genhash and short options. By TecToDo
  20. Todo:
  21. """
  22.  
  23. import optparse
  24. import urllib
  25. import urllib2
  26. import time
  27. import sys
  28. import pickle
  29. import os
  30. import hashlib
  31.  
  32. try:
  33.     import simplejson
  34. except:
  35.     print('Missing simplejson Python module, please check if it is installed.')
  36.     exit()
  37.  
  38. VIRUSTOTAL_API2_KEY = ''
  39. VIRUSTOTAL_REPORT_URL = "https://www.virustotal.com/vtapi/v2/file/report"
  40.  
  41. PICKLE_FILE = 'virustotal-search.pkl'
  42.  
  43. def Serialize(object):
  44.     try:
  45.         fPickle = open(PICKLE_FILE, 'wb')
  46.     except:
  47.         return False
  48.     try:
  49.         pickle.dump(object, fPickle)
  50.     except:
  51.         return False
  52.     finally:
  53.         fPickle.close()
  54.     return True
  55.  
  56. def DeSerialize():
  57.     import os.path
  58.  
  59.     if os.path.isfile(PICKLE_FILE):
  60.         try:
  61.             fPickle = open(PICKLE_FILE, 'rb')
  62.         except:
  63.             return None
  64.         try:
  65.             object = pickle.load(fPickle)
  66.         except:
  67.             return None
  68.         finally:
  69.             fPickle.close()
  70.         return object
  71.     else:
  72.         return None
  73.  
  74. def Timestamp(epoch=None):
  75.     if epoch == None:
  76.         localTime = time.localtime()
  77.     else:
  78.         localTime = time.localtime(epoch)
  79.     return '%04d%02d%02d-%02d%02d%02d' % localTime[0:6]
  80.  
  81. class CSVLogger():
  82.     def __init__(self, prefix, headers, separator=';'):
  83.         self.separator = separator
  84.         self.filename = '%s-%s.csv' % (prefix, Timestamp())
  85.         self.f = open(self.filename, 'w')
  86.         self.f.write(self.separator.join(headers) + '\n')
  87.         self.f.close()
  88.  
  89.     def PrintAndLog(self, formats, parameters, short=False):
  90.         line = self.separator.join(formats) % parameters
  91.         if short == True:
  92.             result = line.split(';')
  93.             if result[2] == 1:
  94.                 print result[0], result[4]+'/'+result[5], result[6]
  95.             else:
  96.                 print(line)
  97.         else:
  98.             print(line)
  99.         f = open(self.filename, 'a')
  100.         f.write(line + '\n')
  101.         f.close()
  102.  
  103. def VTHTTPReportRequest(searchTerm):
  104.     req = urllib2.Request(VIRUSTOTAL_REPORT_URL, urllib.urlencode({'resource': searchTerm, 'apikey': VIRUSTOTAL_API2_KEY}))
  105.     try:
  106.         if sys.hexversion >= 0x020601F0:
  107.             hRequest = urllib2.urlopen(req, timeout=15)
  108.         else:
  109.             hRequest = urllib2.urlopen(req)
  110.     except:
  111.         return None
  112.     try:
  113.         data = hRequest.read()
  114.     except:
  115.         return None
  116.     finally:
  117.         hRequest.close()
  118.     return data
  119.  
  120. def InsertIntoTuple(tupleIn, position, value):
  121.     listIn = list(tupleIn)
  122.     listIn.insert(position, value)
  123.     return tuple(listIn)
  124.  
  125. def GetReport(searchTerm, reports, withComment, forceRequest, short):
  126.     global oLogger
  127.  
  128.     if withComment:
  129.         index = searchTerm.find(' ')
  130.         if index == -1:
  131.             comment = ''
  132.         else:
  133.             comment = searchTerm[index+1:]
  134.             searchTerm = searchTerm[:index]
  135.     if not forceRequest and searchTerm in reports:
  136.         issuedRequest = False
  137.         oResult = reports[searchTerm]
  138.     else:
  139.         jsonResponse = VTHTTPReportRequest(searchTerm)
  140.         issuedRequest = True
  141.         if jsonResponse == None:
  142.             formats = ('%s', '%s')
  143.             parameters = (searchTerm, 'Error')
  144.             if withComment:
  145.                 formats = InsertIntoTuple(formats, 1, '%s')
  146.                 parameters = InsertIntoTuple(parameters, 1, comment)
  147.             oLogger.PrintAndLog(formats, parameters)
  148.             return issuedRequest
  149.         else:
  150.             oResult = simplejson.loads(jsonResponse)
  151.             if oResult['response_code'] == 1:
  152.                 reports[searchTerm] = oResult
  153.     if oResult['response_code'] == 1:
  154.         scans = []
  155.         for scan in sorted(oResult['scans']):
  156.             if oResult['scans'][scan]['detected']:
  157.                 scans.append('#'.join((scan, oResult['scans'][scan]['result'], oResult['scans'][scan]['update'], oResult['scans'][scan]['version'])))
  158.         formats = ('%s', '%d', '%d', '%s', '%d', '%d', '%s', '%s')
  159.         parameters = (searchTerm, issuedRequest, oResult['response_code'], oResult['scan_date'], oResult['positives'], oResult['total'], oResult['permalink'], ','.join(scans))
  160.         if withComment:
  161.             formats = InsertIntoTuple(formats, 1, '%s')
  162.             parameters = InsertIntoTuple(parameters, 1, comment)
  163.         oLogger.PrintAndLog(formats, parameters, short)
  164.     else:
  165.         formats = ('%s', '%d', '%d', '%s')
  166.         parameters = (searchTerm, issuedRequest, oResult['response_code'], oResult['verbose_msg'])
  167.         if withComment:
  168.             formats = InsertIntoTuple(formats, 1, '%s')
  169.             parameters = InsertIntoTuple(parameters, 1, comment)
  170.         oLogger.PrintAndLog(formats, parameters, short)
  171.     return issuedRequest
  172.  
  173. def File2Strings(filename):
  174.     try:
  175.         f = open(filename, 'r')
  176.     except:
  177.         return None
  178.     try:
  179.         return map(lambda line:line.rstrip('\n'), f.readlines())
  180.     except:
  181.         return None
  182.     finally:
  183.         f.close()
  184.  
  185. def VirusTotalSearch(filename, options):
  186.     global oLogger
  187.  
  188.     if options.genhash: #if command executed with the -g or --genhash flag.
  189.         searchTerms = genhash(filename)
  190.         if searchTerms == None:
  191.             print('Error reading file %s' % filename)
  192.             return
  193.     else:
  194.         searchTerms = File2Strings(filename)
  195.         if searchTerms == None:
  196.             print('Error reading file %s' % filename)
  197.             return
  198.         elif searchTerms == []:
  199.             print('No searchterms in file %s' % filename)
  200.             return
  201.  
  202.     headers = ('Search Term', 'Requested', 'Response', 'Scan Date', 'Detections', 'Total', 'Permalink', 'AVs')
  203.     if options.comment:
  204.         headers = InsertIntoTuple(headers, 1, 'Comment')
  205.     oLogger = CSVLogger('virustotal-search', headers)
  206.  
  207.     data = DeSerialize()
  208.     if data == None:
  209.         reports = {}
  210.     else:
  211.         reports = data['reports']
  212.  
  213.     while searchTerms != []:
  214.         issuedRequest = GetReport(searchTerms[0], reports, options.comment, options.force, options.short)
  215.         searchTerms = searchTerms[1:]
  216.         if issuedRequest and searchTerms != []:
  217.             time.sleep(options.delay)
  218.     Serialize({'reports': reports})
  219.  
  220. def genhash(malfile):
  221.     hash = None
  222.     try:
  223.         hash = []
  224.         f = open(malfile,'rb')
  225.         m = hashlib.md5()
  226.         while True:
  227.             data = f.read(10240)
  228.             if len(data) == 0:
  229.                 break
  230.             m.update(data)
  231.         hash.append(m.hexdigest())
  232.     except:
  233.         None
  234.     return hash
  235.  
  236. def Main():
  237.     global VIRUSTOTAL_API2_KEY
  238.  
  239.     oParser = optparse.OptionParser(usage='usage: %prog [options] file\n' + __description__, version='%prog ' + __version__)
  240.     oParser.add_option('-d', '--delay', type=int, default=16, help='delay in seconds between queries (default 16s, VT rate limit is 4 queries per minute)')
  241.     oParser.add_option('-c', '--comment', action='store_true', default=False, help='the search term is followed by a comment and separated by a space character')
  242.     oParser.add_option('-f', '--force', action='store_true', default=False, help='force all request to be send to VirusTotal, even if found in local database (pkl file)')
  243.     oParser.add_option('-g', '--genhash', action='store_true', default=False, help='Generate (md5) hash from file passed as argument.')
  244.     oParser.add_option('-s', '--short', action='store_true', default=False, help='Shorten output, return: hash, score, date and url.')
  245.     oParser.add_option('-k', '--key', default='', help='VirusTotal API key')
  246.     (options, args) = oParser.parse_args()
  247.  
  248.     if len(args) != 1:
  249.         oParser.print_help()
  250.         print('')
  251.         print('  Source code put in the public domain by Didier Stevens, no Copyright')
  252.         print('  Use at your own risk')
  253.         print('  https://DidierStevens.com')
  254.         return
  255.     if os.getenv('VIRUSTOTAL_API2_KEY') != None:
  256.         VIRUSTOTAL_API2_KEY = os.getenv('VIRUSTOTAL_API2_KEY')
  257.     if options.key != '':
  258.         VIRUSTOTAL_API2_KEY = options.key
  259.     if VIRUSTOTAL_API2_KEY == '':
  260.         print('You need to get a VirusTotal API key and set environment variable VIRUSTOTAL_API2_KEY, use option -k or add it to this program.\nTo get your API key, you need a VirusTotal account.')
  261.     else:
  262.         VirusTotalSearch(args[0], options)
  263.  
  264. if __name__ == '__main__':
  265.     Main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement