Skip to content

Commit 391d88e

Browse files
author
Ilya Govorkov
committed
Another stable version.
- Add mincvss comandline arg. - Refactor according to the nmap official repo policy
1 parent e5f8645 commit 391d88e

File tree

2 files changed

+107
-105
lines changed

2 files changed

+107
-105
lines changed

example.png

-13.5 KB
Loading

vulners.nse

+107-105
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Its work is pretty simple:
1010

1111
---
1212
-- @usage
13-
-- nmap -sV --script vulners <target>
13+
-- nmap -sV --script vulners [--script-args mincvss=<arg_val>] <target>
1414
--
1515
-- @output
1616
--
@@ -36,12 +36,13 @@ local json = require "json"
3636
local string = require "string"
3737
local table = require "table"
3838

39-
local api_version="1.1"
39+
local api_version="1.2"
40+
local mincvss=nmap.registry.args.mincvss and tonumber(nmap.registry.args.mincvss) or 0.0
4041

4142

4243
portrule = function(host, port)
43-
local vers=port.version
44-
return vers ~= nil and vers.version ~= nil
44+
local vers=port.version
45+
return vers ~= nil and vers.version ~= nil
4546
end
4647

4748

@@ -51,34 +52,38 @@ end
5152
-- @param vulns a table with the parsed json response from the vulners server
5253
--
5354
function make_links(vulns)
54-
local output_str=""
55-
local is_exploit=false
56-
local cvss_score=""
55+
local output_str=""
56+
local is_exploit=false
57+
local cvss_score=""
5758

58-
-- NOTE[gmedian]: data.search is a "list" already, so just use table.sort with a custom compare function
59-
-- However, for the future it might be wiser to create a copy rather than do it in-place
59+
-- NOTE[gmedian]: data.search is a "list" already, so just use table.sort with a custom compare function
60+
-- However, for the future it might be wiser to create a copy rather than do it in-place
6061

61-
local vulns_result = {}
62-
for _, v in ipairs(vulns.data.search) do
63-
table.insert(vulns_result, v)
64-
end
62+
local vulns_result = {}
63+
for _, v in ipairs(vulns.data.search) do
64+
table.insert(vulns_result, v)
65+
end
6566

6667
-- Sort the acquired vulns by the CVSS score
67-
table.sort(vulns_result, function(a, b)
68-
return a._source.cvss.score > b._source.cvss.score
69-
end
70-
)
71-
72-
for _, vuln in ipairs(vulns_result) do
73-
-- Mark the exploits out
74-
is_exploit = vuln._source.bulletinFamily:lower() == "exploit"
75-
76-
-- Sometimes it might happen, so check the score availability
77-
cvss_score = vuln._source.cvss and ("\t\t" .. vuln._source.cvss.score) or ""
78-
output_str = string.format("%s\n\t%s", output_str, vuln._source.id .. cvss_score .. '\t\thttps://vulners.com/' .. vuln._source.type .. '/' .. vuln._source.id .. (is_exploit and '\t\t*EXPLOIT*' or ''))
68+
table.sort(vulns_result, function(a, b)
69+
return a._source.cvss.score > b._source.cvss.score
70+
end
71+
)
72+
73+
for _, vuln in ipairs(vulns_result) do
74+
-- Mark the exploits out
75+
is_exploit = vuln._source.bulletinFamily:lower() == "exploit"
76+
77+
-- Sometimes it might happen, so check the score availability
78+
cvss_score = vuln._source.cvss and (type(vuln._source.cvss.score) == "number") and (vuln._source.cvss.score) or ""
79+
80+
-- NOTE[gmedian]: exploits seem to have cvss == 0, so print them anyway
81+
if is_exploit or (cvss_score ~= "" and mincvss <= tonumber(cvss_score)) then
82+
output_str = string.format("%s\n\t%s", output_str, vuln._source.id .. "\t\t" .. cvss_score .. '\t\thttps://vulners.com/' .. vuln._source.type .. '/' .. vuln._source.id .. (is_exploit and '\t\t*EXPLOIT*' or ''))
7983
end
80-
81-
return output_str
84+
end
85+
86+
return output_str
8287
end
8388

8489

@@ -90,41 +95,38 @@ end
9095
-- @param type string, the type query argument
9196
--
9297
function get_results(what, vers, type)
93-
local v_host="vulners.com"
94-
local v_port=443
95-
local response, path
96-
local status, error
97-
local vulns
98-
local option={header={}}
99-
100-
option['header']['User-Agent'] = string.format('Vulners NMAP Plugin %s', api_version)
101-
102-
path = '/api/v3/burp/software/' .. '?software=' .. what .. '&version=' .. vers .. '&type=' .. type
103-
104-
response = http.get(v_host, v_port, path, option)
105-
106-
status = response.status
107-
if status == nil then
108-
-- Something went really wrong out there
109-
-- According to the NSE way we will die silently rather than spam user with error messages
110-
return ""
111-
elseif status == 418 then
112-
-- Too many requests
113-
return "You are doing it too fast. Lower the rate or contact isox AT vulners DOT com."
114-
elseif status ~= 200 then
115-
-- Again just die silently
116-
return ""
117-
end
98+
local v_host="vulners.com"
99+
local v_port=443
100+
local response, path
101+
local status, error
102+
local vulns
103+
local option={header={}}
118104

119-
status, vulns = json.parse(response.body)
105+
option['header']['User-Agent'] = string.format('Vulners NMAP Plugin %s', api_version)
120106

121-
if status == true then
122-
if vulns.result == "OK" then
123-
return make_links(vulns)
124-
end
125-
end
107+
path = '/api/v3/burp/software/' .. '?software=' .. what .. '&version=' .. vers .. '&type=' .. type
108+
109+
response = http.get(v_host, v_port, path, option)
126110

111+
status = response.status
112+
if status == nil then
113+
-- Something went really wrong out there
114+
-- According to the NSE way we will die silently rather than spam user with error messages
127115
return ""
116+
elseif status ~= 200 then
117+
-- Again just die silently
118+
return ""
119+
end
120+
121+
status, vulns = json.parse(response.body)
122+
123+
if status == true then
124+
if vulns.result == "OK" then
125+
return make_links(vulns)
126+
end
127+
end
128+
129+
return ""
128130
end
129131

130132

@@ -137,7 +139,7 @@ end
137139
-- @param version string, the software version
138140
--
139141
function get_vulns_by_software(software, version)
140-
return get_results(software, version, "software")
142+
return get_results(software, version, "software")
141143
end
142144

143145

@@ -152,61 +154,61 @@ end
152154
-- @param cpe string, the given cpe
153155
--
154156
function get_vulns_by_cpe(cpe)
155-
local vers
156-
local vers_regexp=":([%d%.%-%_]+)([^:]*)$"
157-
local output_str=""
158-
159-
-- TODO[gmedian]: add check for cpe:/a as we might be interested in software rather than in OS (cpe:/o) and hardware (cpe:/h)
160-
-- TODO[gmedian]: work not with the LAST part but simply with the THIRD one (according to cpe doc it must be version)
157+
local vers
158+
local vers_regexp=":([%d%.%-%_]+)([^:]*)$"
159+
local output_str=""
160+
161+
-- TODO[gmedian]: add check for cpe:/a as we might be interested in software rather than in OS (cpe:/o) and hardware (cpe:/h)
162+
-- TODO[gmedian]: work not with the LAST part but simply with the THIRD one (according to cpe doc it must be version)
161163

162-
-- NOTE[gmedian]: take only the numeric part of the version
163-
_, _, vers = cpe:find(vers_regexp)
164+
-- NOTE[gmedian]: take only the numeric part of the version
165+
_, _, vers = cpe:find(vers_regexp)
164166

165167

166-
if not vers then
167-
return ""
168-
end
168+
if not vers then
169+
return ""
170+
end
169171

170-
output_str = get_results(cpe, vers, "cpe")
172+
output_str = get_results(cpe, vers, "cpe")
171173

172-
if output_str == "" then
173-
local new_cpe
174+
if output_str == "" then
175+
local new_cpe
174176

175-
new_cpe = cpe:gsub(vers_regexp, ":%1:%2")
176-
output_str = get_results(new_cpe, vers, "cpe")
177-
end
178-
179-
return output_str
177+
new_cpe = cpe:gsub(vers_regexp, ":%1:%2")
178+
output_str = get_results(new_cpe, vers, "cpe")
179+
end
180+
181+
return output_str
180182
end
181183

182184

183185
action = function(host, port)
184-
local tab={}
185-
local changed=false
186-
local response
187-
local output_str=""
188-
189-
for i, cpe in ipairs(port.version.cpe) do
190-
output_str = get_vulns_by_cpe(cpe, port.version)
191-
if output_str ~= "" then
192-
tab[cpe] = output_str
193-
changed = true
194-
end
195-
end
196-
197-
-- NOTE[gmedian]: issue request for type=software, but only when nothing is found so far
198-
if not changed then
199-
local vendor_version = port.version.product .. " " .. port.version.version
200-
output_str = get_vulns_by_software(port.version.product, port.version.version)
201-
if output_str ~= "" then
202-
tab[vendor_version] = output_str
203-
changed = true
204-
end
205-
end
206-
207-
if (not changed) then
208-
return
209-
end
210-
return tab
186+
local tab={}
187+
local changed=false
188+
local response
189+
local output_str=""
190+
191+
for i, cpe in ipairs(port.version.cpe) do
192+
output_str = get_vulns_by_cpe(cpe, port.version)
193+
if output_str ~= "" then
194+
tab[cpe] = output_str
195+
changed = true
196+
end
197+
end
198+
199+
-- NOTE[gmedian]: issue request for type=software, but only when nothing is found so far
200+
if not changed then
201+
local vendor_version = port.version.product .. " " .. port.version.version
202+
output_str = get_vulns_by_software(port.version.product, port.version.version)
203+
if output_str ~= "" then
204+
tab[vendor_version] = output_str
205+
changed = true
206+
end
207+
end
208+
209+
if (not changed) then
210+
return
211+
end
212+
return tab
211213
end
212214

0 commit comments

Comments
 (0)