Lucene search

K
nmapPatrik KarlssonNMAP:HTTP-VIRUSTOTAL.NSE
HistoryApr 07, 2012 - 8:51 a.m.

http-virustotal NSE Script

2012-04-0708:51:42
Patrik Karlsson
nmap.org
206

9.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

10 High

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

COMPLETE

Integrity Impact

COMPLETE

Availability Impact

COMPLETE

AV:N/AC:L/Au:N/C:C/I:C/A:C

0.973 High

EPSS

Percentile

99.8%

Checks whether a file has been determined as malware by Virustotal. Virustotal is a service that provides the capability to scan a file or check a checksum against a number of the major antivirus vendors. The script uses the public API which requires a valid API key and has a limit on 4 queries per minute. A key can be acquired by registering as a user on the virustotal web page:

The scripts supports both sending a file to the server for analysis or checking whether a checksum (supplied as an argument or calculated from a local file) was previously discovered as malware.

As uploaded files are queued for analysis, this mode simply returns a URL where status of the queued file may be checked.

Script Arguments

http-virustotal.checksum

a SHA1, SHA256, MD5 checksum of a file to check

http-virustotal.apikey

an API key acquired from the virustotal web page

http-virustotal.upload

true if the file should be uploaded and scanned, false if a checksum should be calculated of the local file (default: false)

http-virustotal.filename

the full path of the file to checksum or upload

slaxml.debug

See the documentation for the slaxml library.

http.host, http.max-body-size, http.max-cache-size, http.max-pipeline, http.pipeline, http.truncated-ok, http.useragent

See the documentation for the http library.

smbdomain, smbhash, smbnoguest, smbpassword, smbtype, smbusername

See the documentation for the smbauth library.

Example Usage

nmap --script http-virustotal --script-args='http-virustotal.apikey="<key>",http-virustotal.checksum="275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f"'

Script Output

Pre-scan script results:
| http-virustotal:
|   Permalink: https://www.virustotal.com/file/275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f/analysis/1333633817/
|   Scan date: 2012-04-05 13:50:17
|   Positives: 41
|   digests
|     SHA1: 3395856ce81f2b7382dee72602f798b642f14140
|     SHA256: 275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f
|     MD5: 44d88612fea8a8f36de82e1278abb02f
|   Results
|     name                  result                          date      version
|     AhnLab-V3             EICAR_Test_File                 20120404  2012.04.05.00
|     AntiVir               Eicar-Test-Signature            20120405  7.11.27.24
|     Antiy-AVL             AVTEST/EICAR.ETF                20120403  2.0.3.7
|     Avast                 EICAR Test-NOT virus!!!         20120405  6.0.1289.0
|     AVG                   EICAR_Test                      20120405  10.0.0.1190
|     BitDefender           EICAR-Test-File (not a virus)   20120405  7.2
|     ByteHero              -                               20120404  1.0.0.1
|     CAT-QuickHeal         EICAR Test File                 20120405  12.00
|     ClamAV                Eicar-Test-Signature            20120405  0.97.3.0
|     Commtouch             EICAR_Test_File                 20120405  5.3.2.6
|     Comodo                Exploit.EICAR-Test-File         20120405  12000
|     DrWeb                 EICAR Test File (NOT a Virus!)  20120405  7.0.1.02210
|     Emsisoft              EICAR-ANTIVIRUS-TESTFILE!IK     20120405  5.1.0.11
|     eSafe                 EICAR Test File                 20120404  7.0.17.0
|     eTrust-Vet            the EICAR test string           20120405  37.0.9841
|     F-Prot                EICAR_Test_File                 20120405  4.6.5.141
|     F-Secure              EICAR_Test_File                 20120405  9.0.16440.0
|     Fortinet              EICAR_TEST_FILE                 20120405  4.3.392.0
|     GData                 EICAR-Test-File                 20120405  22
|     Ikarus                EICAR-ANTIVIRUS-TESTFILE        20120405  T3.1.1.118.0
|     Jiangmin              EICAR-Test-File                 20120331  13.0.900
|     K7AntiVirus           EICAR_Test_File                 20120404  9.136.6595
|     Kaspersky             EICAR-Test-File                 20120405  9.0.0.837
|     McAfee                EICAR test file                 20120405  5.400.0.1158
|     McAfee-GW-Edition     EICAR test file                 20120404  2012.1
|     Microsoft             Virus:DOS/EICAR_Test_File       20120405  1.8202
|     NOD32                 Eicar test file                 20120405  7031
|     Norman                Eicar_Test_File                 20120405  6.08.03
|     nProtect              EICAR-Test-File                 20120405  2012-04-05.01
|     Panda                 EICAR-AV-TEST-FILE              20120405  10.0.3.5
|     PCTools               Virus.DOS.EICAR_test_file       20120405  8.0.0.5
|     Rising                EICAR-Test-File                 20120405  24.04.02.03
|     Sophos                EICAR-AV-Test                   20120405  4.73.0 TP
|     SUPERAntiSpyware      NotAThreat.EICAR[TestFile]      20120402  4.40.0.1006
|     Symantec              EICAR Test String               20120405  20111.2.0.82
|     TheHacker             EICAR_Test_File                 20120405  6.7.0.1.440
|     TrendMicro            Eicar_test_file                 20120405  9.500.0.1008
|     TrendMicro-HouseCall  Eicar_test_file                 20120405  9.500.0.1008
|     VBA32                 EICAR-Test-File                 20120405  3.12.16.4
|     VIPRE                 EICAR (v)                       20120405  11755
|     ViRobot               EICAR-test                      20120405  2012.4.5.5025
|_    VirusBuster           EICAR_test_file                 20120404  14.2.11.0

Requires


local http = require "http"
local io = require "io"
local json = require "json"
local stdnse = require "stdnse"
local openssl = stdnse.silent_require "openssl"
local tab = require "tab"
local table = require "table"

description = [[
Checks whether a file has been determined as malware by Virustotal. Virustotal
is a service that provides the capability to scan a file or check a checksum
against a number of the major antivirus vendors. The script uses the public
API which requires a valid API key and has a limit on 4 queries per minute.
A key can be acquired by registering as a user on the virustotal web page:
* http://www.virustotal.com

The scripts supports both sending a file to the server for analysis or
checking whether a checksum (supplied as an argument or calculated from a
local file) was previously discovered as malware.

As uploaded files are queued for analysis, this mode simply returns a URL
where status of the queued file may be checked.
]]

---
-- @usage
-- nmap --script http-virustotal --script-args='http-virustotal.apikey="<key>",http-virustotal.checksum="275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f"'
--
-- @output
-- Pre-scan script results:
-- | http-virustotal:
-- |   Permalink: https://www.virustotal.com/file/275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f/analysis/1333633817/
-- |   Scan date: 2012-04-05 13:50:17
-- |   Positives: 41
-- |   digests
-- |     SHA1: 3395856ce81f2b7382dee72602f798b642f14140
-- |     SHA256: 275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f
-- |     MD5: 44d88612fea8a8f36de82e1278abb02f
-- |   Results
-- |     name                  result                          date      version
-- |     AhnLab-V3             EICAR_Test_File                 20120404  2012.04.05.00
-- |     AntiVir               Eicar-Test-Signature            20120405  7.11.27.24
-- |     Antiy-AVL             AVTEST/EICAR.ETF                20120403  2.0.3.7
-- |     Avast                 EICAR Test-NOT virus!!!         20120405  6.0.1289.0
-- |     AVG                   EICAR_Test                      20120405  10.0.0.1190
-- |     BitDefender           EICAR-Test-File (not a virus)   20120405  7.2
-- |     ByteHero              -                               20120404  1.0.0.1
-- |     CAT-QuickHeal         EICAR Test File                 20120405  12.00
-- |     ClamAV                Eicar-Test-Signature            20120405  0.97.3.0
-- |     Commtouch             EICAR_Test_File                 20120405  5.3.2.6
-- |     Comodo                Exploit.EICAR-Test-File         20120405  12000
-- |     DrWeb                 EICAR Test File (NOT a Virus!)  20120405  7.0.1.02210
-- |     Emsisoft              EICAR-ANTIVIRUS-TESTFILE!IK     20120405  5.1.0.11
-- |     eSafe                 EICAR Test File                 20120404  7.0.17.0
-- |     eTrust-Vet            the EICAR test string           20120405  37.0.9841
-- |     F-Prot                EICAR_Test_File                 20120405  4.6.5.141
-- |     F-Secure              EICAR_Test_File                 20120405  9.0.16440.0
-- |     Fortinet              EICAR_TEST_FILE                 20120405  4.3.392.0
-- |     GData                 EICAR-Test-File                 20120405  22
-- |     Ikarus                EICAR-ANTIVIRUS-TESTFILE        20120405  T3.1.1.118.0
-- |     Jiangmin              EICAR-Test-File                 20120331  13.0.900
-- |     K7AntiVirus           EICAR_Test_File                 20120404  9.136.6595
-- |     Kaspersky             EICAR-Test-File                 20120405  9.0.0.837
-- |     McAfee                EICAR test file                 20120405  5.400.0.1158
-- |     McAfee-GW-Edition     EICAR test file                 20120404  2012.1
-- |     Microsoft             Virus:DOS/EICAR_Test_File       20120405  1.8202
-- |     NOD32                 Eicar test file                 20120405  7031
-- |     Norman                Eicar_Test_File                 20120405  6.08.03
-- |     nProtect              EICAR-Test-File                 20120405  2012-04-05.01
-- |     Panda                 EICAR-AV-TEST-FILE              20120405  10.0.3.5
-- |     PCTools               Virus.DOS.EICAR_test_file       20120405  8.0.0.5
-- |     Rising                EICAR-Test-File                 20120405  24.04.02.03
-- |     Sophos                EICAR-AV-Test                   20120405  4.73.0 TP
-- |     SUPERAntiSpyware      NotAThreat.EICAR[TestFile]      20120402  4.40.0.1006
-- |     Symantec              EICAR Test String               20120405  20111.2.0.82
-- |     TheHacker             EICAR_Test_File                 20120405  6.7.0.1.440
-- |     TrendMicro            Eicar_test_file                 20120405  9.500.0.1008
-- |     TrendMicro-HouseCall  Eicar_test_file                 20120405  9.500.0.1008
-- |     VBA32                 EICAR-Test-File                 20120405  3.12.16.4
-- |     VIPRE                 EICAR (v)                       20120405  11755
-- |     ViRobot               EICAR-test                      20120405  2012.4.5.5025
-- |_    VirusBuster           EICAR_test_file                 20120404  14.2.11.0
--
-- @args http-virustotal.apikey an API key acquired from the virustotal web page
-- @args http-virustotal.upload true if the file should be uploaded and scanned, false if a
--       checksum should be calculated of the local file (default: false)
-- @args http-virustotal.filename the full path of the file to checksum or upload
-- @args http-virustotal.checksum a SHA1, SHA256, MD5 checksum of a file to check
--


author = "Patrik Karlsson"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories={"safe", "malware", "external"}


local arg_apiKey = stdnse.get_script_args(SCRIPT_NAME .. ".apikey")
local arg_upload = stdnse.get_script_args(SCRIPT_NAME .. ".upload") or false
local arg_filename = stdnse.get_script_args(SCRIPT_NAME .. ".filename")
local arg_checksum = stdnse.get_script_args(SCRIPT_NAME .. ".checksum")

prerule = function() return true end

local function readFile(filename)
  local f = io.open(filename, "r")
  if ( not(f) ) then
    return false, ("Failed to open file: %s"):format(filename)
  end

  local str = f:read("a")
  f:close()
  if ( not(str) ) then
    return false, "Failed to read file contents"
  end
  return true, str
end

local function requestFileScan(filename)
  local status, str = readFile(filename)
  if ( not(status) ) then
    return false, str
  end

  local shortfile = filename:match("^.*[\\/](.*)$")
  local boundary = "----------------------------nmapboundary"
  local header = { ["Content-Type"] = ("multipart/form-data; boundary=%s"):format(boundary) }
  local postdata = ("--%s\r\n"
  .. 'Content-Disposition: form-data; name="apikey"\r\n\r\n'
  .. "%s\r\n"
  .. "--%s\r\n"
  .. 'Content-Disposition: form-data; name="file"; filename="%s"\r\n'
  .. "Content-Type: text/plain\r\n\r\n%s\r\n--%s--\r\n"):format(boundary, arg_apiKey, boundary, shortfile, str, boundary)

  local host = "www.virustotal.com"
  local port = { number = 80, protocol = "tcp" }
  local path = "/vtapi/v2/file/scan"

  local response = http.post( host, port, path, {any_af = true, header = header }, nil, postdata )
  if ( not(response) or response.status ~= 200 ) then
    return false, "Failed to request file scan"
  end

  local status, json_data = json.parse(response.body)
  if ( not(status) ) then
    return false, "Failed to parse JSON response"
  end

  return true, json_data
end

local function getFileScanReport(resource)

  local host = "www.virustotal.com"
  local port = { number = 80, protocol = "tcp" }
  local path = "/vtapi/v2/file/report"


  local response = http.post(host, port, path, {any_af=true}, nil, { ["apikey"] = arg_apiKey, ["resource"] = resource })
  if ( not(response) or response.status ~= 200 ) then
    return false, "Failed to retrieve scan report"
  end

  local status, json_data = json.parse(response.body)
  if ( not(status) ) then
    return false, "Failed to parse JSON response"
  end

  return true, json_data
end

local function calcSHA256(filename)

  local status, str = readFile(filename)
  if ( not(status) ) then
    return false, str
  end
  return true, stdnse.tohex(openssl.digest("sha256", str))
end

local function parseScanReport(report)
  local result = {}

  table.insert(result, ("Permalink: %s"):format(report.permalink))
  table.insert(result, ("Scan date: %s"):format(report.scan_date))
  table.insert(result, ("Positives: %s"):format(report.positives))
  table.insert(result, {
    name = "digests",
    ("SHA1: %s"):format(report.sha1),
    ("SHA256: %s"):format(report.sha256),
    ("MD5: %s"):format(report.md5)
  })

  local tmp = {}
  for name, scanres in pairs(report.scans) do
    local res = ( scanres.detected ) and scanres.result or "-"
    table.insert(tmp, { name = name, result = res, update = scanres.update, version = scanres.version })
  end
  table.sort(tmp, function(a,b) return a.name:upper()<b.name:upper() end)

  local scan_tbl = tab.new(4)
  tab.addrow(scan_tbl, "name", "result", "date", "version")
  for _, v in ipairs(tmp) do
    tab.addrow(scan_tbl, v.name, v.result, v.update, v.version)
  end
  table.insert(result, { name = "Results", tab.dump(scan_tbl) })

  return result
end

local function fail(err) return stdnse.format_output(false, err) end

action = function()

  if ( not(arg_apiKey) ) then
    return fail("An API key is required in order to use this script (see description)")
  end

  local resource
  if ( arg_upload == "true" and arg_filename ) then
    local status, json_data = requestFileScan(arg_filename, arg_apiKey)
    if ( not(status) or not(json_data['resource']) ) then
      return fail(json_data)
    end
    resource = json_data['resource']

    local output = {}
    table.insert(output, "Your file was successfully uploaded and placed in the scanning queue.")
    table.insert(output, { name = "To check the current status visit:", json_data['permalink'] })
    return stdnse.format_output(true, output)
  elseif ( arg_filename ) then
    local status, sha256 = calcSHA256(arg_filename)
    if ( not(status) ) then
      return fail("Failed to calculate SHA256 checksum for file")
    end
    resource = sha256
  elseif ( arg_checksum ) then
    resource = arg_checksum
  else
    return
  end

  local status, response

  local status, response = getFileScanReport(resource)
  if ( not(status) ) then
    return fail("Failed to retrieve file scan report")
  end

  if ( not(response.response_code) or 0 == tonumber(response.response_code) ) then
    return fail(("Failed to retrieve scan report for resource: %s"):format(resource))
  end

  return stdnse.format_output(true, parseScanReport(response))
end

9.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

10 High

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

COMPLETE

Integrity Impact

COMPLETE

Availability Impact

COMPLETE

AV:N/AC:L/Au:N/C:C/I:C/A:C

0.973 High

EPSS

Percentile

99.8%

Related for NMAP:HTTP-VIRUSTOTAL.NSE