modules.processing.irma

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