Nmap Development mailing list archives

Re: Nmap Erros on URI using NSE


From: Shritam Bhowmick <shritam.bhowmick () gmail com>
Date: Wed, 13 Aug 2014 14:03:06 +0530

Hi, thanks for the added functionality, determined that indeed the script
could be used as a fuzzer now via GET requests. Again, this is a major
revision done and works fine. I'd dig up more if needed,

Regards
Shritam Bhowmick
Founder at OpenFire Technologies.
Penetration Tester at+OpenFire Security.
Web Application Analysis and Research.
www.openfire-security.net
http://forum.openfire-security.net

The information contained herein (including any accompanying documents) is
confidential and is intended solely for the addressee(s). It may contain
proprietary, confidential, privileged information or other information
subject to legal restrictions. If you are not the intended recipient of
this message, please do not read, copy, use or disclose this message or its
attachments. Please notify the sender immediately and delete all copies of
this message and any attachments. This e-mail message including
attachment(s), if any, is believed to be free of any virus. However, it is
the responsibility of the recipient to ensure for absence of viruses.
OpenFire Technologies shall not be held responsible nor does it accept
any liability for any damage arising in any way from its use.


On Wed, Aug 13, 2014 at 3:40 AM, <nnposter () users sourceforge net> wrote:

Daniel Miller wrote:
I suppose adding a script-arg "http-form-brute.verb" could be useful in
odd
cases like this, but as I stated before, passing authentication
parameters
in a GET request is unusual because of caching and logging issues.

IMHO it is indeed not very common but I am personally running into it
enough to consider the support in nmap. As an additional benefit I have
found that the script can be sometimes used for detecting accounts or
even as a simple fuzzer for pre-generated cases, in which case GET is
not that uncommon.

The patch below implements http-form-brute.method, accepting GET or POST
as valid values, with POST being the default. I have also implemented
the following code clean-ups:

* Switched to stdnse.format_output(false, "blah...") for aborted
  execution
* Documented the default value for argument "path". (No code change.)
* Removed unreachable code branch that was checking whether argument
  "path" is defined. (It is always defined.)

I do see further opportunities for enhancement but I wanted to keep the
patch relatively concise. Constructive feedback is always appreciated.


Cheers,
nnposter



Patch against revision 33494 follows:


--- scripts/http-form-brute.nse.orig    2014-08-11 13:23:42.388923500 -0600
+++ scripts/http-form-brute.nse 2014-08-12 15:10:40.424876000 -0600
@@ -18,7 +18,7 @@
 use in order to perform password guessing. If it fails doing so the form
 parameters can be supplied using the uservar and passvar arguments.

-After attempting to authenticate using a HTTP POST request the script
+After attempting to authenticate using a HTTP GET or POST request the
script
 analyzes the response and attempt to determine whether authentication was
 successful or not. The script analyzes this by checking the response using
 the following rules:
@@ -48,28 +48,31 @@
 -- |_    Perfomed 60023 guesses in 467 seconds, average tps: 138
 --
 -- @args http-form-brute.path points to the path protected by
authentication
+--       (default: "/")
+-- @args http-form-brute.method sets the HTTP method (default: "POST")
 -- @args http-form-brute.hostname sets the host header in case of virtual
 --       hosting
 -- @args http-form-brute.uservar (optional) sets the http-variable name
that
 --       holds the username used to authenticate. A simple autodetection
of
 --       this variable is attempted.
 -- @args http-form-brute.passvar sets the http-variable name that holds
the
---     password used to authenticate. A simple autodetection of this
variable
---       is attempted.
+--       password used to authenticate. A simple autodetection of this
+--       variable is attempted.
 -- @args http-form-brute.onsuccess (optional) sets the message to expect
on
---     successful authentication
+--       successful authentication
 -- @args http-form-brute.onfailure (optional) sets the message to expect
on
---     unsuccessful authentication
+--       unsuccessful authentication

 --
--- Version 0.3
+-- Version 0.4
 -- Created 07/30/2010 - v0.1 - created by Patrik Karlsson <
patrik () cqure net>
 -- Revised 05/23/2011 - v0.2 - changed so that uservar is optional
 -- Revised 06/05/2011 - v0.3 - major re-write, added onsuccess, onfailure
and
---                support for redirects
+--                             support for redirects
+-- Revised 08/12/2014 - v0.4 - added support for GET method
 --

-author = "Patrik Karlsson"
+author = "Patrik Karlsson, nnposter"
 license = "Same as Nmap--See http://nmap.org/book/man-legal.html";
 categories = {"intrusive", "brute"}

@@ -100,10 +103,10 @@
   login = function( self, username, password )
     -- we need to supply the no_cache directive, or else the http library
     -- incorrectly tells us that the authentication was successful
-    local postparams = { [self.options.passvar] = password }
-    if ( self.options.uservar ) then postparams[self.options.uservar] =
username end
+    local params = { [self.options.passvar] = password }
+    if ( self.options.uservar ) then params[self.options.uservar] =
username end

-    local response = Driver.postRequest(self.host, self.port,
self.options.path, postparams)
+    local response = Driver.sendLogin(self.host, self.port,
self.options.path, self.options.method, params)
     local success = false

     -- if we have no response, we were successful
@@ -149,8 +152,16 @@
     return true
   end,

-  postRequest = function( host, port, path, options )
-    local response = http.post( host, port, path, { no_cache = true },
nil, options )
+  sendLogin = function( host, port, path, method, params )
+    local response
+    if method == "POST" then
+      response = http.post(host, port, path, {no_cache = true}, nil,
params)
+    else
+      local uri = path
+                  .. (path:find("?", 1, true) and "&" or "?")
+                  .. url.build_query(params)
+      response = http.get(host, port, uri, {no_cache = true})
+    end
     local status = ( response and tonumber(response.status) ) or 0
     if ( status > 300 and status < 400 ) then
       local new_path = url.absolute(path, response.header.location)
@@ -180,14 +191,20 @@
 end

 action = function( host, port )
+  local path = stdnse.get_script_args('http-form-brute.path') or "/"
+  local method = stdnse.get_script_args('http-form-brute.method') or
"POST"
   local uservar = stdnse.get_script_args('http-form-brute.uservar')
   local passvar = stdnse.get_script_args('http-form-brute.passvar')
-  local path = stdnse.get_script_args('http-form-brute.path') or "/"
   local onsuccess = stdnse.get_script_args("http-form-brute.onsuccess")
   local onfailure = stdnse.get_script_args("http-form-brute.onfailure")

   local _

+  method=method:upper()
+  if not (method=="GET" or method=="POST") then
+    return stdnse.format_output(false, "Invalid HTTP method: " .. method)
+  end
+
   -- if now fields were given attempt to autodetect
   if ( not(uservar) and not(passvar) ) then
     uservar, passvar = detectFormFields( host, port, path )
@@ -198,39 +215,38 @@

   -- uservar is optional, so only make sure we have a passvar
   if ( not( passvar ) ) then
-    return "\n  ERROR: No passvar was specified (see
http-form-brute.passvar)"
-  end
-
-  if ( not(path) ) then
-    return "\n  ERROR: No path was specified (see http-form-brute.path)"
+    return stdnse.format_output(false, "No passvar was specified (see
http-form-brute.passvar)")
   end

   if ( onsuccess and onfailure ) then
-    return "\n  ERROR: Either the onsuccess or onfailure argument should
be passed, not both."
+    return stdnse.format_output(false, "Either the onsuccess or onfailure
argument should be passed, not both.")
   end

-  local options = { [passvar] = "this_is_not_a_valid_password" }
-  if ( uservar ) then options[uservar] = "this_is_not_a_valid_user" end
+  local params = { [passvar] = "this_is_not_a_valid_password" }
+  if ( uservar ) then params[uservar] = "this_is_not_a_valid_user" end

-  local response = Driver.postRequest( host, port, path, options )
+  local response = Driver.sendLogin( host, port, path, method, params )
   if ( not(response) or not(response.body) or response.status ~= 200 )
then
-    return ("\n  ERROR: Failed to retrieve path (%s) from
server"):format(path)
+    return stdnse.format_output(false, ("Failed to retrieve path (%s)
from server"):format(path))
   end

   -- try to detect onfailure match
   if ( onfailure and not(response.body:match(onfailure)) ) then
-    return ("\n  ERROR: Failed to match password failure message
(%s)"):format(onfailure)
+    return stdnse.format_output(false, ("Failed to match password failure
message (%s)"):format(onfailure))
   elseif ( not(onfailure) and
       not(onsuccess) and

 not(response.body:match("input.-type=[\"]*[Pp][Aa][Ss][Ss][Ww][Oo][Rr][Dd][\"]*"))
) then
-    return ("\n  ERROR: Failed to detect password form field see
(http-form-brute.onsuccess or http-form-brute.onfailure)")
+    return stdnse.format_output(false, ("Failed to detect password form
field see (http-form-brute.onsuccess or http-form-brute.onfailure)"))
   end

-  local engine = brute.Engine:new( Driver, host, port, {
-    uservar = uservar, passvar = passvar,
-    path = path, onsuccess = onsuccess, onfailure = onfailure
-  }
-  )
+  local engine = brute.Engine:new(Driver, host, port, {
+                                                      path = path,
+                                                      method = method,
+                                                      uservar = uservar,
+                                                      passvar = passvar,
+                                                      onsuccess =
onsuccess,
+                                                      onfailure =
onfailure
+                                                      })
   -- there's a bug in http.lua that does not allow it to be called by
   -- multiple threads
   engine:setMaxThreads(1)
_______________________________________________
Sent through the dev mailing list
http://nmap.org/mailman/listinfo/dev
Archived at http://seclists.org/nmap-dev/

_______________________________________________
Sent through the dev mailing list
http://nmap.org/mailman/listinfo/dev
Archived at http://seclists.org/nmap-dev/


Current thread: