local http = require "http"
local shortport = require "shortport"
local stdnse = require "stdnse"
local string = require "string"
local ls = require "ls"
local have_ssl, openssl = pcall(require,'openssl')
description = [[
Shows the content of an "index" Web page.
TODO:
- add support for more page formats
]]
author = "Pierre Lalet"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"default", "discovery", "safe"}
---
-- @usage
-- nmap -n -p 80 --script http-ls test-debit.free.fr
--
-- @args http-ls.checksum compute a checksum for each listed file. Requires OpenSSL.
-- (default: false)
-- @args http-ls.url base URL path to use (default: /)
--
-- @output
-- PORT STATE SERVICE
-- 80/tcp open http
-- | http-ls:
-- | Volume /
-- | maxfiles limit reached (10)
-- | SIZE TIME FILENAME
-- | 524288 02-Oct-2013 18:26 512.rnd
-- | 1048576 02-Oct-2013 18:26 1024.rnd
-- | 2097152 02-Oct-2013 18:26 2048.rnd
-- | 4194304 02-Oct-2013 18:26 4096.rnd
-- | 8388608 02-Oct-2013 18:26 8192.rnd
-- | 16777216 02-Oct-2013 18:26 16384.rnd
-- | 33554432 02-Oct-2013 18:26 32768.rnd
-- | 67108864 02-Oct-2013 18:26 65536.rnd
-- | 1073741824 03-Oct-2013 16:46 1048576.rnd
-- | 188 03-Oct-2013 17:15 README.html
-- |_
--
-- @xmloutput
--
--
-- /
--
--
-- 524288
-- 02-Oct-2013 18:26
-- 512.rnd
--
--
-- 1048576
-- 02-Oct-2013 18:26
-- 1024.rnd
--
--
-- 2097152
-- 02-Oct-2013 18:26
-- 2048.rnd
--
--
-- 4194304
-- 02-Oct-2013 18:26
-- 4096.rnd
--
--
-- 8388608
-- 02-Oct-2013 18:26
-- 8192.rnd
--
--
-- 16777216
-- 02-Oct-2013 18:26
-- 16384.rnd
--
--
-- 33554432
-- 02-Oct-2013 18:26
-- 32768.rnd
--
--
-- 67108864
-- 02-Oct-2013 18:26
-- 65536.rnd
--
--
-- 1073741824
-- 03-Oct-2013 16:46
-- 1048576.rnd
--
--
-- 188
-- 03-Oct-2013 17:15
-- README.html
--
--
--
-- maxfiles limit reached (10)
--
--
--
--
portrule = shortport.http
local function isdir(fname, size)
-- we consider a file is (probably) a directory if its name
-- terminates with a '/' or if the string representing its size is
-- either empty or a single dash ('-').
if string.sub(fname, -1, -1) == '/' then
return true
end
if size == '' or size == '-' then
return true
end
return false
end
local function list_files(host, port, url, output, maxdepth, basedir)
basedir = basedir or ""
local resp = http.get(host, port, url)
if resp.location or not resp.body then
return true
end
if not string.match(resp.body, "<[Tt][Ii][Tt][Ll][Ee][^>]*> *[Ii][Nn][Dd][Ee][Xx] +[Oo][Ff]") then
return true
end
local patterns = {
'<[Aa] [Hh][Rr][Ee][Ff]="([^"]+)">[^<]+[Aa]>[Tt][Dd]><[Tt][Dd][^>]*> *([0-9]+-[A-Za-z0-9]+-[0-9]+ [0-9]+:[0-9]+) *[Tt][Dd]><[Tt][Dd][^>]*> *([^<]+)[Tt][Dd]>',
'<[Aa] [Hh][Rr][Ee][Ff]="([^"]+)">[^<]+[Aa]> *([0-9]+-[A-Za-z0-9]+-[0-9]+ [0-9]+:[0-9]+) *([^ \r\n]+)',
}
for _, pattern in ipairs(patterns) do
for fname, date, size in string.gmatch(resp.body, pattern) do
local continue = true
local directory = isdir(fname, size)
if have_ssl and ls.config('checksum') and not directory then
local checksum = ""
local resp = http.get(host, port, url .. fname)
if not resp.location and resp.body then
checksum = stdnse.tohex(openssl.sha1(resp.body))
end
continue = ls.add_file(output, {size, date, basedir .. fname, checksum})
else
continue = ls.add_file(output, {size, date, basedir .. fname})
end
if not continue then
return false
end
if directory then
if string.sub(fname, -1, -1) ~= "/" then fname = fname .. '/' end
continue = true
if maxdepth > 0 then
continue = list_files(host, port, url .. fname, output, maxdepth - 1,
basedir .. fname)
elseif maxdepth < 0 then
continue = list_files(host, port, url .. fname, output, -1,
basedir .. fname)
end
if not continue then
return false
end
end
end
end
return true
end
action = function(host, port)
local url = stdnse.get_script_args(SCRIPT_NAME .. '.url') or "/"
local output = ls.new_listing()
ls.new_vol(output, url, false)
local continue = list_files(host, port, url, output, ls.config('maxdepth'))
if not continue then
ls.report_info(
output,
string.format("maxfiles limit reached (%d)", ls.config('maxfiles')))
end
ls.end_vol(output)
return ls.end_listing(output)
end