1+ import sys
2+ import requests
3+ import base64
4+ import json
5+ from prettytable import PrettyTable
6+ import sys
7+ from termcolor import colored
8+ import os
9+
10+
11+ log_output = ""
12+
13+ def argv_error ():
14+ print ("./script [option] [value] ..." )
15+ print ("-p\t \t Use this argoument for set your PDF path\n or --path\n " )
16+ print ("-A\t \t Use this argoument for set your VirusTotal API Key\n or --API-Key\n " )
17+ print ("-v\t \t Use this argoument for view a lot more information\n or --verbose\n " )
18+ print ("-l\t \t Use this argoument for save in a log file all verbose information\n or --log\n " )
19+ print ("Examples:" )
20+ print ("$ python3 script.py -p <PDF_DOCUMENT_PATH> -A <VirusTotal_API_Key>" )
21+ print ("\t Generic example" )
22+ print ("$ python3 script.py -p malicious.pdf -A abcdefg123456789876543234567899876543456789876543456789876543 --verbose" )
23+ print ("\t It will print everything in output" )
24+ print ("$ python3 script.py -p malicious.pdf -A abcdefg123456789876543234567899876543456789876543456789876543 --log" )
25+ print ("\t It will print everything in a log file in the same directory where is the script PDF_Parser.py" )
26+
27+ def generic_error (error : str ) -> None :
28+ print ("\n Something went wrong... check your private key and your pdf path :-/" )
29+ print (f"\n { error } " )
30+
31+ """
32+ {
33+ "data": {
34+ "type": "analysis",
35+ "id": "<base64_file_id>"
36+ }
37+ }
38+ """
39+ def upload_file (File_Path : str , VirusTotal_API_Key : str , verbose : bool ) -> str :
40+
41+ url = "https://www.virustotal.com/api/v3/files"
42+
43+ files = {"file" : (File_Path , open (File_Path , "rb" ), "application/pdf" )}
44+ headers = {
45+ "accept" : "application/json" ,
46+ "x-apikey" : VirusTotal_API_Key
47+ }
48+
49+ response = requests .post (url , files = files , headers = headers )
50+
51+ if response .status_code == 200 :
52+ global log_output
53+ if verbose :
54+ print (response .text )
55+ if log_output != "" :
56+ log_output += "\n " + response .text
57+
58+ return response .text
59+ else :
60+ generic_error (f"[*] Error occurred in upload_file function.\n Error code: { response .status_code } " )
61+ return "-1"
62+
63+ """
64+ Load json response as a dict
65+ """
66+ def json_load (json_in_string : str ):
67+ return json .loads (json_in_string )
68+
69+ """
70+ Get data -> id from VirusTotal response
71+ """
72+ def get_base64_file_id_from_response (response : str ) -> str :
73+ response_in_dict = json_load (response )
74+ return response_in_dict ["data" ]["id" ]
75+
76+ """
77+ Decrypt from base64
78+ """
79+ def decrypt_from_base64 (encrypted_string : str ) -> str :
80+ return base64 .b64decode (encrypted_string ).decode ('ascii' )
81+
82+
83+ """
84+ For check the file you must pass as parameters:
85+ - MD5 of a file uploaded
86+ - Your VirusTotal private Key
87+ """
88+ def check_file (FileMD5 : str , VirusTotal_API_Key : str ) -> str :
89+
90+ url = f"https://www.virustotal.com/api/v3/files/{ FileMD5 } "
91+
92+ headers = {
93+ "accept" : "application/json" ,
94+ "x-apikey" : VirusTotal_API_Key
95+ }
96+
97+ response = requests .get (url , headers = headers )
98+
99+ if response .status_code == 200 :
100+ return response .text
101+ else :
102+ generic_error (f"[*] Error occurred in check_file function.\n Error code: { response .status_code } " )
103+ return "-1"
104+
105+ """
106+ Parserize the response
107+ """
108+ def response_parser (response : str , verbose : bool ):
109+ response_in_dict = json_load (response )
110+ antivirus_supported = response_in_dict ["data" ]["attributes" ]["last_analysis_results" ]
111+
112+ malicious = 0
113+ global log_output
114+
115+
116+ cve = {}
117+ for antivirus in antivirus_supported :
118+ if response_in_dict ["data" ]["attributes" ]["last_analysis_results" ][f"{ antivirus } " ]["category" ] == "malicious" :
119+ malicious += 1
120+ cve [f"{ antivirus } " ] = response_in_dict ["data" ]["attributes" ]["last_analysis_results" ][f"{ antivirus } " ]["result" ]
121+
122+ table = ["Result" , "CVE" ]
123+ tab = PrettyTable (table )
124+
125+ for antivirus in cve .keys ():
126+ tab .add_row ([f"{ antivirus } " , f"{ cve [antivirus ]} " ])
127+
128+ if verbose :
129+ print (tab )
130+
131+ if log_output != "" :
132+ log_output += "\n " + str (tab )
133+
134+ else :
135+ for antivirus in antivirus_supported :
136+ if response_in_dict ["data" ]["attributes" ]["last_analysis_results" ][f"{ antivirus } " ]["category" ] == "malicious" :
137+ malicious += 1
138+
139+ print_string = ""
140+ color = ""
141+ if malicious > 2 :
142+ print_string = 'This document is most likely malicious!!!'
143+ color = "red"
144+ elif malicious == 1 :
145+ print_string = "A malicious control has been detected but it could be a false positive."
146+ color = "yellow"
147+ else :
148+ print_string = "This file is safe. :-)"
149+ color = "yellow"
150+
151+ print (colored (f'\n { print_string } ' , color , attrs = ['reverse' , 'blink' ]))
152+
153+ if log_output != "" :
154+ log_output += "\n " + print_string
155+
156+ if __name__ == "__main__" :
157+
158+ File_Path = ""
159+ VirusTotal_API_Key = ""
160+ verbose = False
161+ log = False
162+
163+ for i in range (1 , len (sys .argv )):
164+ if ((sys .argv [i ] == "-p" or sys .argv [i ] == "--path" ) and (len (sys .argv ) > i + 1 )):
165+ File_Path = sys .argv [i + 1 ]
166+ elif ((sys .argv [i ] == "-A" or sys .argv [i ] == "--API-Key" ) and (len (sys .argv ) > i + 1 )):
167+ VirusTotal_API_Key = sys .argv [i + 1 ]
168+ elif ((sys .argv [i ] == "-v" or sys .argv [i ] == "--verbose" )):
169+ verbose = True
170+ elif ((sys .argv [i ] == "-l" or sys .argv [i ] == "--log" )):
171+ log = True
172+ elif ((sys .argv [i ] == "-h" or sys .argv [i ] == "--help" )):
173+ argv_error ()
174+ exit ()
175+
176+ if File_Path != "" and VirusTotal_API_Key != "" :
177+ init_print = f"Your File: { File_Path } \n Your API: { VirusTotal_API_Key [:5 ]} ***"
178+ if verbose :
179+ print (init_print )
180+ if log :
181+ log_output += "\n " + init_print
182+ else :
183+ argv_error ()
184+ exit ()
185+
186+ response = upload_file (File_Path , VirusTotal_API_Key , verbose )
187+
188+ if response == "-1" :
189+ exit ()
190+
191+ encrypted_FileMD5 = get_base64_file_id_from_response (response )
192+
193+ plaintext_FileMD5 = decrypt_from_base64 (encrypted_FileMD5 )
194+
195+ FileMD5 = plaintext_FileMD5 .split (":" )[0 ]
196+ MD5_print = f"MD5: { FileMD5 } "
197+ if verbose :
198+ print (MD5_print )
199+ if log :
200+ log_output += "\n " + MD5_print
201+
202+ VirusTotal_response = check_file (FileMD5 , VirusTotal_API_Key )
203+
204+ if VirusTotal_response == "-1" :
205+ exit ()
206+
207+ response_parser (VirusTotal_response , verbose )
208+
209+ f = open ("PDF_Parser.log" , "w" )
210+ f .write (log_output )
211+ f .close ()
0 commit comments