Lucene search

K
nessusThis script is Copyright (C) 2016-2023 and is owned by Tenable, Inc. or an Affiliate thereof.SMB_CHECK_ROLLUP.NASL
HistoryOct 11, 2016 - 12:00 a.m.

Microsoft Security Rollup Enumeration

2016-10-1100:00:00
This script is Copyright (C) 2016-2023 and is owned by Tenable, Inc. or an Affiliate thereof.
www.tenable.com
3086

Nessus was able to enumerate the Microsoft security rollups installed on the remote Windows host.

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

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

if (description)
{
  script_id(93962);
  script_version("1.180");
  script_set_attribute(attribute:"plugin_modification_date", value:"2023/06/26");

  script_name(english:"Microsoft Security Rollup Enumeration");
  script_summary(english:"Enumerates installed Microsoft security rollups.");

  script_set_attribute(attribute:"synopsis", value:
"This plugin enumerates installed Microsoft security rollups.");
  script_set_attribute(attribute:"description", value:
"Nessus was able to enumerate the Microsoft security rollups installed
on the remote Windows host.");
  # https://blogs.technet.microsoft.com/windowsitpro/2016/08/15/further-simplifying-servicing-model-for-windows-7-and-windows-8-1/
  script_set_attribute(attribute:"see_also", value:"http://www.nessus.org/u?b23205aa");
  script_set_attribute(attribute:"solution", value:"n/a");

  script_set_attribute(attribute:"risk_factor",value:"None");

  script_set_attribute(attribute:"plugin_publication_date", value:"2016/10/11");

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

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

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

  script_dependencies("smb_hotfixes.nasl", "wmi_enum_qfes.nbin", "smb_enum_qfes.nasl", "dism_enum_packages.nbin", "wevtutil_removed_packages.nbin");
  script_require_keys("SMB/Registry/Enumerated", "SMB/WindowsVersion");
  script_require_ports(139, 445);
  script_timeout(30*60);

  exit(0);
}

include("smb_func.inc");
include("smb_hotfixes.inc");
include("smb_hotfixes_fcheck.inc");
include("smb_reg_query.inc");
include("debug.inc");
include("smb_rollup_data.inc");

# rollup_dates has now been moved to smb_rollup_data.inc so it can be handled by automation

##
# gets a file version and saves it in the KB
#
# @param path absolute pathname of file to get version for
#
# @return an array where
#         'error' = augmented comparison error code
#         'version' = file version, if one could be obtained
# .       'report' = report text for downstream plugins
##
function rollup_fcheck(path, fix)
{
  local_var fver, r_code, cmp_result, report;
  
  fver = hotfix_get_fversion(path:path);

  if (isnull(fver) || empty_or_null(fver['error']))
    return {error:HCF_ERR, version:''}; # Function failed; This shouldn't happen

  if (fver['error'] == HCF_OK)
  {
    cmp_result = ver_compare(ver:fver['version'], fix:fix, strict:FALSE);

    if (isnull(cmp_result))
      return {error:HCF_ERR, version:fver['version']};
    else if (cmp_result >= 0)
      return {error:HCF_OK, version:fver['version']};
    else
    {
      report = '  - ' + path + ' has not been patched.\n'
             + '    Remote version : ' + fver['version'] + '\n'
             + '    Should be      : ' + fix + '\n';
      return {error:HCF_OLDER, version:fver['version'], report:report};
    }
  }
  else
  {
    report = '  - An error occured while attempting to check ' + path + '\n'
           +     'Error Code       : ' + fver['error'] + '\n';
    return {error:fver['error'], report:report};
  }
}

function set_rollup_info(rollup, path, fver_arr)
{
  local_var error, version, report;
  if (isnull(rollup) || isnull(fver_arr) || isnull(path))
    return FALSE;
    
  if (!isnull(fver_arr['error']))
  {
    error = fver_arr['error'];
    replace_kb_item(name:'smb_rollup/' + rollup + '/error_code', value:fver_arr['error']);
    replace_kb_item(name:'smb_rollup/' + rollup + '/file', value:path);
    if (!isnull(fver_arr['version'])) replace_kb_item(name:'smb_rollup/' + rollup + '/file_ver', value:fver_arr['version']);
  
    if (!isnull(fver_arr['report']))
    {
      report = get_kb_item('smb_rollup/version_report/' + rollup);
      if (!empty_or_null(report))
        report += fver_arr['report'];
      else
        report = fver_arr['report'];
  
      replace_kb_item(name:'smb_rollup/version_report/' + rollup, value:report); 
    }
    return TRUE;
  }
  else
  {
    return FALSE;
  }
}

function is_patched(file_check, rollup_date)
{
  local_var my_sp, my_os, my_arch, my_os_build, systemroot;
  local_var path, error_code, fver_arr;
  
  my_os = get_kb_item("SMB/WindowsVersion");
  my_sp = get_kb_item("SMB/CSDVersion");
  my_arch = get_kb_item("SMB/ARCH");
  my_os_build = get_kb_item("SMB/WindowsVersionBuild");
  if ( my_sp )
  {
    my_sp = ereg_replace(pattern:".*Service Pack ([0-9]).*", string:my_sp, replace:"\1");
    my_sp = int(my_sp);
  }
  else my_sp = 0;

  if ( file_check['os'] >!< my_os ) return FALSE;
  if ( !empty_or_null(file_check['sp']) && my_sp != file_check['sp'] ) return FALSE;
  if ( !empty_or_null(file_check['arch']) && my_arch != file_check['arch'] ) return FALSE;
  if ( !empty_or_null(file_check['os_build']) && my_os_build != file_check['os_build'] ) return FALSE;
  if (isnull(file_check['path']) || isnull(file_check['file'])) return FALSE;

  systemroot = hotfix_get_systemroot();
  if (!systemroot) audit(AUDIT_PATH_NOT_DETERMINED, 'system root');

  
  
  path = hotfix_append_path(path:systemroot + file_check['path'], value:file_check['file']);

  # Look and see if we already have a confirmed patched file for this specific
  #  rollup. This can happen when multiple files are allowed (hotpatch)
  error_code = get_kb_item('smb_rollup/' + rollup_date + '/error_code');
  if (!empty_or_null(error_code) && error_code == HCF_OK)
    return FALSE;

  # Run rollup-specific fcheck
  fver_arr = rollup_fcheck(path:path, fix:file_check['version']);
  if (isnull(fver_arr) || isnull(fver_arr['error']))
  {
    dbg::log(src:'is_patched()', msg:'rollup_fcheck() function error');
    return FALSE;
  }

  if (!set_rollup_info(rollup:rollup_date, path:path, fver_arr:fver_arr))
    dbg::log(src:'is_patched()', msg:'set_rollup_info() function error');

  if (fver_arr['error'] == HCF_OK)
  {
    replace_kb_item(name:'smb_rollup/fa_info/' + rollup_date, value:'1;' + path + ';' + file_check['version'] + ';' + fver_arr['version']);
    return TRUE;
  }
  else
  {
    replace_kb_item(name:'smb_rollup/fa_info/' + rollup_date, value:'0;' + path + ';' + file_check['version'] + ';' + fver_arr['version']);
    return FALSE;
  }
}

function is_patched_hp(file_check, rollup_date, hp_table)
{
  local_var is_patched, f_tab, entry;

  f_tab = hp_table[file_check['file']];

  if (!isnull(f_tab))
  { 
    foreach entry (f_tab)
    {
      if (isnull(file_check['com_hint']) || file_check['com_hint'] >< entry['path'])
      {
        file_check['path'] = entry['path']; # This is safe. A function operates on a copy unless a reference is specifically used.
        return is_patched(file_check:file_check, rollup_date:rollup_date);
      }
    }
  }
  return FALSE;
}

function gen_hp_table(hp_table)
{
  var key, hklm, r_table, r_key;
  var value, subkey, subkeys;
  var path, file, match;

  if (isnull(hp_table)) hp_table = {};

  key = 'SYSTEM\\CurrentControlSet\\Control\\HotPatch';

  registry_init();
  hklm = registry_hive_connect(hive:HKEY_LOCAL_MACHINE);
  if (isnull(hklm))
  {
    close_registry();
    dbg::detailed_log(lvl:1, src:'gen_hp_table', msg:'Failed to connect to HKLM for HP table.'); 
    audit(AUDIT_REG_FAIL);
  }

  # Old Style
  r_table = get_reg_name_value_table(handle:hklm, key:key);
  dbg::detailed_log(lvl:3, src:'gen_hp_table', msg:'OS: r_table collection\n' + obj_rep(r_table));

  if (!isnull(r_table))
  {
    foreach r_key (keys(r_table))
    {
      r_table[r_key] = unicode2ascii(string:r_table[r_key]);
    }
  }

  # New Style
  subkeys = get_registry_subkeys(handle:hklm, key:key);
  dbg::detailed_log(lvl:3, src:'gen_hp_table', msg:'NS: subkey collection\n' + obj_rep(subkeys)); 
  if (!isnull(subkeys))
  {
    foreach subkey (subkeys)
    {
      value = get_registry_value(handle:hklm, item:join(key, subkey, 'PatchPath', sep:'\\'));
      if (!isnull(value))
      {
        r_table[subkey] = value;
        dbg::detailed_log(lvl:3, src:'gen_hp_table', msg:'NS: r_table addition\nkey: '+ obj_rep(subkey) + '\nvalue: ' + obj_rep(value));
      }
    }
  }
  RegCloseKey(handle:hklm);
  close_registry(close:FALSE);

  dbg::detailed_log(lvl:3, src:'gen_hp_table', msg:'Final r_table collection\n' + obj_rep(r_table));
  if (!isnull(r_table))
  {
    foreach key (keys(r_table))
    {
      # \Systemroot\WinSxs\wow64_microsoft-windows-t..e-package-component_31bf3856ad364e35_10.0.17784.10000_none_55e77d3f6de6933f\rpcrt4_hp.dll
      # 
      match = pregmatch(pattern:"^.+?Systemroot(\\.+)\\([^\\]+)$", string:r_table[key]);
      if (!isnull(match))
      {
        file = match[2];
        path = match[1];

        if (isnull(hp_table[file]))
          hp_table[file] = [];

        append_element(var:hp_table[file], value:{path:path, key:key});
        dbg::detailed_log(lvl:3,  src:'gen_hp_table', msg:'Added table value:', msg_details:{'File':{lvl:3, value:file}, 'Path':{lvl:3, value:path}, 'Key':{lvl:3, value:key}});
      }
      else
        dbg::detailed_log(lvl:1, src:'gen_hp_table', msg:'Failed to parse table value: ' + obj_rep(r_table(key))); 
    }
  }
  dbg::detailed_log(lvl:1, src:'gen_hp_table', msg:'Generated hp_table array', msg_details:{'Table':{lvl:2, value:obj_rep(hp_table)}});
  
  return hp_table;
  # e.g. (64 and 32-bit dlls):
  # make_nested_array(
  #   'rpcrt4_hp.dll', make_nested_list(
  #     make_nested_array(
  #       'key', '00130a96469abda4',
  #       'path', '\\WinSxs\\amd64_microsoft-windows-t..e-package-component_31bf3856ad364e35_10.0.17784.10000_none_4b92d2ed3985d144'
  #     ),
  #     make_nested_array(
  #       'key', '000cb198782e75d3',
  #       'path', '\\WinSxs\\wow64_microsoft-windows-t..e-package-component_31bf3856ad364e35_10.0.17784.10000_none_55e77d3f6de6933f'
  #     )
  #   )
  # )
}

function rollupfix_installed()
{
  var file_ver, dism_rollupfix;
  if(!isnull(_FCT_ANON_ARGS[0])) file_ver = _FCT_ANON_ARGS[0];

  dism_rollupfix = get_kb_item("WMI/DISM/rollupfix");
  if(!isnull(dism_rollupfix) && !isnull(os_ver))
  {
    if(os_ver == "10")
      dism_rollupfix = os_ver + ".0." + dism_rollupfix;
    else
      dism_rollupfix = os_ver + "." + dism_rollupfix;
  }

  if(!isnull(dism_rollupfix) && ver_compare(ver:dism_rollupfix, fix:file_ver, strict:FALSE) >= 0)
    return TRUE;
}

function kb_installed()
{
  var kb, qfes, wevt_removed, dism;
  if(isnull(_FCT_ANON_ARGS[0])) return false;
  kb = "KB" + _FCT_ANON_ARGS[0];
  qfes = get_kb_item("SMB/Microsoft/qfes");
  dism = get_kb_item("WMI/DISM/installed");
  wevt_removed = get_kb_item("WMI/WEVTUTIL/removed");
  if((kb >< qfes) || get_kb_item("WMI/Installed/Hotfix/" + kb) || (kb >< dism) || (kb >< wevt_removed))
    return TRUE;
}

function check_handler(file_check, rollup_date, hp_table)
{
  if (empty_or_null(file_check)) 
  {
    dbg::log(src:'check_handler()', msg:'Provided an empty or null file_check.'); 
    return 0;
  }

  if (file_check['type'] == 'hp')
  {
    if (!get_kb_item("SMB/WindowsHPEnrollment"))
      return 0;

    if (empty_or_null(hp_table)) 
    {
      dbg::log(src:'check_handler()', msg:'hp_table not provided with hp check.');
      return 0;
    }

    return is_patched_hp(file_check:file_check,
                         hp_table:hp_table,
                         rollup_date:rollup_date);
  }
  else
  {
    return is_patched(file_check:file_check, rollup_date:rollup_date); 
  }
}

var report = '';
var latest_eff = '';
var cur_date = '0.0';
var last_date = '0.0';
var latest_file = '';
var latest_ver = '';
var kb_str = '';
var oob_installed = '';
var systemroot = hotfix_get_systemroot();
var smb_qfes = get_kb_item('SMB/Microsoft/qfes');
var wmi_qfes = get_kb_list('WMI/Installed/Hotfix/*');
global_var os_ver = get_kb_item("SMB/WindowsVersion");
var hp_table = {};

if (get_kb_item("SMB/WindowsHPEnrollment"))
{
  report += '\n Hotpatching       : Enrolled';
  hp_table = gen_hp_table();
}

foreach var rollup_date (rollup_dates)
{
  var patch_checks = rollup_patches[rollup_date];
  foreach var patch_check (patch_checks)
  {
    var file_check = patch_check[0];
    if(check_handler(file_check:file_check, rollup_date:rollup_date, hp_table:hp_table))
    {
      
      var kb_list = patch_check[1];

      # 09_2020, 09_2020_2, 09_2020_02_1, etc
      if (rollup_date !~ "^[0-9]+_[0-9][0-9_]*$")
      {
        dbg::log(src:'rollup date loop', msg:'Rollup string failed regex check - rollup_date: ' + obj_rep(rollup_date));
        continue;
      }

      var key_segs = split(rollup_date, sep:'_', keep:FALSE);
      var int_var = key_segs[0];
      key_segs[0] = key_segs[1];
      key_segs[1] = int_var;
      cur_date = join(key_segs, sep:'.');

      if(kb_installed(kb_list["cum"]) || kb_installed(kb_list["pre"]) || max_index(kb_list["oob"]) > 0 || os_ver == "10" || rollupfix_installed(file_check["version"]))
      {
        if (empty_or_null(latest_eff)) latest_eff = rollup_date;

        # 09_2020, 09_2020_2, 09_2020_02_1, etc
        if (latest_eff !~ "^[0-9]+_[0-9][0-9_]*$")
        {
          dbg::log(src:'rollup date loop', msg:'Rollup string failed regex check - latest_eff: ' + obj_rep(latest_eff));
          continue;
        }
        key_segs = split(latest_eff, sep:'_', keep:FALSE);
        int_var = key_segs[0];
        key_segs[0] = key_segs[1];
        key_segs[1] = int_var;
        last_date = join(key_segs, sep:'.');

        if(ver_compare(ver:cur_date, fix:last_date, strict:FALSE) >=0)
        {
          latest_eff = rollup_date;

          kb_str =  kb_list["cum"];
          if(kb_list['oob']) kb_str += ", " + join(kb_list['oob'], sep:", ");
          if(kb_list['sec']) kb_str += ", " + kb_list['sec'];
          if(kb_list['pre']) kb_str += ", " + kb_list['pre'];
        }
      }

      if(os_ver == "10")
      {
        if(kb_installed(kb_list["cum"]))
        {
          report += '\n Cumulative Rollup : ' + rollup_date + ' [KB' + kb_list["cum"] + ']';
          set_kb_item(name:"smb_rollup/" + rollup_date + "/cum", value:kb_list["cum"]);
        }
        if(oob_installed) // todo: research-how-used
        {
          foreach var patch (kb_list["oob"])
          {
            if(kb_installed(patch))
            {
              report += '\n Cumulative Rollup : ' + rollup_date + ' [KB' + patch + ']';
              set_kb_item(name:"smb_rollup/" + rollup_date + "/oob", value:patch);
            }
          }
        }
        if(!kb_installed(kb_list["cum"]) && !oob_installed)
        {
          report += '\n Cumulative Rollup : ' + rollup_date;
          set_kb_item(name:"smb_rollup/" + rollup_date, value:1);
        }
      }
      else
      {
         if(kb_installed(kb_list["cum"]))
        {
          report += '\n Cumulative Rollup : ' + rollup_date + ' [KB' + kb_list["cum"] + ']';
          set_kb_item(name:"smb_rollup/" + rollup_date + "/cum", value:kb_list["cum"]);
        }

        if(kb_installed(kb_list["pre"]))
        {
          report += '\n Preview of Monthly Rollup : ' + rollup_date + ' [KB' + kb_list["pre"] + ']';
          set_kb_item(name:"smb_rollup/" + rollup_date + "/preview", value:kb_list["pre"]);
        }
        if(kb_installed(kb_list["sec"]))
        {
          report += '\n Security Rollup : ' + rollup_date + ' [KB' + kb_list["sec"] + ']';
          set_kb_item(name:"smb_rollup/" + rollup_date + "/sec", value:kb_list["sec"]);
          set_kb_item(name:"smb_rollup/"+rollup_date, value:1);
        }

        # If no qfes could be enumerated, but versions are right
        # defer to the version check.
        if(empty_or_null(smb_qfes) && empty_or_null(wmi_qfes))
        {
          set_kb_item(name:"smb_rollup/"+rollup_date, value:1);
        }
      }
    }
  }
}

# cleanup connection
NetUseDel();

replace_kb_item(name:"smb_check_rollup/done", value:TRUE);

foreach var error_code (make_list(get_kb_list("smb_rollup/*/error_code")))
{
  if (!isnull(error_code) && error_code != HCF_OK
                          && error_code != HCF_OLDER 
                          && error_code != HCF_NOENT)
    {
      replace_kb_item(name:"smb_check_rollup/done", value:FALSE);
      break;
    }
}

if(latest_eff == "" && report == "")
  exit(0, "No Microsoft rollups were found.");

latest_file = get_kb_item("smb_rollup/"+latest_eff+"/file");
latest_ver = get_kb_item("smb_rollup/"+latest_eff+"/file_ver");

if(latest_eff == "")
{
  set_kb_item(name:"smb_rollup/latest", value:"none");
  report += '\n   No cumulative updates are installed.\n';
}
else
{    
  report += '\n\n Latest effective update level : ' + latest_eff +
            '\n File checked                  : ' + latest_file +
            '\n File version                  : ' + latest_ver +
            '\n Associated KB                 : ' + kb_str + '\n';
  set_kb_item(name:"smb_rollup/latest", value:latest_eff);
}

var port = kb_smb_transport();
if(!port)port = 445;

security_note(port:port, extra:report);