Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Removing custom error page limitation from http-default-accounts #577

nnposter opened this issue Oct 30, 2016 · 0 comments

Removing custom error page limitation from http-default-accounts #577

nnposter opened this issue Oct 30, 2016 · 0 comments


Copy link

nnposter commented Oct 30, 2016

Script http-default-accounts currently has a limitation that prevents testing of systems returning status 200 for non-existent pages. This was largely inevitable up until r31899 (2013-08-17), when the target_check concept was introduced.

From the commit message:

Patch by nnposter that improves performance of http-default-accounts

For any given fingerprint from http-default-accounts-fingerprints script http-default-accounts currently tests corresponding default credentials if at least one of the probe URLs succeeded, namely returned with status other than 404.

Some web servers, such as Linksys devices, respond with HTTP/401 even for non-existent URLs. This causes the script to assume that these URLs do exist and to test the credentials, while ideally they should be tested only on those servers where they make sense.

The purpose of the attached patches is to reduce unnecessary credential guessing by implementing a new optional fingerprint element, function target_check(), which takes some already collected target information, including a probe URL response, and returns true or false, indicating whether the credential guessing should be attempted or not.


When testing against the above-mentioned Linksys the difference was notable: 14 login attempts before the patch versus 1 attempt after the patch.

This functionality provides opportunity for further improvement by being able to match page content to differentiate between real HTTP/200 and a custom error page. (As of now the script completely skips targets that return HTTP/200 for non-existent pages.)

The above-mentioned follow-up improvement is fairly straightforward: All fingerprints must have target_check(), either explicitly defined or an implicit one.

  local default_target_check =
    function (host, port, path, response)
      if status_404 and result_404 == 200 then return false end
      return http.page_exists(response, result_404, known_404, path, true)

As you can see, the default target_check effectively preserves the original script behavior, namely:

  • The target must not return HTTP/200 for non-existent pages.
  • The tested path must seem to exist.

The key difference is that these two conditions are no longer global (i.e. the target must meet them) but applicable only to fingerprints that do not know any better (by defining their own target_check).

@@ -231,12 +231,16 @@
   local basepath = stdnse.get_script_args("http-default-accounts.basepath") or 
   local output_lns = {}

-  -- Identify servers that answer 200 to invalid HTTP requests and exit as these would invalidate the tests
+  -- Determine the target's response to "404" HTTP requests.
   local status_404, result_404, known_404 = http.identify_404(host,port)
-  if ( status_404 and result_404 == 200 ) then
-    stdnse.debug1("Exiting due to ambiguous response from web server on %s:%s. All URIs return status 200.", host.ip, port.number)
-    return nil
-  end

@@ -276,6 +280,7 @@

   -- Iterate through responses to find a candidate for login routine
   for _, fingerprint in ipairs(fingerprints) do
+    local target_check = fingerprint.target_check or default_target_check
     local credentials_found = false
     stdnse.debug(1, "Processing %s",
     for _, probe in ipairs(fingerprint.paths) do
@@ -283,10 +288,7 @@
       if result and not credentials_found then
         local path = basepath .. probe['path']

-        if http.page_exists(result, result_404, known_404, path, true)
-          and (not fingerprint.target_check
-          or fingerprint.target_check(host, port, path, result))
-        then
+        if target_check(host, port, path, result) then
           for _, login_combo in ipairs(fingerprint.login_combos) do
             stdnse.debug(2, "Trying login combo -> %s:%s", login_combo["username"], login_combo["password"])
             --Check default credentials

The benefit of this change is that it is now possible to add many new fingerprints and to optimize the current ones.

suraj51k pushed a commit to suraj51k/nmap that referenced this issue Jan 31, 2017
…esting of systems returning status 200 for non-existent pages. Closes nmap#577
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
None yet
None yet

No branches or pull requests

1 participant