mirror of
https://github.com/nmap/nmap.git
synced 2025-12-06 04:31:29 +00:00
o [NSE] Oops, there was a vulnerability in one of our 437 NSE scripts.
If you ran the (fortunately non-default) http-domino-enum-passwords script with the (fortunately also non-default) domino-enum-passwords.idpath parameter against a malicious server, it could cause an arbitrarily named file to to be written to the client system. Thanks to Trustwave researcher Piotr Duszynski for discovering and reporting the problem. We've fixed that script, and also updated several other scripts to use a new stdnse.filename_escape function for extra safety. This breaks our record of never having a vulnerability in the 16 years that Nmap has existed, but that's still a fairly good run. [David, Fyodor]
This commit is contained in:
12
CHANGELOG
12
CHANGELOG
@@ -19,6 +19,18 @@ o [Ncat] Added --lua-exec. This feature is basically an equivalent of ncat
|
|||||||
redirecting all stdin and stdout operations to the socket connection.
|
redirecting all stdin and stdout operations to the socket connection.
|
||||||
[Jacek Wielemborek]
|
[Jacek Wielemborek]
|
||||||
|
|
||||||
|
o [NSE] Oops, there was a vulnerability in one of our 437 NSE scripts.
|
||||||
|
If you ran the (fortunately non-default) http-domino-enum-passwords
|
||||||
|
script with the (fortunately also non-default)
|
||||||
|
domino-enum-passwords.idpath parameter against a malicious server,
|
||||||
|
it could cause an arbitrarily named file to to be written to the
|
||||||
|
client system. Thanks to Trustwave researcher Piotr Duszynski for
|
||||||
|
discovering and reporting the problem. We've fixed that script, and
|
||||||
|
also updated several other scripts to use a new
|
||||||
|
stdnse.filename_escape function for extra safety. This breaks our
|
||||||
|
record of never having a vulnerability in the 16 years that Nmap has
|
||||||
|
existed, but that's still a fairly good run. [David, Fyodor]
|
||||||
|
|
||||||
o [NSE] Added teamspeak2-version.nse by Marin Maržić.
|
o [NSE] Added teamspeak2-version.nse by Marin Maržić.
|
||||||
|
|
||||||
o Nmap's routing table is now sorted first by netmask, then by metric.
|
o Nmap's routing table is now sorted first by netmask, then by metric.
|
||||||
|
|||||||
@@ -1195,4 +1195,36 @@ function pretty_printer (obj, printer)
|
|||||||
return aux(obj, "")
|
return aux(obj, "")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- This pattern must match the percent sign '%' since it is used in
|
||||||
|
-- escaping.
|
||||||
|
local FILESYSTEM_UNSAFE = "[^a-zA-Z0-9._-]"
|
||||||
|
---
|
||||||
|
-- Escape a string to remove bytes and strings that may have meaning to
|
||||||
|
-- a filesystem, such as slashes. All bytes are escaped, except for:
|
||||||
|
-- * alphabetic <code>a</code>-<code>z</code> and <code>A</code>-<code>Z</code>, digits 0-9, <code>.</code> <code>_</code> <code>-</code>
|
||||||
|
-- In addition, the strings <code>"."</code> and <code>".."</code> have
|
||||||
|
-- their characters escaped.
|
||||||
|
--
|
||||||
|
-- Bytes are escaped by a percent sign followed by the two-digit
|
||||||
|
-- hexadecimal representation of the byte value.
|
||||||
|
-- * <code>filename_escape("filename.ext") --> "filename.ext"</code>
|
||||||
|
-- * <code>filename_escape("input/output") --> "input%2foutput"</code>
|
||||||
|
-- * <code>filename_escape(".") --> "%2e"</code>
|
||||||
|
-- * <code>filename_escape("..") --> "%2e%2e"</code>
|
||||||
|
-- This escaping is somewhat like that of JavaScript
|
||||||
|
-- <code>encodeURIComponent</code>, except that fewer bytes are
|
||||||
|
-- whitelisted, and it works on bytes, not Unicode characters or UTF-16
|
||||||
|
-- code points.
|
||||||
|
function filename_escape(s)
|
||||||
|
if s == "." then
|
||||||
|
return "%2e"
|
||||||
|
elseif s == ".." then
|
||||||
|
return "%2e%2e"
|
||||||
|
else
|
||||||
|
return (string.gsub(s, FILESYSTEM_UNSAFE, function (c)
|
||||||
|
return string.format("%%%02x", string.byte(c))
|
||||||
|
end))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return _ENV;
|
return _ENV;
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ action = function(host, port)
|
|||||||
helper:disconnect()
|
helper:disconnect()
|
||||||
|
|
||||||
if ( status and data and path ) then
|
if ( status and data and path ) then
|
||||||
local filename = ("%s/%s.id"):format(path, username )
|
local filename = path .. "/" .. stdnse.filename_escape(u_details.fullname .. ".id")
|
||||||
local status, err = saveIDFile( filename, data )
|
local status, err = saveIDFile( filename, data )
|
||||||
|
|
||||||
if ( status ) then
|
if ( status ) then
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ categories = {"external", "discovery", "intrusive"}
|
|||||||
|
|
||||||
local HOSTMAP_SERVER = "www.bfk.de"
|
local HOSTMAP_SERVER = "www.bfk.de"
|
||||||
|
|
||||||
local filename_escape, write_file
|
local write_file
|
||||||
|
|
||||||
hostrule = function(host)
|
hostrule = function(host)
|
||||||
return not ipOps.isPrivate(host.ip)
|
return not ipOps.isPrivate(host.ip)
|
||||||
@@ -106,7 +106,7 @@ action = function(host)
|
|||||||
|
|
||||||
local filename_prefix = stdnse.get_script_args("hostmap-bfk.prefix")
|
local filename_prefix = stdnse.get_script_args("hostmap-bfk.prefix")
|
||||||
if filename_prefix then
|
if filename_prefix then
|
||||||
local filename = filename_prefix .. filename_escape(host.targetname or host.ip)
|
local filename = filename_prefix .. stdnse.filename_escape(host.targetname or host.ip)
|
||||||
local status, err = write_file(filename, hostnames_str .. "\n")
|
local status, err = write_file(filename, hostnames_str .. "\n")
|
||||||
if status then
|
if status then
|
||||||
output_tab.filename = filename
|
output_tab.filename = filename
|
||||||
@@ -118,13 +118,6 @@ action = function(host)
|
|||||||
return output_tab
|
return output_tab
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Escape some potentially unsafe characters in a string meant to be a filename.
|
|
||||||
function filename_escape(s)
|
|
||||||
return string.gsub(s, "[\0/=]", function(c)
|
|
||||||
return string.format("=%02X", string.byte(c))
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
function write_file(filename, contents)
|
function write_file(filename, contents)
|
||||||
local f, err = io.open(filename, "w")
|
local f, err = io.open(filename, "w")
|
||||||
if not f then
|
if not f then
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ local target = require "target"
|
|||||||
local HOSTMAP_BING_SERVER = "www.ip2hosts.com"
|
local HOSTMAP_BING_SERVER = "www.ip2hosts.com"
|
||||||
local HOSTMAP_DEFAULT_PROVIDER = "ALL"
|
local HOSTMAP_DEFAULT_PROVIDER = "ALL"
|
||||||
|
|
||||||
local filename_escape, write_file
|
local write_file
|
||||||
|
|
||||||
hostrule = function(host)
|
hostrule = function(host)
|
||||||
return not ipOps.isPrivate(host.ip)
|
return not ipOps.isPrivate(host.ip)
|
||||||
@@ -99,7 +99,7 @@ action = function(host)
|
|||||||
output_tab.hosts = hostnames
|
output_tab.hosts = hostnames
|
||||||
--write to file
|
--write to file
|
||||||
if filename_prefix then
|
if filename_prefix then
|
||||||
local filename = filename_prefix .. filename_escape(host.targetname or host.ip)
|
local filename = filename_prefix .. stdnse.filename_escape(host.targetname or host.ip)
|
||||||
hostnames_str = stdnse.strjoin("\n", hostnames)
|
hostnames_str = stdnse.strjoin("\n", hostnames)
|
||||||
local status, err = write_file(filename, hostnames_str)
|
local status, err = write_file(filename, hostnames_str)
|
||||||
if status then
|
if status then
|
||||||
@@ -112,13 +112,6 @@ action = function(host)
|
|||||||
return output_tab
|
return output_tab
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Escape some potentially unsafe characters in a string meant to be a filename.
|
|
||||||
function filename_escape(s)
|
|
||||||
return string.gsub(s, "[%z/=]", function(c)
|
|
||||||
return string.format("=%02X", string.byte(c))
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
function write_file(filename, contents)
|
function write_file(filename, contents)
|
||||||
local f, err = io.open(filename, "w")
|
local f, err = io.open(filename, "w")
|
||||||
if not f then
|
if not f then
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ action = function (host, port)
|
|||||||
if (response.status == 200) then
|
if (response.status == 200) then
|
||||||
-- check it if is valid before inserting
|
-- check it if is valid before inserting
|
||||||
if cfg.check(response.body) then
|
if cfg.check(response.body) then
|
||||||
local filename = ((host.targetname or host.ip) .. url_path):gsub("/", "-");
|
local filename = stdnse.escape_filename((host.targetname or host.ip) .. url_path)
|
||||||
|
|
||||||
-- save the content
|
-- save the content
|
||||||
if save then
|
if save then
|
||||||
|
|||||||
@@ -315,9 +315,10 @@ action = function(host, port)
|
|||||||
http_response = http.get( vhost or host, port, u_details.idfile, { auth = { username = user, password = pass }, no_cache = true })
|
http_response = http.get( vhost or host, port, u_details.idfile, { auth = { username = user, password = pass }, no_cache = true })
|
||||||
|
|
||||||
if ( http_response.status == 200 ) then
|
if ( http_response.status == 200 ) then
|
||||||
local status, err = saveIDFile( ("%s/%s.id"):format(download_path, u_details.fullname), http_response.body )
|
local filename = download_path .. "/" .. stdnse.filename_escape(u_details.fullname .. ".id")
|
||||||
|
local status, err = saveIDFile( filename, http_response.body )
|
||||||
if ( status ) then
|
if ( status ) then
|
||||||
table.insert( id_files, ("%s ID File has been downloaded (%s/%s.id)"):format(u_details.fullname, download_path, u_details.fullname) )
|
table.insert( id_files, ("%s ID File has been downloaded (%s)"):format(u_details.fullname, filename) )
|
||||||
else
|
else
|
||||||
table.insert( id_files, ("%s ID File was not saved (error: %s)"):format(u_details.fullname, err ) )
|
table.insert( id_files, ("%s ID File was not saved (error: %s)"):format(u_details.fullname, err ) )
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ action = function( host, port )
|
|||||||
local filename
|
local filename
|
||||||
if ( dir ) then
|
if ( dir ) then
|
||||||
local instance = instance:GetName():match("%\\+(.+)$") or instance:GetName()
|
local instance = instance:GetName():match("%\\+(.+)$") or instance:GetName()
|
||||||
filename = ("%s/%s_%s_ms-sql_hashes.txt"):format(dir, host.ip, instance)
|
filename = dir .. "/" .. stdnse.filename_escape(("%s_%s_ms-sql_hashes.txt"):format(host.ip, instance))
|
||||||
saveToFile(filename, instanceOutput[1])
|
saveToFile(filename, instanceOutput[1])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ action = function(host, port)
|
|||||||
result = ( infile and infile:getContent() )
|
result = ( infile and infile:getContent() )
|
||||||
|
|
||||||
if ( tftproot ) then
|
if ( tftproot ) then
|
||||||
local fname = tftproot .. host.ip .. "-config"
|
local fname = tftproot .. stdnse.filename_escape(host.ip .. "-config")
|
||||||
local file, err = io.open(fname, "w")
|
local file, err = io.open(fname, "w")
|
||||||
if ( file ) then
|
if ( file ) then
|
||||||
file:write(result)
|
file:write(result)
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ local function check_infected(host, path, save)
|
|||||||
|
|
||||||
fmt = save:gsub("%%h", host.ip)
|
fmt = save:gsub("%%h", host.ip)
|
||||||
fmt = fmt:gsub("%%v", version)
|
fmt = fmt:gsub("%%v", version)
|
||||||
file = io.open(fmt, "w")
|
file = io.open(stdnse.filename_escape(fmt), "w")
|
||||||
if file then
|
if file then
|
||||||
stdnse.print_debug(1, "Wrote %d bytes to file %s.", #result.arguments, fmt)
|
stdnse.print_debug(1, "Wrote %d bytes to file %s.", #result.arguments, fmt)
|
||||||
file:write(result.arguments)
|
file:write(result.arguments)
|
||||||
|
|||||||
Reference in New Issue
Block a user