macOS and Mac OS X User List Enumeration

2016-12-19T00:00:00
ID MACOS_USER_ENUM.NASL
Type nessus
Reporter Tenable
Modified 2018-05-16T00:00:00

Description

Using the supplied credentials, Nessus was able to extract the member list of the 'Admin' and 'Wheel' groups on the remote host. Members of these groups have administrative access.

                                        
                                            #TRUSTED a3b9e06ca31c0ed0fdbfef19343c0ff9ed0733e10f51daa8dc0c82260c6ba956c9908b2f49e2d5fc22095bcf8845a8f9a38bb6591f56858611a2922a1e07446f96196a645c83565ade4628e0cae40c264cbbabaac3956d2655dc08221926a8928e3e380bdb8b8a42b52f668d6489f3d92f07ba5c479f87faf3ed1ae079714174400257f215afe247d2624e05079e46d509cfcb825da420a7030f89318af6e531f8126289540ec1fe63356d66c07ff0abf998a255e3a5eec2b5607ade59138f773baf7aaae85f813337b41d9bb9787d17ef5237a1f53276238ec91010963c85cb7565a8aa4468772441da6f42ae77836101d9daedc6d5f828499aedac4d1c0e867c47c36ae8a31d72275f1859ff20bc4ad20dfbff0088e1015582a8411611282af24c36eb9fe6746e00b5b1b8cc90f104af351e66e41f3852ec2ee1d25d68aa3dd5a71f7bdb68fe68428217e2619f4659b5bd6fd8b36d4add29630df7d172eb08c14d233d91d62f1d98b3826fd876749bc875ea9c2e8372dcbe20f902dac531fa3258ede0e90ba0e67e0de9503290ecf97456537496a71f378011dd3d68d958e1aefaa3a474ced97ebcff9e3c6b4d23cbf923e01a06aa888f09cce53271913d5e0379811a286dca451969241863c02003cc1253ac3e4f4837480fd8b24bf933838b69536641b22f36bc8a13a8c135fdec88cb7c947f1fc4319ca1c77d89585d8a
#
# (C) Tenable Network Security, Inc.
#

if (!defined_func("bn_random")) exit(0);
if (NASL_LEVEL < 3000) exit(0);

include("compat.inc");

if (description)
{
  script_id(95929);
  script_version("1.5");
  script_set_attribute(attribute:"plugin_modification_date", value:"2018/05/16");

  script_name(english:"macOS and Mac OS X User List Enumeration");
  script_summary(english:"Lists users on macOS and Mac OS hosts.");

  script_set_attribute(attribute:"synopsis", value:
"Nessus was able to enumerate local users on the remote host.");
  script_set_attribute(attribute:"description", value:
"Using the supplied credentials, Nessus was able to extract the member
list of the 'Admin' and 'Wheel' groups on the remote host. Members of
these groups have administrative access.");
  script_set_attribute(attribute:"solution", value:"None");
  script_set_attribute(attribute:"risk_factor", value:"None");

  script_set_attribute(attribute:"plugin_publication_date", value:"2016/12/19");

  script_set_attribute(attribute:"plugin_type", value:"local");
  script_set_attribute(attribute:"agent", value:"macosx");
  script_set_attribute(attribute:"cpe", value:"cpe:/o:apple:mac_os_x");
  script_set_attribute(attribute:"cpe", value:"cpe:/o:apple:macos");
  script_end_attributes();

  script_category(ACT_GATHER_INFO);
  script_family(english:"MacOS X Local Security Checks");

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

  script_dependencies("ssh_get_info.nasl");
  script_require_keys("Host/local_checks_enabled", "Host/MacOSX/Version");

  exit(0);
}

include("global_settings.inc");
include("misc_func.inc");
include("ssh_func.inc");
include("macosx_func.inc");
include("data_protection.inc");

if(sshlib::get_support_level() >= sshlib::SSH_LIB_SUPPORTS_COMMANDS)
  enable_ssh_wrappers();
else disable_ssh_wrappers();

if (!get_kb_item("Host/local_checks_enabled")) exit(0, "Local checks are not enabled.");

os = get_kb_item("Host/MacOSX/Version");
if (!os) exit(0, "The host does not appear to be running macOS or Mac OS X.");

cmd = "echo ; /usr/bin/dscl . -readall /Groups GroupMembership";
res_grp = exec_cmd(cmd:cmd);

cmd = "echo ; /usr/bin/dscl . -list /Users";
res_usr = exec_cmd(cmd:cmd);

if("RecordName" >!< res_grp || empty_or_null(res_usr)) exit(0, "Could not retrieve users or groups using dscl.");

###
# dscl returns groups/membership in the format, delimited by - :
# Users in GroupMembership delimited by spaces
# sometimes there are multiple group RecordNames, as is the case with lpadmin
#
# -
# GroupMembership: root _sophos casper JoeyBloggs temp cadmin
# RecordName: staff BUILTIN\Users
# - 
# GroupMembership: temp JoeyBloggs
# RecordName:
#  _lpadmin
#  lpadmin
#  BUILTIN\Print Operators
# -
# ...
###

# split into Recordname/Groupmembership blocks

if(!empty_or_null(res_grp)) grp_blk = split(res_grp, sep:"-", keep:FALSE);
pattern = 'GroupMembership: (.*)RecordName: (.*)';
users = make_array();

# For each group, add the group to a Users array entry for each
# user in group
foreach grp (grp_blk)
{
  if("GroupMembership" >!< grp) continue;

  match = eregmatch(pattern:pattern, string:join(split(grp, keep:FALSE)));

  # only grab the first group RecordNames if there are multiple
  firstname = split(match[2], sep:" ", keep:FALSE);

  # This is for instances like _lpadmin above, where there is a leading space
  # due to the new line in RecordName
  if(empty_or_null(firstname[0])) firstname = firstname[1];
  else firstname = firstname[0];

  # add group to groups list in user array
  foreach user (split(match[1], sep:" ", keep:FALSE))
  {
    if(empty_or_null(users[user])) users[user] = make_list(firstname);
    else users[user] = make_list(users[user], firstname);
  }
}

info = '';
info2 = '';
report = '';
svc = FALSE;
svc_nogroup = make_list();
set_kb_item(name:"Host/MacOSX/Users", value:res_usr);

foreach usr (split(res_usr,keep:FALSE))
{
  if(empty_or_null(usr)) continue;
  if(usr =~ "^_") svc = TRUE;

  if(!svc) info += '\n' + "User   : " + data_protection::sanitize_user_enum(users:usr) + '\n';
  else info2 += '\n' + "User   : " + usr +'\n';

  if(!empty_or_null(users[usr]))
  {
    if(!svc) info += "Groups : " + join(users[usr], sep:',\n         ') + '\n';
    else info2 += "Groups : " + join(users[usr], sep:',\n         ') + '\n';

    set_kb_item(name:"Host/MacOSX/Users/" + usr + "/Groups", value:join(users[usr], sep:'\n'));
  }
  
  svc = FALSE;
}

report = '\n' + "----------[ User Accounts ]----------" + '\n' + info + 
         '\n' +  "----------[ Service Accounts ]----------" + '\n' + info2;

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