Lucene search

K
nmapRiccardo CecolinNMAP:HTTP-CONFIG-BACKUP.NSE
HistoryMar 06, 2012 - 5:51 p.m.

http-config-backup NSE Script

2012-03-0617:51:26
Riccardo Cecolin
nmap.org
247

9.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

10 High

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

COMPLETE

Integrity Impact

COMPLETE

Availability Impact

COMPLETE

AV:N/AC:L/Au:N/C:C/I:C/A:C

0.973 High

EPSS

Percentile

99.8%

Checks for backups and swap files of common content management system and web server configuration files.

When web server files are edited in place, the text editor can leave backup or swap files in a place where the web server can serve them. The script checks for these files:

  • wp-config.php: WordPress
  • config.php: phpBB, ExpressionEngine
  • configuration.php: Joomla
  • LocalSettings.php: MediaWiki
  • /mediawiki/LocalSettings.php: MediaWiki
  • mt-config.cgi: Movable Type
  • mt-static/mt-config.cgi: Movable Type
  • settings.php: Drupal
  • .htaccess: Apache

And for each of these file applies the following transformations (using config.php as an example):

  • config.bak: Generic backup.
  • config.php.bak: Generic backup.
  • config.php~: Vim, Gedit.
  • #config.php#: Emacs.
  • config copy.php: Mac OS copy.
  • Copy of config.php: Windows copy.
  • config.php.save: GNU Nano.
  • .config.php.swp: Vim swap.
  • config.php.swp: Vim swap.
  • config.php.old: Generic backup.

This script is inspired by the CMSploit program by Feross Aboukhadijeh: <http://www.feross.org/cmsploit/&gt;.

Script Arguments

http-config-backup.save

directory to save all the valid config files found

http-config-backup.path

the path where the CMS is installed

slaxml.debug

See the documentation for the slaxml library.

smbdomain, smbhash, smbnoguest, smbpassword, smbtype, smbusername

See the documentation for the smbauth library.

http.host, http.max-body-size, http.max-cache-size, http.max-pipeline, http.pipeline, http.truncated-ok, http.useragent

See the documentation for the http library.

Example Usage

nmap --script=http-config-backup &lt;target&gt;

Script Output

PORT   STATE SERVICE REASON
80/tcp open  http    syn-ack
| http-config-backup:
|   /%23wp-config.php%23 HTTP/1.1 200 OK
|_  /config.php~ HTTP/1.1 200 OK

Requires


local coroutine = require "coroutine"
local http = require "http"
local io = require "io"
local shortport = require "shortport"
local stdnse = require "stdnse"
local string = require "string"
local table = require "table"
local url = require "url"

description = [[
Checks for backups and swap files of common content management system
and web server configuration files.

When web server files are edited in place, the text editor can leave
backup or swap files in a place where the web server can serve them. The
script checks for these files:

* <code>wp-config.php</code>: WordPress
* <code>config.php</code>: phpBB, ExpressionEngine
* <code>configuration.php</code>: Joomla
* <code>LocalSettings.php</code>: MediaWiki
* <code>/mediawiki/LocalSettings.php</code>: MediaWiki
* <code>mt-config.cgi</code>: Movable Type
* <code>mt-static/mt-config.cgi</code>: Movable Type
* <code>settings.php</code>: Drupal
* <code>.htaccess</code>: Apache

And for each of these file applies the following transformations (using
<code>config.php</code> as an example):

* <code>config.bak</code>: Generic backup.
* <code>config.php.bak</code>: Generic backup.
* <code>config.php~</code>: Vim, Gedit.
* <code>#config.php#</code>: Emacs.
* <code>config copy.php</code>: Mac OS copy.
* <code>Copy of config.php</code>: Windows copy.
* <code>config.php.save</code>: GNU Nano.
* <code>.config.php.swp</code>: Vim swap.
* <code>config.php.swp</code>: Vim swap.
* <code>config.php.old</code>: Generic backup.

This script is inspired by the CMSploit program by Feross Aboukhadijeh:
http://www.feross.org/cmsploit/.
]];

---
-- @usage
-- nmap --script=http-config-backup <target>
--
-- @output
-- PORT   STATE SERVICE REASON
-- 80/tcp open  http    syn-ack
-- | http-config-backup:
-- |   /%23wp-config.php%23 HTTP/1.1 200 OK
-- |_  /config.php~ HTTP/1.1 200 OK
--
-- @args http-config-backup.path the path where the CMS is installed
-- @args http-config-backup.save directory to save all the valid config files found
--

author = "Riccardo Cecolin";
license = "Same as Nmap--See https://nmap.org/book/man-legal.html";
categories = { "auth", "intrusive" };


portrule = shortport.http;

local function make_grep(pattern)
  return function(s)
    return string.match(s, pattern)
  end
end

local grep_php = make_grep("<%?php");
local grep_cgipath = make_grep("CGIPath");

local function check_htaccess(s)
  return string.match("<Files") or string.match(s, "RewriteRule")
end

local CONFIGS = {
  { filename = "wp-config.php", check = grep_php }, -- WordPress
  { filename = "config.php", check = grep_php }, -- phpBB, ExpressionEngine
  { filename = "configuration.php", check = grep_php }, -- Joomla
  { filename = "LocalSettings.php", check = grep_php }, -- MediaWiki
  { filename = "/mediawiki/LocalSettings.php", check = grep_php }, -- MediaWiki
  { filename = "mt-config.cgi", check = grep_cgipath }, -- Movable Type
  { filename = "mt-static/mt-config.cgi", check = grep_cgipath }, -- Movable Type
  { filename = "settings.php", check = grep_php }, -- Drupal
  { filename = ".htaccess", check = check_htaccess }, -- Apache
};

-- Return directory, filename pair. directory may be empty.
local function splitdir(path)
  local dir, filename

  dir, filename = string.match(path, "^(.*/)(.*)$")
  if not dir then
    dir = ""
    filename = path
  end

  return dir, filename
end

-- Return basename, extension pair. extension may be empty.
local function splitext(filename)
  local base, ext;

  base, ext = string.match(filename, "^(.+)(%..+)")
  if not base then
    base = filename
    ext = ""
  end

  return base, ext
end

-- Functions mangling filenames.
local TRANSFORMS = {
  function(fn)
    local base, ext = splitext(fn);
    if ext ~= "" then
      return base .. ".bak" -- generic bak file
    end
  end,
  function(fn) return fn .. ".bak" end,
  function(fn) return fn .. "~" end, -- vim, gedit
  function(fn) return "#" .. fn .. "#" end, -- Emacs
  function(fn)
    local base, ext = splitext(fn);
    return base .. " copy" .. ext -- mac copy
  end,
  function(fn) return "Copy of " .. fn end, -- windows copy
  function(fn) return fn .. ".save" end, -- nano
  function(fn) if string.sub(fn, 1, 1) ~= "." then return "." .. fn .. ".swp" end end, -- vim swap
  function(fn) return fn .. ".swp" end, -- vim swap
  function(fn) return fn .. ".old" end, -- generic backup
};

---
--Creates combinations of backup names for a given filename
--Taken from: http-backup-finder.nse
local function backupNames (filename)
  local dir, basename;

  dir, basename = splitdir(filename);
  return coroutine.wrap(function()
    for _, transform in ipairs(TRANSFORMS) do
      local result = transform(basename);

      if result == nil then
      elseif type(result) == "string" then
        coroutine.yield(dir .. result);
        result = {result}
      elseif type(result) == "table" then
        for _, r in ipairs(result) do
          coroutine.yield(dir .. r);
        end
      end
    end
  end)
end

---
--Writes string to file
--Taken from: hostmap.nse
-- @param filename Filename to write
-- @param contents Content of file
-- @return True if file was written successfully
local function write_file (filename, contents)
  local f, err = io.open(filename, "w");
  if not f then
    return f, err;
  end
  f:write(contents);
  f:close();
  return true;
end

action = function (host, port)
  local path = stdnse.get_script_args("http-config-backup.path") or "/";
  local save = stdnse.get_script_args("http-config-backup.save");

  local backups = {};

  if not path:match("/$") then
    path = path .. "/";
  end

  if not path:match("^/") then
    path = "/" .. path;
  end

  if (save and not(save:match("/$") ) ) then
    save = save .. "/";
  end

  local status_404, result_404, known_404 = http.identify_404(host, port)
  if not status_404 then
    stdnse.debug1("Can't distinguish 404 response. Quitting.")
    return stdnse.format_output(false, "Can't determine file existence")
  end

  -- for each config file
  for _, cfg in ipairs(CONFIGS) do
    -- for each alteration of the filename
    for entry in backupNames(cfg.filename) do
      local url_path

      url_path = url.build({path = path .. entry});

      -- http request
      local response = http.get(host, port, url_path);

      -- if it's not 200, don't bother. If it is, check that it's not a false 404
      if response.status == 200 and http.page_exists(response, result_404, known_404, url_path) then
        -- check it if is valid before inserting
        if cfg.check(response.body) then
          local filename = stdnse.escape_filename((host.targetname or host.ip) .. url_path)

          -- save the content
          if save then
            local status, err = write_file(save .. filename, response.body);
            if status then
              stdnse.debug1("%s saved", filename);
            else
              stdnse.debug1("error saving %s", err);
            end
          end

          table.insert(backups, url_path .. " " .. response["status-line"]);
        else
          stdnse.debug1("%s: found but not matching: %s",
            host.targetname or host.ip, url_path);
        end
      end
    end
  end

  return stdnse.format_output(true, backups);
end;

9.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

10 High

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

COMPLETE

Integrity Impact

COMPLETE

Availability Impact

COMPLETE

AV:N/AC:L/Au:N/C:C/I:C/A:C

0.973 High

EPSS

Percentile

99.8%

Related for NMAP:HTTP-CONFIG-BACKUP.NSE