summaryrefslogtreecommitdiffstats
path: root/scripts/ajp-auth.nse
blob: 0a258e01669b88e92bd08dab2af0cef6f761f8ef (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
local ajp = require "ajp"
local http = require "http"
local shortport = require "shortport"
local stdnse = require "stdnse"
local table = require "table"

description = [[
Retrieves the authentication scheme and realm of an AJP service (Apache JServ Protocol) that requires authentication.
]]

---
-- @usage
-- nmap -p 8009 <ip> --script ajp-auth [--script-args ajp-auth.path=/login]
--
-- @output
-- PORT     STATE SERVICE
-- 8009/tcp open  ajp13
-- | ajp-auth:
-- |_  Digest opaque=GPui3SvCGBoHrRMMzSsgaYBV qop=auth nonce=1336063830612:935b5b389696b0f67b9193e19f47e037 realm=example.org
--
-- @args ajp-auth.path  Define the request path
--

author = "Patrik Karlsson"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"default", "auth", "safe"}


portrule = shortport.port_or_service(8009, 'ajp13', 'tcp')

local arg_path = stdnse.get_script_args(SCRIPT_NAME .. ".path")

action = function(host, port)
  local helper = ajp.Helper:new(host, port)

  if ( not(helper:connect()) ) then
    return stdnse.format_output(false, "Failed to connect to AJP server")
  end

  local status, answer = helper:get(arg_path or "/")

  --- check for 401 response code
  if ( not(status) or answer.status ~= 401 ) then
    return
  end

  local result = { name = answer.status_line:match("^(.*)\r?\n$") }

  local www_authenticate = answer.headers["www-authenticate"]
  if not www_authenticate then
    table.insert( result, ("Server returned status %d but no WWW-Authenticate header."):format(answer.status) )
    return stdnse.format_output(true, result)
  end

  local challenges = http.parse_www_authenticate(www_authenticate)
  if ( not(challenges) ) then
    table.insert( result, ("Server returned status %d but the WWW-Authenticate header could not be parsed."):format(answer.status) )
    table.insert( result, ("WWW-Authenticate: %s"):format(www_authenticate) )
    return stdnse.format_output(true, result)
  end

  for _, challenge in ipairs(challenges) do
    local line = challenge.scheme
    if ( challenge.params ) then
      for name, value in pairs(challenge.params) do
        line = line .. (" %s=%s"):format(name, value)
      end
    end
    table.insert(result, line)
  end
  return stdnse.format_output(true, result)
end