Skip to content

Instantly share code, notes, and snippets.

@tomer
Last active December 23, 2019 16:44
Show Gist options
  • Save tomer/d548006a6b2c14bfdbb7cbb16398b1d8 to your computer and use it in GitHub Desktop.
Save tomer/d548006a6b2c14bfdbb7cbb16398b1d8 to your computer and use it in GitHub Desktop.
Upload file to Virus Total servers and reterive scan report

Installation

  • Use pipenv or make sure to have the python requests library available.
  • Make sure to have valid API key by creating a developer account on virustotal website and then accessing your profile for API keys.

Usage

usage: virustotal_api_check_file.py [-h] --key KEY filename

positional arguments:
  filename    File to scan

optional arguments:
  -h, --help  show this help message and exit
  --key KEY   API Key

Tested scenarios

  • Random files should be clean. Generate random file from the command line: head /dev/random > randomFile
  • eicar test file (known positive detection)
    • echo 'X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*' > badFile
    • echo $(head /dev/random) 'X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*' > randomBadFile
  • As the engine doesn't re-check existing files by its md5/sha1 signatures, the code most handle cases when the checks takes longer than with files previously uploaded. (Note the rate limit of 4 requests/minute)
$ echo 'X5O@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*' > badFile    
$ python virustotal_api.py --key my.api.key.goes.here badFile
Scanned file: badFile2
Positives: 1
['SUPERAntiSpyware']
$ echo $(head /dev/random) 'X5O@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*' > randomBadFile
$ python virustotal_api.py --key my.api.key.goes.here randomBadFile
Scanned file: randomBadFile
Positives: 3
['Ikarus', 'MaxSecure', 'Qihoo-360']
$ head /dev/random > randomFile
$ python virustotal_api.py --key my.api.key.goes.here randomFile
Scanned file: randomFile
Positives: 0
[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"
[packages]
requests = "*"
[dev-packages]
[requires]
python_version = "3.7"
{
"folders": [
{
"path": "."
}
]
}
#!/usr/bin/env python
import sys
import argparse
import requests
from time import sleep
from pprint import pprint
class VirusTotal_API:
def __init__(self, apiKey):
self.apiKey = apiKey
def uploadFile(self, fileName):
''' upload file to virustotal online scanner, and receive its response message'''
# https://developers.virustotal.com/reference#file-scan
url = 'https://www.virustotal.com/vtapi/v2/file/scan'
files = {'file': open(fileName, 'rb')}
# r = requests.post(url, files=files)
params = {'apikey': self.apiKey}
r = requests.post(url, data=params, files=files)
r.raise_for_status()
if r.headers['Content-Type'] == 'application/json':
return r.json()['resource']
else:
raise Exception('Unable to locate result')
def retrieveReport(self, resourceId):
''' retrieve report of an existing resource on the virustotal server '''
# https://developers.virustotal.com/reference#url-report
url = 'https://www.virustotal.com/vtapi/v2/file/report'
params = {'apikey': self.apiKey, 'resource': resourceId}
while True:
r = requests.get(url, params=params)
r.raise_for_status()
if r.headers['Content-Type'] == 'application/json':
if r.json()['response_code'] == 1:
break
else:
delay = 25
sleep(delay)
else:
raise Exception('Invalid content type')
report = r.json()
self.report = report
positives = []
for engine, result in report['scans'].items():
if result['detected'] == True:
positives.append(engine)
return positives
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--key', help='API Key', type=str, required=True)
parser.add_argument('filename', help='File to scan')
args = parser.parse_args()
# print(f'Args: {args}')
api = VirusTotal_API(args.key)
resourceId = api.uploadFile(args.filename)
positives = api.retrieveReport(resourceId)
filename = args.filename
print(f'Scanned file: {filename}')
print(f'Positives: {len(positives)}')
if len(positives) > 0:
# print(api.report)
# print(f'WARNING: Found {positives} alerts. Please see the full report above.')
print(positives)
sys.exit(1)
else:
sys.exit(0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment