Lucene search
K

Remote listeners enumeration (Linux / AIX)

🗓️ 16 May 2007 00:00:00Reported by TenableType 
nessus
 nessus
🔗 www.tenable.com👁 1045 Views

Remote listeners enumeration for Linux / AIX with identifiable proces

Code
#TRUSTED 8c1e58c49d58684cda2cbeb1051edc1db3cff6dbffe473a8d82b9412177b070fe76a4ff0c72e0e14cde834a4d48d9b7854f957face60b5fe220f34c07b4c0372375a9fde9959d32a7f5dd3cf77591b120e27feb73310cc83f8e64359b4c3dbb605e542fe2660cf6af2dfce2cf258d52e0e3aabcdd0a1a2851afb7444a443f73bc5dbb9bbcefb9f7a84d08d08ec2eb1d145e00fd210f756d7396aa039dfdad0e4e25e27622aea0462243f7a52a1510d2eddafc9acaf45bc7e1bebf2ba2773127bcfd4f994c985848ed2b4383f6ce8a5166b8a6e719809cd8694be8a6fc849800cc0ac4071b34bcf5417e0f042d59eb5e3be6ac9b1402d2e63974521a35ef96c2cc02b46a7e40ddefd04fa7fd34ded364e24909c0ab2d9d4a00782e3644838d91ddea5d0be85c493686a25217f9373b207b5d7360eff9e594863e1347731338b2f4255affcd3fee1a1b1dda70c5895bae425c5aa9d8a0dcd4fc4bd3ac87224e7caeaa332e8f55fbed7c72ec8f4014af26e330a37d1e88d49770c05d8b8783516b1c2b085c78ab8615ab0d122cf12b11baf55188c04eedd0829ad081c7411fedec2fa378cd4026e326e3efe3ca4abed1d3c0126607533236a4d2574211de964f646ecd17258d922165643308b88b1159f067864edae9b06bf4370f2485fda3b24588c512f0d3f0e2a9926d2b50f5bec4a07326931a98f2b630e7d99f85ebd7d8ed8
#TRUST-RSA-SHA256 4624575b351b9de3623c302d33eca4aa729538c275d6ef7aac834cdff19944550a5c95f050aafa99539078eff6b35923a7e1133da781ee2fdb6afbe9082ce894dd573d4eccfa6cf2019232d086a647db9ececb8906def2fc06d2d0f85280b9b8fca803dd76dc3644c8a7719eb15f5aa621942493110f9dd6ba4caa7b8f584a9d732f017245e8876c193b2964fed4b4a60be6dcb6501f371fd8f29b2fc57d58595a4b026c71ba53d3467419c63ccc1f1f17fc31c495897fb5928b2d9f9be9a290df2792236f1663893a8bdae60c576ae3933b5744671f265e4c00c63a9b55f0c586606197f59627c487aea2679df7d7230a40c1c123e7de71b8cdd2962dbe44ed3e8f02728d4a660e09414350d1178cadcdec6591bd8fe47df9629716b866f591a43d0630f55473e34bcbecc43311ee94a2a98a7d896d5569e6d5d05954072adf4000060fe6517d9ccebe91d57343937c1ed57321cc3afb7453f4a0d4295336dcdb9c6016f86df96e06018cf3985c52daff8fef5ca51d8d412625aba99fa43ae82777d3478d22689c88dd7e0524b51a66b5c33676679cfb0ab9ce93761869f6de8fd205b78a321425e76856a238583f5a52d5f6bbb4b0060ba0f0d12a636c481e2694b604ffc68d279c5b0c08ef32385082f4d2185fd875f36c097e6bfdf20a9c88c96585732c467861cecc93874e649e9315c9bf5c760b79bf19963ba892bfb8
#
# (C) Tenable Network Security, Inc.
#

include("compat.inc");

if (description)
{
 script_id(25221);
 script_version("1.30");
 script_set_attribute(attribute:"plugin_modification_date", value:"2026/05/21");

 script_name(english:"Remote listeners enumeration (Linux / AIX)");
 script_summary(english:"Finds the process listening on each port with netstat.");

 script_set_attribute(attribute:"synopsis", value:
"Using the supplied credentials, it was possible to identify the
process listening on the remote port.");
 script_set_attribute(attribute:"description", value:
"By logging into the remote host with the supplied credentials, Nessus
was able to obtain the name of the process listening on the remote
port.

Note that the method used by this plugin only works for hosts running
Linux or AIX.");
 script_set_attribute(attribute:"solution", value:"n/a");
 script_set_attribute(attribute:"risk_factor", value:"None");

 script_set_attribute(attribute:"plugin_publication_date", value:"2007/05/16");

 script_set_attribute(attribute:"plugin_type", value:"local");
 script_set_attribute(attribute:"agent", value:"unix");
 script_end_attributes();

 script_category(ACT_GATHER_INFO);
 script_family(english:"Service detection");

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

 script_dependencies("ssh_settings.nasl", "ssh_get_info.nasl");
 script_require_ports("Services/ssh", 22, "nessus/product/agent");
 script_require_keys("Host/uname");

 exit(0);
}

include("compat_shared.inc");
include("ssh_func.inc");
include("telnet_func.inc");
include("hostlevel_funcs.inc");
include("local_detection_nix.inc");
include("process_on_port_parser.inc");
include("command_builder.inc");

var cmdlines = make_array();
var cmdlines_enc = make_array();
var localaddrs = make_array();
var exes = make_array();
var pids = make_array();
var prelinked = make_array();
var md5s = make_array();

##
# Uses readlink, md5sum and cat to get executable, md5 and commandline of the target process
# @param pid PID of the target process
# @return An array containing {executable:string, commandline:string, b64_commandline:string}
# @remark This function can also write to md5s array if it finds a new broken executable link
##
function get_process_data(pid)
{
  if (pid <= 0) return NULL;
  
  var results = {};
  var exe = ldnix::run_cmd_template_wrapper(template:'LC_ALL=C readlink \'/proc/$1$/exe\' 2>/dev/null', args:[pid]);
  if (strlen(exe) > 0) exe = chomp(exe);
  results['executable'] = exe;

  # check md5sum of process image for further verification if needed  (used in daemons_with_broken_links.nasl)
  if(isnull(md5s[pid]) && preg(pattern:"^(.+) \(deleted\)$", string:exe))
  {
    var exe_md5sum = ldnix::run_cmd_template_wrapper(template:'LC_ALL=C md5sum \'/proc/$1$/exe\' 2>/dev/null', args:[pid]);
    var item = pregmatch(pattern:'^([a-zA-Z0-9]{32}) ', string: exe_md5sum);
    if(!isnull(item)) md5s[pid] = item[1];
  }

  var cmdline_pure = ldnix::run_cmd_template_wrapper(template:'LC_ALL=C cat \'/proc/$1$/cmdline\' 2>/dev/null', args:[pid]);
  
  var cmdline = join(split(cmdline_pure, sep:'\x00', keep:FALSE), sep:' ');
  var cmdline_enc = base64(str:cmdline_pure);
  results['commandline'] = cmdline;
  results['b64_commandline'] = cmdline_enc;

  return results;
}

##
# Parses nestat output from a qualifying host
# @param buf netstat -anp or ss -anp output from a host
# @param @line_parser A reference to function that parses either an ss or netstat output line
# @remark This function will fill cmdlines, localaddrs, exes, pids, prelinked and md5s global arrays
##
function fill_socket_data(buf, line_parser)
{
  var results, port, pid, socket, exe, process_info, cmdline, cmdline_enc;
  var lines = split(buf, keep:FALSE);
  foreach var line (lines)
  { 
    results = line_parser(line:line);
    
    if (isnull(results)) continue;
    
    port = results['port'];
    if (port < 0 || port > 65535) continue;
    proto = results['proto'];
    if (proto != "tcp" && proto != "udp") continue;

    socket = strcat(proto, '/', port);
    if (exes[socket]) continue;

    pid = results['pid'];
    process_info = get_process_data(pid:pid);
    if(isnull(process_info) || empty_or_null(process_info['executable'])) exe = results['executable'];
    else exe = process_info['executable'];
    if (strlen(exe) == 0) continue;

    localaddrs[socket] = results['address'];
    exes[socket] = exe;
    if (pid > 0) pids[socket] = pid;
    cmdline = process_info['commandline'];
    if (strlen(cmdline) > 0) cmdlines[socket] = cmdline;
    cmdline_enc = process_info['b64_commandline'];
    if (strlen(cmdline_enc) > 0) cmdlines_enc[socket] = cmdline_enc;
  }
}

var uname = get_kb_item_or_exit("Host/uname");
if (
  'Linux' >!< uname &&
  'AIX' >!< uname
) audit(AUDIT_HOST_NOT, "Linux / AIX");

enable_ssh_wrappers();
info_connect();

# nb: On Solaris, you can do this with a command like:
#
#     pfexec pfiles `ls /proc` 2>/dev/null | egrep '^[0-9]|port:'
#
#     The problem is that pfiles, as its man page warns, can cause a process
#     to stop while its being inspected by the tool, and that is to be
#     avoided in a production environment!

var buf, item, entry, netstat_cmd, ss_cmd, netstat_buf, ss_buf, errmsg;

if ("Linux" >< uname)
{
  buf = info_send_cmd(cmd:"prelink -p 2>/dev/null");
  # sanity check
  if('objects found in prelink cache' >< buf)
  {
    foreach entry (split(buf, sep:'\n', keep:FALSE))
    {
      # only interested in binaries, the code below
      # will filter out the libraries
      if(':' >< entry && entry !~ "\[0x[a-zA-Z0-9]+\]")
      {
        item = pregmatch(pattern:"^([^:]+):", string:entry);
        if(!isnull(item)) prelinked[item[1]] = TRUE;
      }
    }
  }

  netstat_cmd = "netstat -anp";
  ss_cmd = 'ss -anp';
  netstat_buf = ldnix::run_cmd_template_wrapper(template:"LC_ALL=C "+netstat_cmd);
  if (strlen(netstat_buf) == 0)
  {
    errmsg = ssh_cmd_error();
    if (errmsg) errmsg ='for the following reason :\n\n' + errmsg + '\n\n';
    else errmsg = 'for an unknown reason. ';
    errmsg = "Failed to run '" + netstat_cmd + "' " + errmsg;
    dbg::detailed_log(lvl:1, msg:errmsg);
  }
  if(!empty_or_null(netstat_buf))
  {
    set_kb_item(name:"Host/netstat_anp", value:netstat_buf);
    fill_socket_data(buf:netstat_buf, line_parser:@process_on_port_parser::parse_netstat_output_line);
  }
  else
  {
    ss_buf = ldnix::run_cmd_template_wrapper(template:"LC_ALL=C "+ss_cmd);
    if(strlen(ss_buf) == 0)
    {
      errmsg = ssh_cmd_error();
      if (errmsg) errmsg ='for the following reason :\n\n' + errmsg + '\n\n';
      else errmsg = 'for an unknown reason. ';
      errmsg = "Failed to run '" + ss_cmd + "' " + errmsg;
      dbg::detailed_log(lvl:1, msg:errmsg);
      
      if (info_t == INFO_SSH) ssh_close_connection();
      exit(1, "Both nestat and ss failed, see debug log for errors");
    }
  }
  if(!empty_or_null(ss_buf))
  {
    set_kb_item(name:"Host/ss_anp", value:ss_buf);
    fill_socket_data(buf:ss_buf, line_parser:@process_on_port_parser::parse_ss_output_line);
  }
}
# Suggested by Bernhard Thaler
#
# http://www-01.ibm.com/support/docview.wss?rs=71&uid=swg21264632
else if ("AIX" >< uname)
{
  var line, proto, port, v, v2, k, pcbaddr, pid, exe, cmd, cmdline;

  netstat_cmd = "netstat -Aan";
  buf = info_send_cmd(cmd:"LC_ALL=C "+netstat_cmd);
  if (strlen(buf) == 0)
  {
    errmsg = ssh_cmd_error();
    if (errmsg) errmsg ='for the following reason :\n\n' + errmsg + '\n\n';
    else errmsg = 'for an unknown reason. ';
    errmsg = "Failed to run '" + netstat_cmd + "' " + errmsg;
    if (info_t == INFO_SSH) ssh_close_connection();
    exit(1, errmsg);
  }
  set_kb_item(name:"Host/netstat_Aan", value:buf);

  foreach line (split(buf, keep:FALSE))
  {
    v = pregmatch(string:line, pattern:'^(f[a-f0-9]{15})[ \t]+((tcp|udp)[46]?)[ \t]+[0-9]+[ \t]+[0-9]+[ \t]+(\\*|[0-9]+\\.[0-9.]+\\.[0-9]+\\.[0-9]+)\\.([0-9]+)[ \t]+(\\*|[0-9]+\\.[0-9.]+\\.[0-9]+\\.[0-9]+)\\.[0-9*]+([ \t]+LISTEN)?$');
    if (isnull(v)) continue;

    port = int(v[5]);
    if (port < 0 || port > 65535) continue;

    proto = tolower(v[3]);
    if (proto != "tcp" && proto != "udp") continue;

    pcbaddr = v[1];

    exe = cmdline = '';

    cmd = "rmsock " + pcbaddr + " ";
    if (proto == "tcp") cmd += "tcpcb";
    else cmd += "inpcb";

    buf = info_send_cmd(cmd:"LC_ALL=C "+cmd + ' 2>/dev/null');
    if (strlen(buf) > 0)
    {
      buf = chomp(buf);
      v2 = pregmatch(string:buf, pattern:"The socket [^ ]+ is being held by proccess ([0-9]+)[ \t]+\(([^)]+)\)\.");
      if (!isnull(v2))
      {
        pid = int(v2[1]);
        exe = v2[2];

        cmd = "proctree " + pid;
        buf = info_send_cmd(cmd:"LC_ALL=C "+cmd+" 2>/dev/null");
        if (strlen(buf) > 0)
        {
          foreach line (split(buf, keep:FALSE))
          {
            v2 = pregmatch(pattern:'^[ \t]*'+pid+'[ \t]+([^ \t].+)$', string:line);
            if (!isnull(v2)) cmdline = v2[1];
          }
        }
      }
      else
      {
        v2 = pregmatch(string:buf, pattern:"The socket [^ ]+ is being held by Kernel/Kernel Extension\.");
        if (!isnull(v2))
        {
          pid = "n/a";
          exe = "[kernel/kernel extension]";
        }
      }
    }
    if (strlen(exe) == 0) continue;

    k = strcat(proto, '/', port);
    if (exes[k]) continue;

    localaddrs[k] = v[4];
    exes[k] = exe;
    if (pid > 0 || pid == "n/a") pids[k] = pid;
    if (strlen(cmdline) > 0) cmdlines[k] = cmdline;
  }
}
if (max_index(keys(exes)) == 0)
{
  if (info_t == INFO_SSH) ssh_close_connection();
  exit(0, "The host does not have any listening services.");
}

var found, ip, sanchk, cmdline_enc, localaddr, match, lead_slash, report;

found = 0;
ip = get_host_ip();

foreach k (sort(keys(exes)))
{
  v = pregmatch(pattern:"^(.+)/([0-9]+)$", string:k);
  if (isnull(v))
  {
    if (info_t == INFO_SSH) ssh_close_connection();
    exit(1, "Failed to parse protocol / port info for '"+k+"'.");
  }

  proto = v[1];
  port = v[2];

  exe = exes[k];
  localaddr = localaddrs[k];
  cmdline = cmdlines[k];
  cmdline_enc = cmdlines_enc[k];
  if (strlen(cmdline) == 0) cmdline = "n/a";
  if (strlen(cmdline_enc) == 0) cmdline_enc = "n/a";
  pid = pids[k];

  # Check exe for unexpected chars
  if (!command_builder::validate_no_injection_denylist(exe))
  {
    dbg::detailed_log(lvl:1, msg:'Continue due to injection attempt in listener',
        msg_details:{
          'listener':{'lvl':1, 'value':exe}
        }
    );
    continue;
  }

  set_kb_item(name:'Host/Daemons/'+localaddr+'/'+proto+'/'+port, value:exe);

  if (
    (
      TARGET_IS_IPV6 &&
      (localaddr == "::" || localaddr == ip)
    ) ||
    (
      !TARGET_IS_IPV6 &&
      (localaddr == '0.0.0.0' || localaddr == ip || localaddr == "::" || localaddr == "*")
    )
  )
  {
    set_kb_item(name: 'Host/Listeners/'+proto+'/'+port, value:exe);
    set_kb_item(name: 'Host/Listeners/'+proto+'/'+port+'/cmdline', value:cmdline_enc);
    set_kb_item(name: 'Host/Listeners/'+proto+'/'+port+'/pid', value:pid);

    found++;

    match = pregmatch(pattern:"^(.+) \(deleted\)$", string:exe);
    if (!isnull(match)) exe = match[1];

    if (exe[0] == '/') lead_slash = '';
    else lead_slash = '/';

    if(!isnull(md5s[pid]))
      replace_kb_item(name: 'Host/DaemonMD5s' + lead_slash + exe, value:md5s[pid]);

    # this is here so we only report on listening pre-linked daemons
    if(prelinked[exe])
    {
      # whitelist
      if(exe =~ "^[0-9A-Za-z_\-./]+$")
        buf = info_send_cmd(cmd:"prelink -y " + exe + " | md5sum");

      item = pregmatch(pattern:'^([a-zA-Z0-9]{32}) ', string: buf);
      if(!isnull(item))
        replace_kb_item(name: 'Host/PrelinkedDaemons' + lead_slash + exe, value:item[1]);
      else
        replace_kb_item(name: 'Host/PrelinkedDaemons' + lead_slash + exe, value:'md5_unknown');

    }
    report = '\n  Process ID   : ' + pid +
             '\n  Executable   : ' + exe;
    if (strlen(cmdline) > 0) report += '\n  Command line : ' + cmdline;
    report += '\n';
    if (COMMAND_LINE) report = '\n  Port         : ' + port + ' (' + proto + ')' + report;

    if (report_verbosity > 0) security_note(port:port, proto:proto, extra:report);
    else security_note(port:port, proto:proto);
  }
}
if (info_t == INFO_SSH) ssh_close_connection();
if (found) set_kb_item(name:"Host/Listeners/Check", value:netstat_cmd);

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

21 May 2026 00:00Current
5.8Medium risk
Vulners AI Score5.8
1045