public static VirusTotalUrlResponse ConvertUrlResponse(byte[] response_bytes) { string response_string = Encoding.ASCII.GetString(response_bytes); VirusTotalUrlResponse vtru = JsonConvert.DeserializeObject <VirusTotalUrlResponse>(response_string); return(vtru); }
// ┌────────────────────────────────────────────────────────────┐ // │ Main Method │ // └────────────────────────────────────────────────────────────┘ // Upon execution, main function reads/checks the first CLI arg to see if it is a valid action string; if so, it verifies the other CLI args are present for the relevant action then calls the VirusTotal API // TO DO: There may be some redundancy in the various switch branches below with checking args; we can probably simplify this. static void Main(string[] args) { if (args.Length == 0) { Console.WriteLine("LogRhythm VirusTotal Query\r\n\r\nAvailable queries:\r\n\r\nScan File\r\nScan URL\r\n\r\nSyntax:\r\n\r\nlrvt.exe --scan-file [FILE_NAME] [VIRUSTOTAL_API_KEY]\r\nlrvt.exe --scan-url [URL] [VIRUSTOTAL_API_KEY]"); } else { switch (args[0]) { case "--scan-url": if (args.Length == 1) { Console.WriteLine("No URL specified and no VirusTotal API key specified!\r\n\r\nSyntax:\r\n\r\nlrvt.exe --scan-url [URL] [VIRUSTOTAL_API_KEY]\r\n"); break; } else { if (args.Length != 3) { Console.WriteLine("No VirusTotal API key specified!\r\n\r\nSyntax:\r\n\r\nlrvt.exe --scan-url [URL] [VIRUSTOTAL_API_KEY]\r\n"); break; } else { try { byte[] url_resp_bytes = VtScanUrl(args[1], "application/x-www-form-urlencoded", vt_scanurl_uri, args[2]); VirusTotalUrlResponse vt_urlsub_resp = ConvertUrlResponse(url_resp_bytes); if (vt_urlsub_resp.response_code != 1) { Console.WriteLine("Error submitting URL to VirusTotal!\r\n\r\nError Information:\r\n{0}", vt_urlsub_resp.verbose_msg); break; } else { bool has_ret_resp = false; int retry_count = 0; bool resp_check = false; System.Threading.Thread.Sleep(15000); while (has_ret_resp == false && retry_count < 8) { byte[] url_report_bytes = VtGetReport(vt_urlsub_resp.resource, vt_reporturl_uri, args[2]); if (url_report_bytes != null && url_report_bytes.Length != 0) { // ***API TROUBLESHOOTING/DEBUG HELPER OPTION*** Output each response check to stdout. (Uncomment the following 2 lines) //Console.WriteLine(Encoding.ASCII.GetString(url_report_bytes)); //Console.WriteLine(); resp_check = CheckResponseStatus(url_report_bytes); } if (resp_check == true) { has_ret_resp = true; OutputUrlReport(url_report_bytes); return; } else { System.Threading.Thread.Sleep(30000); retry_count++; } } Console.WriteLine("Query took longer than 120 seconds to respond! Please check the scan's permalink, available at:\r\n{0}", vt_urlsub_resp.permalink); break; } } catch (Exception u) { Console.WriteLine("Error submitting URL to VirusTotal!\r\n\r\nError Information:\r\n{0}", u.Message); break; } } } case "--scan-file": if (args.Length == 1) { Console.WriteLine("No file name specified and no VirusTotal API key specified!\r\n\r\nSyntax:\r\n\r\nlrvt.exe --scan-file [FILE_NAME] [VIRUSTOTAL_API_KEY]\r\n"); break; } else { if (args.Length != 3) { Console.WriteLine("No VirusTotal API key specified!\r\n\r\nSyntax:\r\n\r\nlrvt.exe --scan-file [FILE_NAME] [VIRUSTOTAL_API_KEY]\r\n"); break; } else { if (File.Exists(args[1]) == false) { Console.WriteLine("File \"{0}\" not found!\r\nPlease verify file name is valid; if file name contains spaces, try wrapping the name in double-quotes.", args[1]); break; } else { try { byte[] file_bytes = File.ReadAllBytes(args[1]); byte[] file_resp_bytes = VtUploadFile(file_bytes, Path.GetFileName(args[1]), "application/octet-stream", vt_filescan_uri, args[2]); VirusTotalResponse vt_filesub_resp = ConvertResponse(file_resp_bytes); if (vt_filesub_resp.response_code != 1) { Console.WriteLine("Error submitting file to VirusTotal!\r\n\r\nError Information:\r\n{0}", vt_filesub_resp.verbose_msg); break; } else { bool has_ret_resp = false; int retry_count = 0; System.Threading.Thread.Sleep(20000); while (has_ret_resp == false && retry_count < 8) { //System.Threading.Thread.Sleep(30000); bool resp_check = false; byte[] file_chk_bytes = VtGetReport(vt_filesub_resp.resource, vt_report_uri, args[2]); if (file_chk_bytes != null && file_chk_bytes.Length != 0) { // ***API TROUBLESHOOTING/DEBUG HELPER OPTION*** Output each response check to stdout. (Uncomment the following 2 lines) //Console.WriteLine(Encoding.ASCII.GetString(file_chk_bytes)); //Console.WriteLine(); resp_check = CheckResponseStatus(file_chk_bytes); } if (resp_check == true) { has_ret_resp = true; OutputFileReport(file_chk_bytes, Path.GetFileName(args[1])); return; } else { System.Threading.Thread.Sleep(30000); retry_count++; } } Console.WriteLine("Query took longer than 240 seconds to respond! Please check the scan's permalink, available at:\r\n{0}", vt_filesub_resp.permalink); break; } } catch (Exception f) { Console.WriteLine("Error submitting file to VirusTotal!\r\n\r\nError Information:\r\n{0}", f.Message); break; } } } } default: if (args[0] == "--scan-file" || args[0] == "--scan-url") { Console.WriteLine("Missing argument(s) in command! Available actions: Scan File or Scan URL\r\n\r\nSyntax:\r\n\r\nlrvt.exe --scan-file [FILE_NAME] [VIRUSTOTAL_API_KEY]\r\nlrvt.exe --scan-url [URL] [VIRUSTOTAL_API_KEY]"); } else { Console.WriteLine("Invalid (or no) action specified! Available actions: Scan File or Scan URL\r\n\r\nSyntax:\r\n\r\nlrvt.exe --scan-file [FILE_NAME] [VIRUSTOTAL_API_KEY]\r\nlrvt.exe --scan-url [URL] [VIRUSTOTAL_API_KEY]"); } break; } return; } }