Lucene search
K

Target Cipher Inventory

🗓️ 08 Dec 2025 00:00:00Reported by TenableType 
nessus
 nessus
🔗 www.tenable.com👁 4 Views

This plugin collects cryptographic ciphers and algorithms found during the scan into a machine parsable JSON file.

Refs
Code
#TRUSTED 391f29cf453bbf594379bea3b15edbcc5463418065e73eb13b61e0198b7819ce05bbf975e80e574482342db765a3a79c250c9c8d55de85c382bc4788d5c6030941ad2418fed7657b5586deba9fc55eac23a1a06284a4ac9d82785f62267ab5e3302259c711a5b9d0b0be9baedb651c34663aed36afad5153b10bf8485f3dfa9c0897abd3fd3b6bfccea4b9ebb6c14f07694e90cdcdfa44c7c087e14ea9021df953aab1f250be7802790188ec100361d0e8f1a0ec95c7535236df279f185fb61f230032e2fc9222979434a321de6b7c6e7598185102d32c60cb2a85e8e173649c429ee41b6fd36da80b73ed6b01c7f00176d926f8eea8c3c73bdd445f2ec9e412c2b03b1f4855f80d68f029dbf990c0e0f852a7f350c95d54bcbc6dfc01a2e5de0cdee26c00b89566425f9104bb3d721be1274be46694c29905d18fadd86c421e10d2b6b0812d686dbe29f549d827873a03c68914e618c2f8ea71b982bbd61178561e2ed00653a70d4c4291d36efbf9f7f880afbd00dc777103306a28e20932bc3fcdefced28031858670f09214af072fbb59b06bd791cf914c993cd6ee5814a76c39aa7eb2f0a292986024b1d1a15412d3e1782d2f433a3747b5f69c60082afce1a3d060f1e714f1a4a01a46e2bca2177fd8796587f04741d88a76858de06eccd3ad540717c9f5422e2a19906e55dcbd821d27d97a8f2b0fec934ce3b5ffe267
#TRUST-RSA-SHA256 6cb698555bbe551cbf977ff293b5871865302ba937b05102838f9f760b210ec3e01b066b4803c4118ba5a888493816a458a8422554924aa59ca260f688d950c6de0650bed97a1c3ccef3b1780057df6179ce3efc39b64192d6f2f86c47f87b6fa56376f10dec98e8d0674dd79983d490ddaf41394e7e23ca1ec068276dbdf601734ec1caaf0a42c4103389e2fc6b1f419e30713fec66b42c5ee7e9a91255e15fc162486474d41ee43f06c812205885cbcb04c120ef6f6fd4daa68b30dde2f18e0ed67d813f6a45ccb8a037a999f7d4eef84ba5651e4add3f3e78adc4dc358ad9f34c458658ca82c97fdc4d08360c27210d9ef8b0facdddd64883521f2387af3b34c8bd15b3bd4fd1ce1b5715498b20d1857ef5d107912aef8de7a17818230d0d1693876dfa0a041a15a98cfc766cf6265a67b24e91709589148b65b1881082e32cde4c75712289662679b65b07aa59f533dfb9f9a89b50c2b2ddb70239ce79db5fb0094f80cd2575b9024c576b36793b908c6ab3fe55f6050fe79e5782d072786dd6c2bf413148d3b54c1afc6038203410537c6a162ddba9c373bc4ac1bd91bb396bc5a4ab07c3b3b99a122b602d2b0a2d8a455a1c17d3cb3f9302e3d251cd72d7738b1b7a01bc768dc685cf1e5233044b851bf0d1238f87eb6768e71257eedee5d5612f8dfe8bc694aea5278fbcd00542c12c7f21e02abc7f5090dc381f0951
#%NASL_MIN_LEVEL 80900
#TRUST-RSA-SHA256
#
# (C) Tenable Network Security, Inc.
#

include('compat.inc');

if (description)
{
  script_id(277652);
  script_version("1.5");
  script_set_attribute(attribute:"plugin_modification_date", value:"2026/04/13");

  script_name(english:"Target Cipher Inventory");

  script_set_attribute(attribute:"synopsis", value:
"Reports the ciphers and algorithms discovered during the scan.");
  script_set_attribute(attribute:"description", value:
"This plugin collects cryptographic ciphers and algorithms discovered
during the scan as a machine parsable JSON file attachment.");

  script_set_attribute(attribute:"solution", value:"n/a");
  script_set_attribute(attribute:"risk_factor", value:"None");
  # https://www.nist.gov/news-events/news/2024/08/nist-releases-first-3-finalized-post-quantum-encryption-standards
  script_set_attribute(attribute:"see_also", value:"http://www.nessus.org/u?7a390f87");
  # https://www.ietf.org/archive/id/draft-kwiatkowski-pquip-pqc-migration-00.html
  script_set_attribute(attribute:"see_also", value:"http://www.nessus.org/u?ad7d6b3b");
  # https://www.rd.ntt/e/research/JN202305_21871.html
  script_set_attribute(attribute:"see_also", value:"http://www.nessus.org/u?1c0c61e0");
  # https://ntruprime.cr.yp.to/ntruprime-20170816.pdf
  script_set_attribute(attribute:"see_also", value:"http://www.nessus.org/u?5eec4b28");
  script_set_attribute(attribute:"plugin_publication_date", value:"2025/12/08");

  script_set_attribute(attribute:"plugin_type", value:"remote");
  script_end_attributes();

  script_category(ACT_GATHER_INFO);
  script_family(english:"General");

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

  script_dependencies("ssh_supported_algorithms.nasl", "tls_supported_groups.nasl",
                      "x509_signature_algos.nasl", "ssl_supported_ciphers.nasl");
  script_require_ports("SSL/Supported", "TLS/supported_groups", "X509/signature_algos", "SSH/server_algos");

  exit(0);
}

include("structured_data.inc");
include("ssl_funcs.inc");

var do_cipher_inventory = get_preference("collect_crypto_inventory");

if(isnull(do_cipher_inventory) || do_cipher_inventory != "yes")
  do_cipher_inventory = false;

var cipher_inventory = [];

if(!get_kb_item("SSL/Supported") && !get_kb_item("TLS/supported_groups") && !get_kb_item("X509/signature_algos") &&
   !get_kb_item("SSH/server_algos"))
  exit(1, "None of the required KBs are set.");

##
# Reads ciphers stored in KB entries for a given protocol and adds them to
# the plugin cipher inventory report and to an instance of the given structured data
# type.  Callbacks also decide whether a processed cipher is a post-quantum
# cipher and perform an action based on that determination.
#
# @param [kb_glob:string] A glob for extracting KB items representing ciphers for a protocol.
# @param [sd_obj_name:string] The type name of a structured data object for reporting ciphers.
# @param [proto_inventory_function:function] A function that collects ciphers for a protocol.
# @param [unique_port_fn:function] Extracts a list of unique ports from the supplied KB glob results.
# @param [pqc_eval_fn:function] Determines whether a cipher is a post-quantum or not.
# @param [pqc_action_fn:function] An action to perform if a cipher is post-quantum.
# @param [protocol:string] A protocol name or abbreviation.
# @param [cipher_inventory: A list of discovered ciphers to report in this plugin.
##
function make_inventory(kb_glob, sd_obj_name, proto_inventory_fn,
                        unique_port_fn, pqc_eval_fn, pqc_action_fn,
                        protocol, &cipher_inventory)
{
  var kb, port, port_entry, pqc_algo, report_ciphers, sd;
  var pqc_ret;

  var kbs = get_kb_list(kb_glob);
  if(isnull(kbs))
    return;

  var ports = {};
  var cipher_array = [];
  var unique_ports = {};
  var structured_data = {};
  var sd_cipher_arr, sd_cipher;

  for(kb in kbs)
  {
    port = unique_port_fn(kb:kb);
    if(!isnull(port))
      unique_ports[port] = 1;
  }

  for(port in unique_ports)
  {
    port_entry = {};
    if(isnull(structured_data[port]) && do_cipher_inventory)
      structured_data[port] = new(sd_obj_name, port, "tcp");

    sd_cipher_arr = proto_inventory_fn(port:port, structured_data:structured_data);
    if(empty_or_null(ref:sd_cipher_arr))
      continue;

    pqc_algo = false;

    # Evaluate each cipher
    report_ciphers = {};
    for(sd_cipher of sd_cipher_arr)
    {
      if(pqc_eval_fn(sd_cipher:sd_cipher, report_ciphers:report_ciphers))
        pqc_algo = true;
    }

    port_entry.port = port;
    port_entry.ciphers = sd_cipher_arr;
    append_element(var:cipher_array, value:port_entry);

    pqc_action_fn(port:port, report_ciphers:report_ciphers, is_pqc:pqc_algo);
  }

  ports.proto = protocol;
  ports.ports = cipher_array;
  if(!empty_or_null(ref:cipher_array))
  {
    append_element(var:cipher_inventory, value:ports);

    if(do_cipher_inventory)
    {
      for(sd in structured_data)
        structured_data[sd].report_internal();
    }
  }
}

# TLS
function tls_inventory(port, &structured_data)
{
  var supported_group, supported_groups, info, sd_cipher;
  var cipher_name, sig_scheme;
  var kb_cipher, kb_ciphers, proto, proto_name;
  var tls_sd_cipher_arr = [];
  var protos =  get_kb_list("SSL/Transport/" + port);

  for(proto of protos)
  {
    proto_name = ENCAPS_NAMES[proto];
    kb_ciphers = get_kb_list("SSL/Ciphers/" + port + "/" + proto_name);
    for(kb_cipher of kb_ciphers)
    {
      supported_groups = get_kb_list("TLS/supported_groups/" + port + "/" + proto_name + "/" + kb_cipher);
      info = split(ciphers_desc[kb_cipher], sep:'|', keep:FALSE);
      cipher_name = preg_replace(string:kb_cipher, pattern:"^(TLS)\d+(.*$)", replace:"\1\2");

      if(!empty_or_null(ref:supported_groups))
      {
        for(supported_group of supported_groups)
        {
          sig_scheme = get_one_kb_item("TLS/signature_schemes/" + port + "/" + proto_name + "/" + kb_cipher);

          sd_cipher = {};
          sd_cipher.ciphersuite = cipher_name;
          sd_cipher.encaps = proto_name;

          if(info[2] == "-")
          {
            if("ffdhe" >< supported_group)
              sd_cipher.key_exchange = "DHE";
            else
              sd_cipher.key_exchange = "ECDHE";

            if(is_pqc_group(group:supported_group))
              sd_cipher.key_exchange = supported_group;
            else
              sd_cipher.named_group = supported_group;
          }
          else
          {
            sd_cipher.key_exchange = info[2];
            sd_cipher.named_group = supported_group;
          }

          if(!isnull(sig_scheme))
            sd_cipher.signature_scheme = sig_scheme;

          if(do_cipher_inventory)
            structured_data[port].append("ciphers", sd_cipher);
          append_element(var:tls_sd_cipher_arr, value:sd_cipher);
        }
      }
      else
      {
        sd_cipher = {};
        sd_cipher.ciphersuite = cipher_name;
        sd_cipher.key_exchange = info[2];
        sd_cipher.encaps = proto_name;

        if(do_cipher_inventory)
          structured_data[port].append("ciphers", sd_cipher);
        append_element(var:tls_sd_cipher_arr, value:sd_cipher);
      }
    }
  }
  return tls_sd_cipher_arr;
}

function tls_port(kb)
{
  var kb_parts = split(kb, sep:"/", keep:FALSE);
  return kb_parts[2];
}

function tls_is_pqc(sd_cipher, &report_ciphers)
{
  var is_pqc = false;
  if(isnull(sd_cipher))
    return false;

  if(is_pqc_group(group:sd_cipher.key_exchange))
  {
    if(empty_or_null(report_ciphers["KEX"]))
      report_ciphers["KEX"] = {};
    report_ciphers["KEX"][sd_cipher.key_exchange] = 1;
    is_pqc= true;
  }

  return is_pqc;
}

function tls_pqc_action(port, report_ciphers, is_pqc)
{
  if(is_pqc && !empty_or_null(ref:report_ciphers))
    replace_kb_item(name:"Host/PQC/" + port + "/TLS/hardened", value:serialize(report_ciphers));
  else
    replace_kb_item(name:"Host/PQC/" + port + "/TLS/vulnerable", value:1);
}

make_inventory(
  kb_glob:"SSL/Ciphers/*",
  sd_obj_name:"structured_data_tls_cipher_inventory",
  proto_inventory_fn:@tls_inventory,
  unique_port_fn:@tls_port,
  pqc_eval_fn:@tls_is_pqc,
  pqc_action_fn:@tls_pqc_action,
  protocol:"TLS",
  cipher_inventory:cipher_inventory
);

# X509
function x509_inventory(port, &structured_data)
{
  var x509_sd_cipher_arr = [];
  var x509_sd_cipher;
  var x509_sig = get_one_kb_item("X509/signature_algo/" + port);
  var x509_subject = get_one_kb_item("Transport/SSL/" + port + "/subject");
  if(!isnull(x509_sig) && !isnull(x509_subject))
  {
    x509_sd_cipher.subject = x509_subject;
    x509_sd_cipher.signature = x509_sig;

    if(do_cipher_inventory)
      structured_data[port].append("ciphers", x509_sd_cipher);

    append_element(var:x509_sd_cipher_arr, value:x509_sd_cipher);
  }

  return x509_sd_cipher_arr;
}

function x509_port(kb)
{
  return kb - "X509/signature_algo/";
}

function x509_is_pqc(sd_cipher, &report_ciphers)
{
  var is_pqc = false;
  if(isnull(sd_cipher))
    return false;

  if("ML-DSA" >< sd_cipher.signature || "SLH-DSA" >< sd_cipher.signature)
  {
    if(empty_or_null(report_ciphers["SIG"]))
      report_ciphers["SIG"] = {};
    report_ciphers["SIG"][sd_cipher.signature] = 1;

    is_pqc = true;
  }

  return is_pqc;
}

function x509_pqc_action(port, report_ciphers, is_pqc)
{
  var old_report_ciphers, sig_cipher;

  if(is_pqc && !empty_or_null(ref:report_ciphers))
  {
    if(!isnull(get_one_kb_item("Host/PQC/" + port + "/TLS/vulnerable")))
      rm_kb_item(name:"Host/PQC/" + port + "/TLS/vulnerable");

    if(!isnull(get_one_kb_item("Host/PQC/" + port + "/TLS/hardened")))
      old_report_ciphers = deserialize(get_one_kb_item("Host/PQC/" + port + "/TLS/hardened"));
    else
      old_report_ciphers = {};

    if(empty_or_null(old_report_ciphers["SIG"]))
      old_report_ciphers["SIG"] = {};

    for(sig_cipher in report_ciphers["SIG"])
      old_report_ciphers["SIG"][sig_cipher] = 1;

    replace_kb_item(name:"Host/PQC/" + port + "/TLS/hardened", value:serialize(old_report_ciphers));
  }
}

make_inventory(
  kb_glob:"X509/signature_algo/*",
  sd_obj_name:"structured_data_x509_signature_algorithm_inventory",
  proto_inventory_fn:@x509_inventory,
  unique_port_fn:@x509_port,
  pqc_eval_fn:@x509_is_pqc,
  pqc_action_fn:@x509_pqc_action,
  protocol:"X509",
  cipher_inventory:cipher_inventory
);

# SSH
function ssh_cipher_type(port, alg_type, alg_kb_name, &cipher_arr, &structured_data)
{
  var kb_cipher, sd_cipher;
  var kb_ciphers = get_one_kb_item("SSH/" + port + "/" + alg_kb_name + "/kex_recv_namelists");
  var kb_cipher_list = split(kb_ciphers, sep:",", keep:false);
  var cipher_dict = {};

  for(kb_cipher of kb_cipher_list)
    cipher_dict[kb_cipher] = 1;

  for(kb_cipher in cipher_dict)
  {
    sd_cipher = {};
    sd_cipher.type = alg_type;
    sd_cipher.name = kb_cipher;

    append_element(var:cipher_arr, value:sd_cipher);
    if(do_cipher_inventory)
      structured_data[port].append("ciphers", sd_cipher);
  }
}

function ssh_inventory(port, &structured_data)
{
  var sd_cipher_arr = [];

  ssh_cipher_type(port:port, alg_type:"key exchange", alg_kb_name:"kex_algorithms",
                 cipher_arr:sd_cipher_arr, structured_data:structured_data);

  ssh_cipher_type(port:port, alg_type:"host auth", alg_kb_name:"server_host_key_algorithms",
                 cipher_arr:sd_cipher_arr, structured_data:structured_data);

  ssh_cipher_type(port:port, alg_type:"encryption", alg_kb_name:"encryption_algorithms_*",
                 cipher_arr:sd_cipher_arr, structured_data:structured_data);

  ssh_cipher_type(port:port, alg_type:"message auth", alg_kb_name:"mac_algorithms_*",
                 cipher_arr:sd_cipher_arr, structured_data:structured_data);

  return sd_cipher_arr;
}

function ssh_port(kb)
{
  return preg_replace(string:kb, pattern:"^SSH/(\d+)/.*$", replace:"\1");
}

function ssh_is_pqc(sd_cipher, &report_ciphers)
{
  var is_pqc = false;
  if(sd_cipher.type == "key exchange" && ("mlkem" >< sd_cipher.name || "sntrup" >< sd_cipher.name))
  {
    if(empty_or_null(report_ciphers["KEX"]))
      report_ciphers["KEX"] = {};
    report_ciphers["KEX"][sd_cipher.name] = 1;
    is_pqc = true;
  }

  return is_pqc;
}

function ssh_pqc_action(port, report_ciphers, is_pqc)
{
  if(is_pqc && !empty_or_null(ref:report_ciphers))
    replace_kb_item(name:"Host/PQC/" + port + "/SSH/hardened", value:serialize(report_ciphers));
  else
    replace_kb_item(name:"Host/PQC/" + port + "/SSH/vulnerable", value:1);
}

make_inventory(
  kb_glob:"SSH/*/kex_algorithms/kex_recv_namelists",
  sd_obj_name:"structured_data_ssh_cipher_inventory",
  proto_inventory_fn:@ssh_inventory,
  unique_port_fn:@ssh_port,
  pqc_eval_fn:@ssh_is_pqc,
  pqc_action_fn:@ssh_pqc_action,
  protocol:"SSH",
  cipher_inventory:cipher_inventory
);

if(do_cipher_inventory != "yes")
  exit(0, "Cipher inventory disabled by scan policy preference.");

# Protect scanner from injection with bogus hostname
var display_options = SERIALIZE_JSON | SERIALIZE_FORMAT;
security_report_v4(port:0, severity:SECURITY_NOTE, extra:serialize(cipher_inventory, indent:"  ", options:display_options));

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

13 Apr 2026 00:00Current
5.8Medium risk
Vulners AI Score5.8
4