From 72a9c62d4a1509b28446e6047411ab73dc212184 Mon Sep 17 00:00:00 2001 From: adrien <adrien@malingrey.fr> Date: Mon, 10 Apr 2023 21:02:42 +0200 Subject: [PATCH] nmap favicon url --- http-favicon-url.nse | 168 +++++++++++++++++++++++++++++++++++++++++++ index.php | 16 ++++- results.xsl | 10 ++- scan_all.php | 20 ++++-- 4 files changed, 204 insertions(+), 10 deletions(-) create mode 100644 http-favicon-url.nse diff --git a/http-favicon-url.nse b/http-favicon-url.nse new file mode 100644 index 0000000..9fd3145 --- /dev/null +++ b/http-favicon-url.nse @@ -0,0 +1,168 @@ +local datafiles = require "datafiles" +local http = require "http" +local nmap = require "nmap" +local shortport = require "shortport" +local stdnse = require "stdnse" +local string = require "string" +local url = require "url" + +local openssl = stdnse.silent_require "openssl" + +description = [[ +Gets the favicon url ("favorites icon"). + +If the script argument <code>favicon.uri</code> is given, that relative URI is +always used to find the favicon. Otherwise, first the page at the root of the +web server is retrieved and parsed for a <code><link rel="icon"></code> +element. If that fails, the icon is looked for in <code>/favicon.ico</code>. If +a <code><link></code> favicon points to a different host or port, it is ignored. +]] + +--- +-- @args favicon.uri URI that will be requested for favicon. +-- @args favicon.root Web server path to search for favicon. +-- +-- @usage +-- nmap --script=http-favicon-url.nse \ +-- --script-args favicon.root=<root>,favicon.uri=<uri> +-- @output +-- |_ http-favicon: http://hostname:80/favicon.ico + +-- HTTP default favicon enumeration script +-- rev 1.2 (2009-03-11) +-- Original NASL script by Javier Fernandez-Sanguino Pena + + +author = "Vlatko Kosturjak" + +license = "Same as Nmap--See https://nmap.org/book/man-legal.html" + +categories = {"default", "discovery", "safe"} + + +portrule = shortport.http + +action = function(host, port) + local md5sum,answer + local match + local status, favicondb + local result + local favicondbfile="nselib/data/favicon-db" + local index, icon + local root = "" + local url + local hostname = host.targetname or (host.name ~= "" and host.name) or host.ip + + status, favicondb = datafiles.parse_file( favicondbfile, {["^%s*([^%s#:]+)[%s:]+"] = "^%s*[^%s#:]+[%s:]+(.*)"}) + if not status then + stdnse.debug1("Could not open file: %s", favicondbfile ) + return + end + + if(stdnse.get_script_args('favicon.root')) then + root = stdnse.get_script_args('favicon.root') + end + local favicon_uri = stdnse.get_script_args("favicon.uri") + if(favicon_uri) then + -- If we got a script arg URI, always use that. + answer = http.get( host, port, root .. "/" .. favicon_uri) + stdnse.debug4("Using URI %s", favicon_uri) + url = favicon_uri + else + -- Otherwise, first try parsing the home page. + index = http.get( host, port, root .. "/" ) + if index.status == 200 or index.status == 503 then + -- find the favicon pattern + icon = parseIcon( index.body ) + -- if we find a pattern + if icon then + stdnse.debug1("Got icon URL %s.", icon) + local icon_host, icon_port, icon_path = parse_url_relative(icon, hostname, port.number, root) + if (icon_host == host.ip or + icon_host == host.targetname or + icon_host == (host.name ~= '' and host.name)) and + icon_port == port.number then + -- request the favicon + answer = http.get( icon_host, icon_port, icon_path ) + url = port.service.."://"..hostname..":"..port.number.."/"..root.."/"..icon_path + else + answer = nil + end + else + answer = nil + end + end + + -- If that didn't work, try /favicon.ico. + if not answer or answer.status ~= 200 then + answer = http.get( host, port, root .. "/favicon.ico" ) + url = port.service.."://"..hostname..":"..port.number.."/"..root.."favicon.ico" + stdnse.debug4("Using default URI.") + end + end + + --- check for 200 response code + if answer and answer.status == 200 then + result = url + else + stdnse.debug1("No favicon found.") + return + end --- status == 200 + return result +end + +local function dirname(path) + local dir + dir = string.match(path, "^(.*)/") + return dir or "" +end + +-- Return a URL's host, port, and path, filling in the results with the given +-- host, port, and path if the URL is relative. Return nil if the scheme is not +-- "http" or "https". +function parse_url_relative(u, host, port, path) + local scheme, abspath + u = url.parse(u) + scheme = u.scheme or "http" + if not (scheme == "http" or scheme == "https") then + return nil + end + abspath = u.path or "" + if not string.find(abspath, "^/") then + abspath = dirname(path) .. "/" .. abspath + end + return u.host or host, u.port or url.get_default_port(scheme), abspath +end + +function parseIcon( body ) + local _, i, j + local rel, href, word + + -- Loop through link elements. + i = 0 + while i do + _, i = string.find(body, "<%s*[Ll][Ii][Nn][Kk]%s", i + 1) + if not i then + return nil + end + -- Loop through attributes. + j = i + while true do + local name, quote, value + _, j, name, quote, value = string.find(body, "^%s*(%w+)%s*=%s*([\"'])(.-)%2", j + 1) + if not j then + break + end + if string.lower(name) == "rel" then + rel = value + elseif string.lower(name) == "href" then + href = value + end + end + for word in string.gmatch(rel or "", "%S+") do + if string.lower(word) == "icon" then + return href + end + end + end +end diff --git a/index.php b/index.php index 1eb8c92..302449e 100644 --- a/index.php +++ b/index.php @@ -22,14 +22,24 @@ </header> <div class="ui main text container"> <div class="ui link selection list"> -<?php foreach (scandir("./site") as $file) { - if (strrpos($file, ".xml")) { +<?php +if (! function_exists('str_ends_with')) { + function str_ends_with(string $haystack, string $needle): bool + { + $needle_len = strlen($needle); + return ($needle_len === 0 || 0 === substr_compare($haystack, $needle, - $needle_len)); + } +} + +foreach (scandir("./site") as $file) { + if (str_ends_with($file, ".xml")) { $site = str_replace(".xml", "", $file); if (file_exists("scans/$site.xml")) { echo " <a href='site/$site.xml' class='item'>$site</a>\n"; } } -} ?> +} +?> </div> </div> </body> diff --git a/results.xsl b/results.xsl index 760db18..643eefb 100644 --- a/results.xsl +++ b/results.xsl @@ -25,6 +25,7 @@ padding: 1em; } </style> + <meta http-equiv="refresh" content="300" /> </head> <body> <header class="ui fixed blue inverted menu"> @@ -70,7 +71,14 @@ <xsl:otherwise>ui fluid mini left icon action input error</xsl:otherwise> </xsl:choose> </xsl:attribute> - <i class="icon"><img class="ui image" src="http://{$scannedHostAddress}/favicon.ico" alt="" /></i> + <xsl:choose> + <xsl:when test="$scannedHost/ports/port/script[@id='http-favicon-url']/@output"> + <i class="icon"><img class="ui image" src="{$scannedHost/ports/port/script[@id='http-favicon-url']/@output}" alt="" /></i> + </xsl:when> + <xsl:otherwise> + <i class="server icon"></i> + </xsl:otherwise> + </xsl:choose> <input type="text" readonly=""> <xsl:attribute name="value"> <xsl:choose> diff --git a/scan_all.php b/scan_all.php index bb8f729..af03907 100644 --- a/scan_all.php +++ b/scan_all.php @@ -1,8 +1,16 @@ <?php +if (! function_exists('str_ends_with')) { + function str_ends_with(string $haystack, string $needle): bool + { + $needle_len = strlen($needle); + return ($needle_len === 0 || 0 === substr_compare($haystack, $needle, - $needle_len)); + } +} + if (!file_exists("scans")) mkdir("scans"); -foreach (scandir("./site") as $file) { - if (strrpos($file, ".yaml")) { +foreach (scandir("./site/") as $file) { + if (str_ends_with($file, ".yaml")) { $site = str_replace(".yaml", "", $file); $yaml = yaml_parse_file("site/$file"); @@ -33,12 +41,12 @@ foreach (scandir("./site") as $file) { } } } - - $targets = array_keys($targets); - $services = array_keys($services); $xml->asXML("site/$site.xml"); - exec("nmap -v -Pn -p ".join($services, ",")." --script smb-enum-shares.nse -oX 'scans/$site.xml' ".join($targets, " ")."\n"); + $targets = join(array_keys($targets), " "); + $services = join(array_keys($services), ","); + + exec("nmap -v -Pn -p $services --script smb-enum-shares.nse,http-errors,./http-favicon-url.nse --script-args=httpspider.maxpagecount=1 -oX 'scans/$site.xml' $targets\n"); } };