From 521af786df9b5453959021ea4e1cc55a4d46284e Mon Sep 17 00:00:00 2001 From: Dextroz <25749668+Dextroz@users.noreply.github.com> Date: Mon, 15 Apr 2019 20:20:33 +0100 Subject: [PATCH] Dev - Ease of use release - 0.0.2 (#3) * Updated README.md with new usage examples. * Added new examples for changes to virustotal.py * Bumped version. Changes to address issue #2 * Added Changelog. * Bumped version. Added keywords. --- README.md | 80 +++++++++++++++++++++++++-------- setup.py | 7 +-- virustotal_python/examples.py | 68 +++++++++++++++++++++------- virustotal_python/virustotal.py | 28 ++++++------ 4 files changed, 133 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 11c54ef..3f6a102 100644 --- a/README.md +++ b/README.md @@ -25,33 +25,66 @@ Or ## Example Usage ```python -from virustotal_python import Virustotal +from virustotal import Virustotal from pprint import pprint + vtotal = Virustotal("Insert API Key Here.") # NOTE: Check virustotal.py for docstrings containing full parameter descriptions. # Send a file to Virustotal for analysis. -resp = vtotal.file_scan("./test.py") # PATH to file for querying. +resp = vtotal.file_scan("./test.py") # PATH to file for querying. # Resend a file to Virustotal for analysis. -# Contains the resource (SHA256) HASH of the file above. -resp = vtotal.file_rescan("75efd85cf6f8a962fe016787a7f57206ea9263086ee496fc62e3fc56734d4b53") -# Also accepts a CSV list (MAX 25 items) -resp = vtotal.file_rescan("HASH,HASH,HASH,HASH,etc.") - -# Retrieve scan report(s) for a given file from Virustotal. -resp = vtotal.file_report("75efd85cf6f8a962fe016787a7f57206ea9263086ee496fc62e3fc56734d4b53") -# Or accepts a CSV list with a combination of scan_ids and HASHs. -resp = vtotal.file_report("scan_id,HASH,scan_id,HASH") +# A list containing the resource (SHA256) HASH of the file above. +resp = vtotal.file_rescan( + ["75efd85cf6f8a962fe016787a7f57206ea9263086ee496fc62e3fc56734d4b53"] +) +# A list containing md5/sha1/sha256 hashes. Can be a combination of any of the three allowed hashes (MAX 25 items). +# NOTE: The second hash here is flagged as malicious by multiple engines. +resp = vtotal.file_rescan( + [ + "75efd85cf6f8a962fe016787a7f57206ea9263086ee496fc62e3fc56734d4b53", + "9f101483662fc071b7c10f81c64bb34491ca4a877191d464ff46fd94c7247115", + ] +) + +# Retrieve scan report(s) for given file(s) from Virustotal. +# A list containing the resource (SHA256) HASH of a known malicious file. +resp = vtotal.file_report( + ["9f101483662fc071b7c10f81c64bb34491ca4a877191d464ff46fd94c7247115"] +) +# A list of resource(s). Can be `md5/sha1/sha256 hashes` and/or combination of hashes and scan_ids (MAX 4 per standard request rate). +# The first is a scan_id, the second is a SHA256 HASH. +resp = vtotal.file_report( + [ + "75efd85cf6f8a962fe016787a7f57206ea9263086ee496fc62e3fc56734d4b53-1555351539", + "9f101483662fc071b7c10f81c64bb34491ca4a877191d464ff46fd94c7247115", + ] +) # Query url(s) to VirusTotal. -resp = vtotal.url_scan("ihaveaproblem.info") # Query a single url. -resp = vtotal.url_scan("ihaveaproblem.info\ngoogle.com\nwikipedia.com\ngithub.com") # Query multiple url(s) seperated by "\n" character. - -# Retrieve report(s) -resp = vtotal.url_report("ihaveaproblem.info") # Query a single url. -resp = vtotal.url_report("ihaveaproblem.info\ngoogle.com\nwikipedia.com\ngithub.com", scan="1") # Get the report(s) for a url(s), scan_id(s). +# A list containing a url to be scanned by VirusTotal. +resp = vtotal.url_scan(["ihaveaproblem.info"]) # Query a single url. +# A list of url(s) to be scanned by VirusTotal (MAX 4 per standard request rate). +resp = vtotal.url_scan( + ["ihaveaproblem.info", "google.com", "wikipedia.com", "github.com"] +) + +# Retrieve url report(s) +# A list containing the url of the report to be retrieved. +resp = vtotal.url_report(["ihaveaproblem.info"]) # Query a single url. +# A list of the url(s) and/or scan_id(s) report(s) to be retrieved (MAX 4 per standard request rate). +# The first object in the list is a scan_id. +resp = vtotal.url_report( + [ + "fd21590d9df715452c8c000e1b5aa909c7c5ea434c2ddcad3f4ccfe9b0ee224e-1555352750", + "google.com", + "wikipedia.com", + "github.com", + ], + scan="1", +) # Query an IP to Virustotal. resp = vtotal.ipaddress_report("90.156.201.27") @@ -60,7 +93,12 @@ resp = vtotal.ipaddress_report("90.156.201.27") resp = vtotal.domain_report("027.ru") # Put a comment onto a specific resource. -resp = vtotal.put_comment("ihaveaproblem.info", comment="This website is flagged by a few scanners as malicious! #watchout") +resp = vtotal.put_comment( + "9f101483662fc071b7c10f81c64bb34491ca4a877191d464ff46fd94c7247115", + comment="#watchout, this looks very malicious!", +) + +pprint(resp) ``` ```python @@ -79,6 +117,12 @@ pprint(resp) 'status_code': 200} ``` +## Changelog + +* 0.0.2 - Changes to file_rescan(), file_report(), url_scan(), url_report() to improve ease of use of the wrapper. See issue [#2](https://github.com/Dextroz/virustotal-python/issues/2). Examples updated for changes. + +* 0.0.1 - Inital release of virustotal-python. Covered all endpoints of the Virustotal public API. + ## Authors -- Contributors * **Dextroz** - *Author* - [Dextroz](https://github.com/Dextroz) diff --git a/setup.py b/setup.py index 948ff35..38892ec 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setup( name="virustotal-python", - version="0.0.1", + version="0.0.2", author="Dextroz", author_email="dextrozmlg@gmail.com", description="A light wrapper around the public VirusTotal API.", @@ -16,6 +16,7 @@ classifiers=[ "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.7" + "Programming Language :: Python :: 3.7", ], -) \ No newline at end of file + keywords="Light VirusTotal Wrapper Public API", +) diff --git a/virustotal_python/examples.py b/virustotal_python/examples.py index 586a0a2..d0adb11 100644 --- a/virustotal_python/examples.py +++ b/virustotal_python/examples.py @@ -1,30 +1,63 @@ from virustotal import Virustotal from pprint import pprint + vtotal = Virustotal("Insert API Key Here.") # NOTE: Check virustotal.py for docstrings containing full parameter descriptions. # Send a file to Virustotal for analysis. -resp = vtotal.file_scan("./test.py") # PATH to file for querying. +resp = vtotal.file_scan("./test.py") # PATH to file for querying. # Resend a file to Virustotal for analysis. -# Contains the resource (SHA256) HASH of the file above. -resp = vtotal.file_rescan("75efd85cf6f8a962fe016787a7f57206ea9263086ee496fc62e3fc56734d4b53") -# Also accepts a CSV list (MAX 25 items) -resp = vtotal.file_rescan("HASH,HASH,HASH,HASH,etc.") +# A list containing the resource (SHA256) HASH of the file above. +resp = vtotal.file_rescan( + ["75efd85cf6f8a962fe016787a7f57206ea9263086ee496fc62e3fc56734d4b53"] +) +# A list containing md5/sha1/sha256 hashes. Can be a combination of any of the three allowed hashes (MAX 25 items). +# NOTE: The second hash here is flagged as malicious by multiple engines. +resp = vtotal.file_rescan( + [ + "75efd85cf6f8a962fe016787a7f57206ea9263086ee496fc62e3fc56734d4b53", + "9f101483662fc071b7c10f81c64bb34491ca4a877191d464ff46fd94c7247115", + ] +) -# Retrieve scan report(s) for a given file from Virustotal. -resp = vtotal.file_report("75efd85cf6f8a962fe016787a7f57206ea9263086ee496fc62e3fc56734d4b53") -# Or accepts a CSV list with a combination of scan_ids and HASHs. -resp = vtotal.file_report("scan_id,HASH,scan_id,HASH") +# Retrieve scan report(s) for given file(s) from Virustotal. +# A list containing the resource (SHA256) HASH of a known malicious file. +resp = vtotal.file_report( + ["9f101483662fc071b7c10f81c64bb34491ca4a877191d464ff46fd94c7247115"] +) +# A list of resource(s). Can be `md5/sha1/sha256 hashes` and/or combination of hashes and scan_ids (MAX 4 per standard request rate). +# The first is a scan_id, the second is a SHA256 HASH. +resp = vtotal.file_report( + [ + "75efd85cf6f8a962fe016787a7f57206ea9263086ee496fc62e3fc56734d4b53-1555351539", + "9f101483662fc071b7c10f81c64bb34491ca4a877191d464ff46fd94c7247115", + ] +) # Query url(s) to VirusTotal. -resp = vtotal.url_scan("ihaveaproblem.info") # Query a single url. -resp = vtotal.url_scan("ihaveaproblem.info\ngoogle.com\nwikipedia.com\ngithub.com") # Query multiple url(s) seperated by "\n" character. +# A list containing a url to be scanned by VirusTotal. +resp = vtotal.url_scan(["ihaveaproblem.info"]) # Query a single url. +# A list of url(s) to be scanned by VirusTotal (MAX 4 per standard request rate). +resp = vtotal.url_scan( + ["ihaveaproblem.info", "google.com", "wikipedia.com", "github.com"] +) -# Retrieve report(s) -resp = vtotal.url_report("ihaveaproblem.info") # Query a single url. -resp = vtotal.url_report("ihaveaproblem.info\ngoogle.com\nwikipedia.com\ngithub.com", scan="1") # Get the report(s) for a url(s), scan_id(s). +# Retrieve url report(s) +# A list containing the url of the report to be retrieved. +resp = vtotal.url_report(["ihaveaproblem.info"]) # Query a single url. +# A list of the url(s) and/or scan_id(s) report(s) to be retrieved (MAX 4 per standard request rate). +# The first object in the list is a scan_id. +resp = vtotal.url_report( + [ + "fd21590d9df715452c8c000e1b5aa909c7c5ea434c2ddcad3f4ccfe9b0ee224e-1555352750", + "google.com", + "wikipedia.com", + "github.com", + ], + scan="1", +) # Query an IP to Virustotal. resp = vtotal.ipaddress_report("90.156.201.27") @@ -33,4 +66,9 @@ resp = vtotal.domain_report("027.ru") # Put a comment onto a specific resource. -resp = vtotal.put_comment("ihaveaproblem.info", comment="This website is flagged by a few scanners as malicious! #watchout") \ No newline at end of file +resp = vtotal.put_comment( + "9f101483662fc071b7c10f81c64bb34491ca4a877191d464ff46fd94c7247115", + comment="#watchout, this looks very malicious!", +) + +pprint(resp) diff --git a/virustotal_python/virustotal.py b/virustotal_python/virustotal.py index 5e9acd9..d38c44c 100644 --- a/virustotal_python/virustotal.py +++ b/virustotal_python/virustotal.py @@ -34,7 +34,7 @@ class Virustotal(object): def __init__(self, API_KEY=None): self.API_KEY = API_KEY self.BASEURL = "https://www.virustotal.com/vtapi/v2/" - self.VERSION = "0.0.1" + self.VERSION = "0.0.2" self.headers = { "Accept-Encoding": "gzip, deflate", "User-Agent": f"gzip, virustotal-python {self.VERSION}", @@ -55,46 +55,46 @@ def file_scan(self, file): resp = self.make_request(f"{self.BASEURL}file/scan", params=params, files=files) return resp - def file_rescan(self, resource): + def file_rescan(self, *resource: list): """ Resend a file to Virustotal for analysis. (https://www.virustotal.com/en/documentation/public-api/#rescanning-files) - :param resource: The resource of the specified file. Can be an `md5/sha1/sha256 hash` or CSV list made up of a combination of any of the three allowed hashes (MAX 25 items). + :param *resource: A list of resource(s) of a specified file(s). Can be `md5/sha1/sha256 hashes`. Can be a combination of any of the three allowed hashes (MAX 25 items). :rtype: A dictionary containing the resp_code and JSON response. """ - params = {"apikey": self.API_KEY, "resource": resource} + params = {"apikey": self.API_KEY, "resource": ",".join(*resource)} resp = self.make_request(f"{self.BASEURL}file/rescan", params=params) return resp - def file_report(self, resource): + def file_report(self, *resource: list): """ Retrieve scan report(s) for a given file from Virustotal. (https://www.virustotal.com/en/documentation/public-api/#getting-file-scans) - :param resource: The `md5/sha1/sha256 hash` of the file or CSV list made up of a combination of hashes and scan_ids (MAX 4 items). + :param *resource: A list of resource(s) of a specified file(s). Can be `md5/sha1/sha256 hashes` and/or combination of hashes and scan_ids (MAX 4 per standard request rate). :rtype: A dictionary containing the resp_code and JSON response. """ - params = {"apikey": self.API_KEY, "resource": resource} + params = {"apikey": self.API_KEY, "resource": ",".join(*resource)} resp = self.make_request( f"{self.BASEURL}file/report", params=params, method="GET" ) return resp - def url_scan(self, url): + def url_scan(self, *url: list): """ Send url(s) to Virustotal. (https://www.virustotal.com/en/documentation/public-api/#scanning-urls) - :param url: The url(s) to be scanned. Also accepts a list of urls (MAX 4); urls must be separated by a new line character. + :param *url: A list of url(s) to be scanned. (MAX 4 per standard request rate). :rtype: A dictionary containing the resp_code and JSON response. """ - params = {"apikey": self.API_KEY, "url": url} + params = {"apikey": self.API_KEY, "url": "\n".join(*url)} resp = self.make_request(f"{self.BASEURL}url/scan", params=params) return resp - def url_report(self, resource, scan=None): + def url_report(self, *resource: list, scan=None): """ Retrieve scan report(s) for a given url(s) (https://www.virustotal.com/en/documentation/public-api/#getting-url-scans) - :param resource: The url(s) of the given report to be retrieved or scan_id or a CSV list made up of scan_ids or urls (MAX 4); the scan_ids or urls `must` be separated by a new line character. - :param scan: An optional parameter. When set to "1" will automatically submit the URL for analysis if no report is found for it in VirusTotal's database. + :param *resource: A list of the url(s) and/or scan_id(s) report(s) to be retrieved (MAX 4 per standard request rate). + :param scan: An optional parameter. When set to "1" it will automatically submit the URL for analysis if no report is found for it in VirusTotal's database. :rtype: A dictionary containing the resp_code and JSON response. """ - params = {"apikey": self.API_KEY, "resource": resource} + params = {"apikey": self.API_KEY, "resource": "\n".join(*resource)} if scan is not None: params["scan"] = scan resp = self.make_request(f"{self.BASEURL}url/report", params=params)