Package modules :: Package processing :: Module irma
[hide private]
[frames] | no frames]

Source Code for Module modules.processing.irma

  1  # Copyright (C) 2014-2016 Cuckoo Foundation. 
  2  # This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org 
  3  # See the file 'docs/LICENSE' for copying permission. 
  4   
  5  import logging 
  6  import time 
  7  import urlparse 
  8   
  9  try: 
 10      import requests 
 11      HAVE_REQUESTS = True 
 12   
 13      # Disable requests/urllib3 debug & info messages. 
 14      logging.getLogger("requests").setLevel(logging.WARNING) 
 15      logging.getLogger("urllib3").setLevel(logging.WARNING) 
 16  except ImportError: 
 17      HAVE_REQUESTS = False 
 18   
 19  from lib.cuckoo.common.abstracts import Processing 
 20  from lib.cuckoo.common.exceptions import CuckooOperationalError 
 21  from lib.cuckoo.common.utils import sha256_file 
 22   
 23  log = logging.getLogger(__name__) 
 24   
25 -class Irma(Processing):
26 """Gets antivirus signatures from IRMA for various results. 27 28 Currently obtains IRMA results for the target sample or URL and the 29 dropped files. 30 """ 31 # IRMA statuses https://github.com/quarkslab/irma-cli/blob/master/irma/apiclient.py 32 IRMA_FINISHED_STATUS = 50 33
34 - def _request_json(self, url, **kwargs):
35 """Wrapper around doing a request and parsing its JSON output.""" 36 try: 37 r = requests.get(url, timeout=self.timeout, **kwargs) 38 return r.json() if r.status_code == 200 else {} 39 except (requests.ConnectionError, ValueError) as e: 40 raise CuckooOperationalError( 41 "Unable to fetch IRMA results: %r" % e.message 42 )
43
44 - def _post_json(self, url, **kwargs):
45 """Wrapper around doing a post and parsing its JSON output.""" 46 try: 47 r = requests.post(url, timeout=self.timeout, **kwargs) 48 return r.json() if r.status_code == 200 else {} 49 except (requests.ConnectionError, ValueError) as e: 50 raise CuckooOperationalError( 51 "Unable to fetch IRMA results: %r" % e.message 52 )
53
54 - def _scan_file(self, filepath, force):
55 # Initialize scan in IRMA. 56 init = self._post_json(urlparse.urljoin(self.url, "/api/v1.1/scans")) 57 58 log.debug("Scanning file: %s", filepath) 59 60 # Post file for scanning. 61 files = { 62 "files": open(filepath, "rb"), 63 } 64 url = urlparse.urljoin( 65 self.url, "/api/v1.1/scans/%s/files" % init.get("id") 66 ) 67 self._post_json(url, files=files,) 68 69 # launch posted file scan 70 params = { 71 "force": force, 72 } 73 url = urlparse.urljoin( 74 self.url, "/api/v1.1/scans/%s/launch" % init.get("id") 75 ) 76 requests.post(url, json=params) 77 78 result = None 79 80 while result is None or result.get("status") != self.IRMA_FINISHED_STATUS: 81 log.debug("Polling for results for ID %s", init.get("id")) 82 url = urlparse.urljoin( 83 self.url, "/api/v1.1/scans/%s" % init.get("id") 84 ) 85 result = self._request_json(url) 86 time.sleep(1) 87 88 return
89
90 - def _get_results(self, sha256):
91 # Fetch list of scan IDs. 92 results = self._request_json( 93 urlparse.urljoin(self.url, "/api/v1.1/files/%s" % sha256) 94 ) 95 96 if not results.get("items"): 97 log.info("File %s hasn't been scanned before", sha256) 98 return 99 100 result_id = results["items"][-1]["result_id"] 101 return self._request_json( 102 urlparse.urljoin(self.url, "/api/v1.1/results/%s" % result_id) 103 )
104
105 - def run(self):
106 """Runs IRMA processing 107 @return: full IRMA report. 108 """ 109 if not HAVE_REQUESTS: 110 raise CuckooOperationalError( 111 "The IRMA processing module requires the requests " 112 "library (install with `pip install requests`)" 113 ) 114 115 self.key = "irma" 116 117 self.url = self.options.get("url") 118 self.timeout = int(self.options.get("timeout", 60)) 119 self.scan = int(self.options.get("scan", 0)) 120 self.force = int(self.options.get("force", 0)) 121 122 sha256 = sha256_file(self.file_path) 123 124 results = self._get_results(sha256) 125 126 if self.force or (not results and self.scan): 127 log.info("File scan requested: %s", sha256) 128 self._scan_file(self.file_path, self.force) 129 return self._get_results(sha256) or {} 130 131 return results
132