Package: release.debian.org Severity: normal I'd like to upload a security update for nmap to stable. Please see #719289 for further details.
Cheers, -Hilko
diff -u nmap-6.00/debian/changelog nmap-6.00/debian/changelog --- nmap-6.00/debian/changelog +++ nmap-6.00/debian/changelog @@ -1,3 +1,21 @@ +nmap (6.00-0.3+deb7u1) stable; urgency=high + + * Backport fix for CVE-2013-4885 (remote arbitrary file creation + vulnerability) from upstream SVN repository, r31576 (Closes: #719289). + The fix has been implemented by adding a filename_escape() function to + the stdnse.lua standard library. The following NSE scripts have been + modified to use it: + + - domino-enum-users.nse + - hostmap-bfk.nse + - http-config-backup.nse + - http-domino-enum-passwords.nse + - ms-sql-dump-hashes.nse + - snmp-ios-config.nse + - stuxnet-detect.nse + + -- Hilko Bengen <ben...@debian.org> Mon, 12 Aug 2013 23:07:29 +0200 + nmap (6.00-0.3) unstable; urgency=low * Non-maintainer upload. @@ -718,4 +735,0 @@ - -Local variables: -mode: debian-changelog -End: only in patch2: unchanged: --- nmap-6.00.orig/nselib/stdnse.lua +++ nmap-6.00/nselib/stdnse.lua @@ -969,3 +969,34 @@ 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 only in patch2: unchanged: --- nmap-6.00.orig/scripts/domino-enum-users.nse +++ nmap-6.00/scripts/domino-enum-users.nse @@ -99,7 +99,7 @@ helper:disconnect() 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 ) if ( status ) then only in patch2: unchanged: --- nmap-6.00.orig/scripts/snmp-ios-config.nse +++ nmap-6.00/scripts/snmp-ios-config.nse @@ -178,7 +178,7 @@ result = ( infile and infile:getContent() ) 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") if ( file ) then file:write(result) only in patch2: unchanged: --- nmap-6.00.orig/scripts/http-config-backup.nse +++ nmap-6.00/scripts/http-config-backup.nse @@ -203,7 +203,7 @@ if (response.status == 200) then -- check it if is valid before inserting 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 if save then only in patch2: unchanged: --- nmap-6.00.orig/scripts/ms-sql-dump-hashes.nse +++ nmap-6.00/scripts/ms-sql-dump-hashes.nse @@ -116,7 +116,7 @@ local filename if ( dir ) then 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]) end end only in patch2: unchanged: --- nmap-6.00.orig/scripts/stuxnet-detect.nse +++ nmap-6.00/scripts/stuxnet-detect.nse @@ -78,7 +78,7 @@ fmt = save:gsub("%%h", host.ip) fmt = fmt:gsub("%%v", version) - file = io.open(fmt, "w") + file = io.open(stdnse.filename_escape(fmt), "w") if file then stdnse.print_debug(1, "Wrote %d bytes to file %s.", #result.arguments, fmt) file:write(result.arguments) only in patch2: unchanged: --- nmap-6.00.orig/scripts/http-domino-enum-passwords.nse +++ nmap-6.00/scripts/http-domino-enum-passwords.nse @@ -308,9 +308,10 @@ 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 - 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 - 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 table.insert( id_files, ("%s ID File was not saved (error: %s)"):format(u_details.fullname, err ) ) end only in patch2: unchanged: --- nmap-6.00.orig/scripts/hostmap-bfk.nse +++ nmap-6.00/scripts/hostmap-bfk.nse @@ -47,7 +47,7 @@ local HOSTMAP_SERVER = "www.bfk.de" -local filename_escape, write_file +local write_file hostrule = function(host) return not ipOps.isPrivate(host.ip) @@ -89,7 +89,7 @@ local filename_prefix = stdnse.get_script_args("hostmap-bfk.prefix") 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") if status then output_str = string.format("Saved to %s\n", filename) @@ -104,13 +104,6 @@ return output_str 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) local f, err = io.open(filename, "w") if not f then