Lucene search
+L

Adobe Acrobat Detection

🗓️ 28 Aug 2009 00:00:00Reported by TenableType 
nessus
 nessus
🔗 www.tenable.com👁 47 Views

Adobe Acrobat PDF software installed on remote Windows host

Refs
Code
#%NASL_MIN_LEVEL 80900
##
# (C) Tenable, Inc.
##

include('compat.inc');

if (description)
{
  script_id(40797);
  script_version("1.38");
  script_set_attribute(attribute:"plugin_modification_date", value:"2026/08/17");

  script_xref(name:"IAVT", value:"0001-T-0512");

  script_name(english:"Adobe Acrobat Detection");

  script_set_attribute(attribute:"synopsis", value:
"Adobe Acrobat is installed on the remote Windows host.");
  script_set_attribute(attribute:"description", value:
"Adobe Acrobat, a PDF file creation and editing tool, is installed on
the remote Windows host.");
  script_set_attribute(attribute:"see_also", value:"https://acrobat.adobe.com/us/en/acrobat.html");
  script_set_attribute(attribute:"solution", value:"n/a");
  script_set_attribute(attribute:"risk_factor", value:"None");

  script_set_attribute(attribute:"plugin_publication_date", value:"2009/08/28");

  script_set_attribute(attribute:"plugin_type", value:"local");
  script_set_attribute(attribute:"cpe", value:"cpe:/a:adobe:acrobat");
  script_set_attribute(attribute:"asset_inventory", value:"True");
  script_set_attribute(attribute:"asset_inventory_category", value:"software_enumeration");
  script_set_attribute(attribute:"agent", value:"windows");
  script_end_attributes();

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

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

  script_dependencies("smb_hotfixes.nasl");
  script_require_keys("SMB/Registry/Enumerated");
  script_require_ports(139, 445);

  exit(0);
}

include('install_func.inc');
include('local_detection_win.inc');
include("universal_collection.inc");

get_kb_item_or_exit('SMB/Registry/Enumerated');

# Per-path registry metadata populated in collect(), consumed in main flow.
var _path_min = make_array();
var _path_max = make_array();
var _path_su1 = make_array();

# @collection-signature
var signature = {
  'Windows': {
    'UninstalledRegistry': [
      {
        'Signature': [
          { 'Name': { 'Regex': 'Adobe Acrobat(?! Reader| Plugin)' } }
        ]
      }
    ],
    'Files': [
      {
        'Signature': [
          { 'FilePath': { 'EndsWith': '\\Acrobat\\Acrobat.exe' } }
        ],
        'Get': {
          'PEVersion': [
            { 'Value': 'ProductVersionString', 'Label': 'Acrobat.exe ProductVersionString' }
          ]
        }
      }
    ]
  }
};

function collect()
{
  var collector = new universal_collection::collector();
  var uninst_sig_field, uninst_sig_operator, uninst_pattern;
  var file_sig_field, file_sig_operator, file_endswith, pev_block;

  # --- Phase 1: Uninstall registry discovery (signature-driven) ---
  uninst_sig_field    = 'Name';
  uninst_sig_operator = 'Regex';
  uninst_pattern      = NULL;

  foreach var uninst_entry (signature['Windows']['UninstalledRegistry'])
  {
    foreach var uninst_criteria (uninst_entry['Signature'])
    {
      uninst_pattern = uninst_criteria[uninst_sig_field][uninst_sig_operator];
      if (!isnull(uninst_pattern)) break;
    }
    if (!isnull(uninst_pattern)) break;
  }

  if (!isnull(uninst_pattern))
  {
    local_detection_win::registry::collect_uninstall_matches(
      collector:collector, display_name_pattern:uninst_pattern);
  }

  # --- Phase 2: Registry walk SOFTWARE\Adobe\Adobe Acrobat\* ---
  registry_init();
  var hklm = registry_hive_connect(hive:HKEY_LOCAL_MACHINE, exit_on_fail:TRUE);

  var base_key = "SOFTWARE\\Adobe\\Adobe Acrobat";
  var subkeys = get_registry_subkeys(handle:hklm, key:base_key);
  var key2, path, min, max, su1;

  foreach var subkey (subkeys)
  {
    if (!strlen(subkey) || (subkey !~ "^[0-9.]+$" && subkey != "DC"))
      continue;

    path = NULL;
    min  = NULL;
    max  = NULL;
    su1  = NULL;

    if (subkey !~ "^20\\d\\d$" && subkey != "DC")
      key2 = base_key + "\\" + subkey + "\\Installer";
    else
      key2 = base_key + "\\" + subkey + "\\InstallPath";

    var vmax = get_registry_value(handle:hklm, item:key2 + "\\VersionMax");
    if (!isnull(vmax)) max = int(vmax);

    var vmin = get_registry_value(handle:hklm, item:key2 + "\\VersionMin");
    if (!isnull(vmin)) min = int(vmin);

    var path_val = get_registry_value(handle:hklm, item:key2 + "\\Path");
    if (!isnull(path_val))
    {
      path = path_val;
      if (strlen(path) > 0 && path[strlen(path)-1] == "\")
        path = substr(path, 0, strlen(path)-2);
    }

    if (subkey =~ "^20\\d\\d$" || subkey == "DC")
    {
      var installer_key = base_key + "\\" + subkey + "\\Installer";
      var sca_level = get_registry_value(handle:hklm, item:installer_key + "\\SCAPackageLevel");

      if (!isnull(sca_level) && int(sca_level) == 1)
      {
        dbg::detailed_log(lvl:1, msg:'Installed product is Acrobat Reader (SCAPackageLevel=1), skipping subkey: ' + subkey);
        continue;
      }

      var default_val = get_registry_value(handle:hklm, item:key2 + "\\");
      if (!isnull(default_val) && strlen(default_val) > 8 &&
          default_val[strlen(default_val)-8] == '\\' &&
          tolower(substr(default_val, strlen(default_val)-7)) == 'acrobat')
        path = substr(default_val, 0, strlen(default_val)-9);
      else if (!isnull(default_val))
        path = default_val;
    }

    if (subkey == '8.0' && !isnull(min) && (min >> 16 == 2))
    {
      var su1_val = get_registry_value(handle:hklm, item:key2 + "\\VersionSU");
      if (!isnull(su1_val)) su1 = su1_val;
    }

    if (!empty_or_null(path))
    {
      if (strlen(path) > 0 && path[strlen(path)-1] == "\")
        path = substr(path, 0, strlen(path)-2);
      _path_min[tolower(path)] = min;
      _path_max[tolower(path)] = max;
      _path_su1[tolower(path)] = su1;
      dbg::detailed_log(lvl:1, msg:'Found Adobe Acrobat in registry walk: ' + path);
    }
  }

  RegCloseKey(handle:hklm);

  # Merge registry-walk paths with uninstall-discovered paths
  var existing_paths = collector.paths();
  foreach var rp (keys(_path_min))
  {
    var already = FALSE;
    var ep;
    foreach ep (existing_paths)
    {
      if (tolower(rp) == tolower(ep)) { already = TRUE; break; }
    }
    if (!already)
      append_element(var:existing_paths, value:rp);
  }

  if (!thorough_tests && empty_or_null(existing_paths))
  {
    close_registry();
    return collector;
  }

  close_registry(close:FALSE);

  # --- Read file signature metadata ---
  file_sig_field    = 'FilePath';
  file_sig_operator = 'EndsWith';
  file_endswith     = NULL;
  pev_block         = NULL;

  foreach var file_entry (signature['Windows']['Files'])
  {
    foreach var file_criteria (file_entry['Signature'])
    {
      file_endswith = file_criteria[file_sig_field][file_sig_operator];
      if (!isnull(file_endswith)) break;
    }
    pev_block = file_entry['Get']['PEVersion'];
    if (!isnull(file_endswith)) break;
  }

  # --- Phase 3: File version checks ---
  var exe_path, ver, err, version, dll, dll_ver, dll_err;
  var md_entries, pev_entry;

  foreach path (existing_paths)
  {
    # Normalize trailing backslash
    if (strlen(path) > 0 && path[strlen(path)-1] == "\")
      path = substr(path, 0, strlen(path)-2);

    exe_path = hotfix_append_path(path:path, value:file_endswith);

    if (!hotfix_file_exists(path:exe_path))
    {
      dbg::detailed_log(lvl:1, msg:'Acrobat.exe not found: ' + exe_path);
      continue;
    }

    ver     = hotfix_get_pversion(path:exe_path);
    err     = hotfix_handle_error(error_code:ver['error'], file:exe_path);
    if (err && ver['error'] != HCF_NOVER)
    {
      dbg::detailed_log(lvl:1, msg:err);
      continue;
    }

    version = ver['version'];

    # v7.0.8: Acrobat.exe reports 7.1.0 — use acrodist.exe
    if (!empty_or_null(version) && version =~ "^7\.0\.8\.")
    {
      dll = hotfix_append_path(path:hotfix_append_path(path:path, value:'Distillr'), value:'acrodist.exe');
      if (hotfix_file_exists(path:dll))
      {
        dll_ver = hotfix_get_pversion(path:dll);
        dll_err = hotfix_handle_error(error_code:dll_ver['error'], file:dll);
        if (!dll_err || dll_ver['error'] == HCF_NOVER)
          version = dll_ver['version'];
      }
    }
    # v11.0.04: Acrobat.exe does not update — use Acrobat.dll
    else if (!empty_or_null(version) && version =~ "^11\.0\.04\.")
    {
      dll = hotfix_append_path(path:hotfix_append_path(path:path, value:'Acrobat'), value:'Acrobat.dll');
      if (hotfix_file_exists(path:dll))
      {
        dll_ver = hotfix_get_pversion(path:dll);
        dll_err = hotfix_handle_error(error_code:dll_ver['error'], file:dll);
        if (!dll_err || dll_ver['error'] == HCF_NOVER)
          version = dll_ver['version'];
      }
    }

    md_entries = make_list();
    if (!empty_or_null(pev_block))
    {
      foreach pev_entry (pev_block)
      {
        if (pev_entry['Value'] != 'ProductVersionString') continue;
        append_element(var:md_entries, value:collector.make_peversion_match_data_entry(
          value          : version,
          label          : pev_entry['Label'],
          peversion_type : 'ProductVersionString'
        ));
      }
    }

    collector.add_file_match(
      filepath     : exe_path,
      sig_field    : file_sig_field,
      sig_operator : file_sig_operator,
      sig_val      : file_endswith,
      match_data   : md_entries
    );
  }

  hotfix_check_fversion_end();
  return collector;
}

##
# Main
##

var app    = 'Adobe Acrobat';
var cpe = 'cpe:/a:adobe:acrobat';
var vendor = 'Adobe';

var collector = get_collector_or_collect(signature:signature, collect_func:@collect);

var uninstall_matches = collector.get_matches_by_source(source:'UninstalledRegistry');
var file_matches      = collector.get_matches_by_source(source:'Files');

if (empty_or_null(file_matches))
{
  if (!empty_or_null(uninstall_matches))
    audit(AUDIT_UNINST, app);
  else
    audit(AUDIT_NOT_INST, app);
}

# Derive file sig field from signature for path stripping
var _file_sig_field = 'FilePath';
var _file_sig_op    = 'EndsWith';
var _pev_label      = NULL;

foreach var _fsig (signature['Windows']['Files'])
{
  foreach var _fcrit (_fsig['Signature'])
  {
    foreach var _ff (keys(_fcrit))
    {
      _file_sig_field = _ff;
      break;
    }
    break;
  }
  foreach var _pev (_fsig['Get']['PEVersion'])
  {
    _pev_label = _pev['Label'];
    break;
  }
  break;
}

var finding, install_path, file_version, version, regversion, match_data;
var min_val, max_val, su1_val, vparts, a, b, c, d, i, version_ui, track;
var extra, extra_nr, pat, vm;

foreach finding (file_matches)
{
  install_path  = NULL;
  file_version  = NULL;
  version       = NULL;
  regversion    = NULL;

  # Derive install path: FilePath - EndsWith suffix
  foreach var matching_sig (finding['MatchingSignatures'])
  {
    if (matching_sig['SigField'] != _file_sig_field) continue;
    if (matching_sig['SigOperator'] != _file_sig_op) continue;
    var subpath = matching_sig['SigVal'];
    install_path = finding['CollectData']['FilePath'] - subpath;
    install_path = preg_replace(pattern:"^(.+)\\$", replace:"\1", string:install_path);
    break;
  }

  if (empty_or_null(install_path))
  {
    dbg::detailed_log(lvl:1, msg:'Could not derive install path from finding',
      msg_details:{'filepath':{'lvl':1,'value':finding['CollectData']['FilePath']}});
    continue;
  }

  # Extract ProductVersionString from MatchData
  foreach match_data (finding['MatchData'])
  {
    if (!isnull(_pev_label) && match_data['Label'] == _pev_label)
    {
      file_version = match_data['Values'][0];
      break;
    }
  }

  # Find matching uninstall entry for DisplayVersion fallback
  foreach var uninst (uninstall_matches)
  {
    var uninst_path = uninst['CollectData']['DirPath'];
    if (!empty_or_null(uninst_path))
      uninst_path = preg_replace(pattern:"^(.+)\\$", replace:"\1", string:uninst_path);
    if (tolower(uninst_path) != tolower(install_path)) continue;
    regversion = uninst['CollectData']['Version'];
    break;
  }

  version = file_version;

  # Fallback to DisplayVersion when ProductVersionString is absent
  if (empty_or_null(version) && !isnull(regversion))
  {
    version = regversion;
  }
  # For v10+ (2-digit major), prefer DisplayVersion if major matches
  else if (!empty_or_null(version) && version !~ '^[0-9]\\.' && !isnull(regversion))
  {
    var vsplit  = split(version,   sep:'.', keep:FALSE);
    var rvsplit = split(regversion, sep:'.', keep:FALSE);
    if (!isnull(vsplit) && !isnull(rvsplit) && rvsplit[0] == vsplit[0])
      version = regversion;
  }

  if (empty_or_null(version)) version = UNKNOWN_VER;

  # Apply VersionMin/VersionMax adjustments from Installer registry key
  min_val = _path_min[tolower(install_path)];
  max_val = _path_max[tolower(install_path)];
  su1_val = _path_su1[tolower(install_path)];

  vparts = split(version, sep:'.', keep:FALSE);
  for (i = 0; i < max_index(vparts); i++)
    vparts[i] = int(vparts[i]);

  if (!isnull(max_val) && !isnull(min_val))
  {
    a = (max_val >> 16);
    b = max_val & 0xffff;
    c = min_val >> 16;
    d = min_val & 0xffff;
    if (vparts[0] > 7 && vparts[0] == a && vparts[1] == b && vparts[2] < c)
    {
      vparts[2] = c;
      vparts[3] = d;
      version = vparts[0] + '.' + vparts[1] + '.' + vparts[2];
    }
    if (vparts[0] <= 7 && a == 0 && vparts[0] == b && vparts[1] == c && vparts[2] < d)
    {
      vparts[2] = d;
      vparts[3] = 0;
      version = vparts[0] + '.' + vparts[1] + '.' + vparts[2];
    }
  }

  # Format display version
  pat = "^([0-9]+\.[0-9]+\.[0-9])\.(2[0-9]{3})([0-9]{2})([0-9]{2})([0-9]{2})$";
  vm  = pregmatch(pattern:pat, string:version);
  if (!isnull(vm))
  {
    if (vparts[0] < 7)
      version_ui = vm[1] + ' ' + int(vm[3]) + '/' + int(vm[4]) + '/' + int(vm[2]);
    else
      version_ui = vm[1];
  }
  else
  {
    version_ui = version;
  }

  if (version =~ "^[0-9]+\.[0-9]+\.2[0-9]+")      track = 'DC Continuous';
  else if (version =~ "^[0-9]+\.[0-9]+\.3[0-9]+") track = 'DC Classic';
  else                                              track = UNKNOWN_VER;

  extra    = {'Track': track};
  extra_nr = {};
  if (!empty_or_null(su1_val))
  {
    extra_nr['812su1Installed'] = su1_val;
    extra['Update'] = 'Security Update 1';
  }

  register_install(
    app_name        : app,
    vendor          : vendor,
    product         : 'Acrobat',
    path            : install_path,
    version         : version,
    display_version : version_ui,
    extra           : extra,
    extra_no_report : extra_nr,
    cpe             : cpe
  );
}

get_install_count(app_name:app, exit_if_zero:TRUE);
report_installs(app_name:app);

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

17 Aug 2026 00:00Current
5.4Medium risk
Vulners AI Score5.4
47