Lucene search
+L

Command Path Injection

🗓️ 14 Sep 2026 00:00:00Reported by TenableType 
nessus
 nessus
🔗 www.tenable.com👁 67 Views

Scanner detects PATH-based command injection enabling local privilege escalation or host takeover.

Code
#TRUSTED 8093d09f93316289b632a3c7139e64c24e6170bf2ea8c5f2c22befe69be63f7988b363a6db46e8a6bf43b03ea37c4721c14b7cc03dccf262bbcab2f03dead76ca5c8b35d5ba79bcdfc603b561e34daaf93f0a0cdd63dbee948d02d4423a0f69a397bba68edaf801ab259c8a4cb4a715a0e28971fa0efe2175790b922628bb0e7b70151641e779a0841dccea680808971f759850b11306f56a11ed6ebae2f0e992f5eff197d41e0591b4b08577c8620268cc5c01e65d2cbc64b25adfc430d94a6e3f9f2fd1efcf0d09e253654551cfe88389fe7269b59938e481f1a481c4bc38160381d92d23eeacb14c52d86a6b445d81be5df2c571657ea4b5ff777be01128948e3c8789c9112e6e91d880ce5c0482ceb4a51e7bd07e6f6595494d8bd47ad16087238765d4df2a3af7485328e8e92fcbc2bc8ba2ebb746a7ab664c5f0216af09c7d60a894416a1e976b5d95e6514fda230e0a8c39367122f33c98e7d497709e5731192ed48f99e65b2bc1e04c3d14665dae67d9d8ea3137afba996b40b8a0486a335b73ee5b04a3b54e8d3bad8f152a069bf9dfc2c655e2ee6c232368388348088d5ec7c0cf31c8f4357d96936c0951b4572f501a1de4280c4740ecb6b7b2ffb280c0e74f1f8e1449e09357c4e6d8c7cf458e39ce9b7478653b1f69a2a07e60f4dc397a1d8e7411ea40ae72c2171c7fc5aadec49e30a287da87b31cf49ac475
#TRUST-RSA-SHA256 10ad016e01738112ae21452e2c971ae98969865ad0d4cd902d67fb351d9b2956e507a9020d5df906e1db4c04d666df873409a085bd2819f0761da16ad0fbf16b015203b2d0b441767ff667f5d25be0be5f09b0fdce0293c6df16d6ade1a52765cb6d9d4701778b0f50b434a602b5aca092511cf5a0fc5e69d94d04c9aea6dfba4c9cda80aadff0c72537f6523ee74c3e22cdb5ab924b1ea342c4129ead1cf6a7e736b67560b98c4a2d771136161aa679dceb98204399a16fc8cc8f5975d4b84328d818ca2ae505c6d3b7792bd39e8d80f2eb1d6ff1a50bb909df748b9513e16990e523d7a8a7f28f6f8153dd3edf404a9010340ae6a6cc0ebfe35696bb0dd722c72f4e7680b5298b5d99ecc148761cf493dfc3ce4157f3948403997fad49c706e74ec4a9e6511bfa64435edbe752b9a93d626c5b23098a7835cef612cbaa19ffb4b62801a8a3fcbd6824a571f07a4526c3bdbd1332549b2bb1aae49cfdbff46c0c938031b2728afc2f500111a552cd1c6464d0af75a75a2c778531483508a03e5d1e247b70654dafa7c6d19289bf3413fa0e0d65a02460442117396315b70166334f17ae02df29c51781bcd0cff1ec0f5dbd461885cc113bb0dcd8a39e7cb9a1c88780b843a2a577f19f601637372b42d4318040b03005c6c20866b730337e81f76291c27195b330cb3f31aa757c6008433a79085a51ba6595eda97d2da8cd01
#%NASL_MIN_LEVEL 80900

##
# (C) Tenable, Inc.
##


include('compat.inc');

if(description)
{
  script_id(345664);
  script_version("1.1");
  script_set_attribute(attribute:"plugin_modification_date", value:"2026/09/14");

  script_name(english:"Command Path Injection");
  script_set_attribute(attribute:"synopsis", value:
"Finds environment paths that could enable a command injection attack.");
  script_set_attribute(attribute:"description", value:
"This plugin identifies PATH environment variables either at the
system or user level that could be leveraged by a local attacker for
path based command injection.

Path command injection happens when a PATH places user controlled
directories, relative paths or world writable directories ahead of
critical system directories.  A local low-privilege attacker can
then place malicious payloads with names matching system executables
in those locations and achieve privilege escalation and possibly
complete takeover of the target host.");

  script_set_attribute(attribute:"solution", value:
"Modify the target system's settings to move user controlled
directories, relative paths and world-writable directories to
a position after system controlled locations in the affected
PATH environment variable.");
  script_set_cvss_base_vector("CVSS2#AV:L/AC:L/Au:S/C:C/I:C/A:C");
  script_set_cvss3_base_vector("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H");
  script_set_attribute(attribute:"cvss_score_source", value:"manual");
  script_set_attribute(attribute:"cvss3_score_source", value:"manual");
  script_set_attribute(attribute:"cvss_score_rationale", value:"Tenable score based on exploit profile.");
  script_set_attribute(attribute:"cvss3_score_rationale", value:"Tenable score based on exploit profile.");

  script_set_attribute(attribute:"plugin_publication_date", value:"2026/09/14");
  script_set_attribute(attribute:"agent", value:"all");
  script_set_attribute(attribute:"plugin_type", value:"local");
  script_end_attributes();

  script_category(ACT_GATHER_INFO);
  script_family(english:"General");
  script_copyright(english:"This script is Copyright (C) 2026 and is owned by Tenable, Inc. or an Affiliate thereof.");

  script_dependencies("microsoft_windows_env_vars.nasl", "enumerate_nix_env_vars.nasl");
  script_require_keys("Host/env_vars/enumerated");

  exit(0);
}

include("ssh_lib.inc");
include("ssh_globals.inc");
include("smb_func.inc");
include("debug.inc");
include("structured_data_environment_variable.inc");

get_kb_item_or_exit("Host/env_vars/enumerated");

function get_linux_path_characteristics()
{
  var pattern = "^.(...)(...)(...)t?\.?\s+\d+\s+([^\s]+)\s+([^\s]+)";
  info_connect(exit_on_fail:TRUE);

  var path = _FCT_ANON_ARGS[0];
  var path_segs = split(path, sep:':', keep:false);
  var res, match;
  var path_chars = [];

  for(var seg of path_segs)
  {
    # Guard against ::
    if(empty_or_null(seg))
      continue;

    if(seg == "." || ".." >< seg)
    {
      append_element(var:path_chars, value:[seg, true]);
      continue;
    }

    # This will always happen because we directly parse scripts which have path segments like $PATH
    if(seg =~ INJECTION_PATTERN)
    {
      dbg::detailed_log(lvl:1, msg:'A PATH segment contains command injection characters. Ignoring.',
                        src:SCRIPT_NAME,
                        msg_details: {"path segment":{"lvl":2, "value":seg}});
      continue;
    }

    res = info_send_cmd(cmd:"ls -ldH " + seg);
    if(empty_or_null(res))
    {
      dbg::detailed_log(lvl:1, src:SCRIPT_NAME, msg:'Command execution failed.  Directory may not exist, continue.');
      continue;
    }

    match = pregmatch(string:res, pattern:pattern);
    if(isnull(match) || isnull(match[5]))
    {
      dbg::detailed_log(lvl:1, src:SCRIPT_NAME, msg:'Unexpected directory listing element, ignoring.');
      continue;
    }

    if(match[4] != "root" ||                         # Owner is not root
       (match[5] != "root" && 'w' >< match[2]) ||    # Directory is group writable by non-root group
       ('w' >< match[3]))                            # Directory is world writable
      append_element(var:path_chars, value:[seg, true]);
    else
      append_element(var:path_chars, value:[seg, false]);
  }

  if(info_t == INFO_SSH)
    ssh_close_connection();

  return path_chars;
}

function get_windows_path_characteristics()
{
  var name    =  kb_smb_name();
  var login   =  kb_smb_login();
  var pass    =  kb_smb_password();
  var domain  =  kb_smb_domain();
  var port    =  kb_smb_transport();

  # We are testing if a directory allows users with the following permissions to write
  var generic_builtins = [
    "^1-5-7$",                # ANONYMOUS
    "^1-1-0$",                # Everyone
    "^1-5-12$",               # Restricted
    "^1-5-21-\d+-501",        # Local guest
    "^1-5-21-\d+-514",        # Domain guest
    "^1-5-32-546$",           # GUEST built-in
    "^1-5-32-545$"            # Users
  ];

  if(!smb_session_init())
    audit(AUDIT_FN_FAIL, 'smb_session_init');

  var systemroot = hotfix_get_systemroot();
  if(empty_or_null(systemroot))
    audit(AUDIT_PATH_NOT_DETERMINED, "system root");

  var current_share = "";

  var path = _FCT_ANON_ARGS[0];
  var path_segs = split(path, sep:';', keep:false);
  var fh, sd, dacl, ace, sace, vuln, sid, drive, ret, realseg;
  var path_chars = [];
  for(var seg of path_segs)
  {
    # Guard against double ;;
    if(empty_or_null(seg))
      continue;

    if(seg == "." || ".." >< seg)
    {
      append_element(var:path_chars, value:[seg, true]);
      continue;
    }

    realseg = str_replace(string:tolower(seg), find:"%systemroot%", replace:systemroot);
    drive = hotfix_path2share(path:realseg);
    if(drive == realseg)
      drive = hotfix_path2share(path:systemroot);
    if(drive != current_share)
    {
      if(!empty_or_null(current_share))
        NetUseDel(close:false);

      current_share = drive;

      ret = NetUseAdd(login:login, password:pass, domain:domain, share:current_share);
      if(ret != 1)
      {
        NetUseDel(close:false);
        dbg::detailed_log(lvl:1, src:SCRIPT_NAME, msg:"Can't connect to the " + current_share + " share.");
        continue;
      }
    }

    realseg = ereg_replace(pattern:'^[A-Za-z]:(.*)', replace:"\1", string:realseg);

    fh = CreateFile(
           file:realseg,
           desired_access:GENERIC_READ,
           file_attributes:FILE_ATTRIBUTE_DIRECTORY,
           share_mode:FILE_SHARE_READ,
           create_disposition:OPEN_EXISTING
         );

    if(!fh)
    {
      # Assume failure to open because location is secure
      dbg::detailed_log(lvl:1, msg:"Could not open file. Counting PATH segment as secure.",
                        src:SCRIPT_NAME, msg_details:{"path segment":{"lvl":3, "value":seg}});
      append_element(var:path_chars, value:[seg, false]);
      continue;
    }

    sd = GetSecurityInfo(handle:fh, level:DACL_SECURITY_INFORMATION);
    if(isnull(sd))
    {
      # Assume failure to access security info is because location is secure
      append_element(var:path_chars, value:[seg, false]);
      CloseFile(handle:fh);
      continue;
    }

    dacl = sd[3];
    dacl = parse_pdacl(blob:dacl);
    if(isnull(dacl))
    {
      dbg::detailed_log(lvl:1, src:SCRIPT_NAME, msg:"Error parsing DACL. Counting PATH segment as vuln.");
      append_element(var:path_chars, value:[seg, true]);
      CloseFile(handle:fh);
      continue;
    }

    vuln = false;

    for(ace of dacl)
    {
      ace = parse_dacl(blob:ace);
      if(isnull(ace))
        continue;

      sace = sid2string(sid:ace[1]);
      if(isnull(sace))
      {
        dbg::detailed_log(lvl:1, src:SCRIPT_NAME, msg:"Error parsing ACE.");
        continue;
      }

      for(sid of generic_builtins)
      {
        if(sace =~ sid && ace[3] == ACCESS_ALLOWED_ACE_TYPE &&
           (ace[0] & FILE_WRITE_DATA) == FILE_WRITE_DATA)
        {
          vuln = true;
          break;
        }
      }

      if(vuln)
        break;
    }
    append_element(var:path_chars, value:[seg, vuln]);
    CloseFile(handle:fh);
  }

  NetUseDel();

  return path_chars;
}

function evaluate_path()
{
  var path = _FCT_ANON_ARGS[0];
  if(empty_or_null(path))
  {
    dbg::detailed_log(lvl:1, src:SCRIPT_NAME, msg:"Unexpected: The anonymous path argument was empty.");
    return "";
  }

  var platform = _FCT_ANON_ARGS[1];
  var path_elem_characteristics;
  var report = "";

  if(platform == "LINUX")
  {
    path_elem_characteristics = get_linux_path_characteristics(path["value"]);
  }
  else if(platform == "WINDOWS")
  {
    path_elem_characteristics = get_windows_path_characteristics(path["value"]);
  }
  else
  {
    dbg::detailed_log(
      lvl:1, src:SCRIPT_NAME,
      msg:"Unexpected: The environment variable observation context for this host was not WINDOWS or LINUX."
    );
    return "";
  }

  if(empty_or_null(path_elem_characteristics))
  {
    dbg::detailed_log(lvl:1, src:SCRIPT_NAME, msg:"No path characteristics were returned.");
    return "";
  }

  var vuln_seen = NULL;
  for(var pchar of path_elem_characteristics)
  {
    if(!pchar[1])
    {
      if(!isnull(vuln_seen))
      {
        report += strcat(vuln_seen[0], " defined at " + path["source_path"] + " owned by ", path["user"], '\n');
        break;
      }
    }
    else
    {
      vuln_seen = pchar;
    }
  }

  return report;
}

var host_env = get_discovered_environment_variables();
var host_env_vars = host_env["variables"];
var platform = host_env["observation_scope"];

if(empty_or_null(host_env_vars))
  audit(AUDIT_HOST_NONE, "environment variables");

var report, name;

for(var ev of host_env_vars)
{
  name = ev["name"];
  if(!empty_or_null(name) && name == "PATH")
    report += evaluate_path(ev, platform);
}

if(empty_or_null(report))
  audit(AUDIT_NOT_DETECT, "A path based command injection vulnerability");

security_report_v4(port:0, severity:SECURITY_HOLE, extra:report);

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation