Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Identify Managed AD Security Groups #6375

Merged
merged 8 commits into from Jan 12, 2016

Conversation

stufus
Copy link
Contributor

@stufus stufus commented Dec 20, 2015

Overview

This module identifies AD groups which have the 'managedBy' attribute set (which will be the DN of a user who is allowed to manage the group). It will also optionally retrieve the sAMAccountName (username) of the user.

AD groups can be managed by otherwise low privileged users by setting the 'Managed By' attribute:

managed_by_tab

This is routinely used for distribution groups, but it turns out that security groups also support this option. If the 'manager can update membership list' option is set, it allows that user to add members to the group. This has two implications:

  1. If your user happens to be the manager of a group with this option set, you can add yourself or any other user to the group.
  2. You could maintain Domain Admins persistence by setting the Domain Admins group (or any group which is also a member of the Domain Admins group) to be managed by your user. You would then have the ability to gain domain administrator privileges whenever you wished to acquire them.

This module is concerned with Implication 1; identifying AD groups which have a manager set.

Explanation of Impact

On a test domain (goat.stu), an unprivileged user has been created with default privileges. As can be seen, this user does not have sufficient privileges to manipulate the domain admins group.

unprivileged_user

Executing this module initially shows no results.

msf > use post/windows/gather/enum_ad_managedby_groups 
msf post(enum_ad_managedby_groups) > set SESSION 4
SESSION => 4
msf post(enum_ad_managedby_groups) > show options

Module options (post/windows/gather/enum_ad_managedby_groups):

   Name                  Current Setting  Required  Description
   ----                  ---------------  --------  -----------
   ADDITIONAL_FIELDS                      no        Additional group fields to retrieve, comma separated.
   DOMAIN                                 no        The domain to query or distinguished name (e.g. DC=test,DC=com)
   MAX_SEARCH            500              yes       Maximum values to retrieve, 0 for all.
   RESOLVE_MANAGERS      true             yes       Query LDAP to get the account name of group managers.
   SECURITY_GROUPS_ONLY  TRUE             yes       Only include security groups.
   SESSION               4                yes       The session to run this module on.

msf post(enum_ad_managedby_groups) > run

[*] No results returned.
[*] Post module execution completed
msf post(enum_ad_managedby_groups) >

However, if a domain admin user sets the unprivileged user to be the manager of the Domain Admins group and sets the 'Manager can update membership list' option:

domain_admin_set_managed

The module now shows the presence of a managed group:

msf post(enum_ad_managedby_groups) > run

Groups with Managers
====================

 cn             distinguishedname                         managedBy                                     description                              Manager Account Name
 --             -----------------                         ---------                                     -----------                              --------------------
 Domain Admins  CN=Domain Admins,CN=Users,DC=goat,DC=stu  CN=Unprivileged User,CN=Users,DC=goat,DC=stu  Designated administrators of the domain  unprivileged.user

[*] Post module execution completed
msf post(enum_ad_managedby_groups) >

This then allows the unprivileged.user to add themselves (or any other user) to the Domain Admins group.

manipulated_groups

Module

The purpose of this module is simply to identify any groups that have managers. It cannot at the moment determine whether the 'Manager can update membership list' is set because this is encoded into the nTSecurityDescriptor attribute which will need more work to obtain and parse. However, if a compromised user is the manager of a particular group which itself can access sensitive information, this would be a useful way of laterally moving, especially as the manager does not have to be a permanent member of the group. As per the example above, it could also be a sneaky way of persisting once privileged access has been obtained, because the presence of this setting is not obvious.

This is not something that is regularly seen but is worth checking for.

Options

Option Value
ADDITIONAL_FIELDS Include additional fields in the group LDAP search. cn, managedBy, distinguishedName and description will always be included.
RESOLVE_MANAGERS If this is TRUE, the module will loop through each of the groups with a manager set and launch another query to get the sAMAccountName (logon name) of the manager. The managedBy field returns a distinguished name.
SECURITY_GROUPS_ONLY If this is TRUE, the module will restrict the search for managedBy groups to security groups rather than distribution groups.

Conclusion

This module is not likely to be regularly used, but could reveal an otherwise hidden horizontal privilege escalation vulnerability. It is unusual for groups to be managed by non-domain admins but is not unheard of.

Further Work

The main improvement that this module needs is to be able to obtain and parse the nTSecurityDescriptor attribute which will allow results to be filtered to only include those for who the 'manager can update membership list' options is set.

if datastore['RESOLVE_MANAGERS']
begin
managedby_cn = result[2][:value].split(/,(?<!\\,)/)[0]
m = query("(&(objectClass=user)(objectCategory=person)(#{managedby_cn}))", 1, ['sAMAccountName'])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a Group is managed by a Group then this fails to resolve the 'Manager Account Name', although 'managedBy' will be correct.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will update this just to search on the distinguishedName

@Meatballs1
Copy link
Contributor

Bob manages Domain Admins
Domain Admins manages Bosses (SG)
Bosses manage Domain Users

Groups with Managers
====================

 cn             distinguishedname                         managedBy                                 description                              Manager Account Name
 --             -----------------                         ---------                                 -----------                              --------------------
 Domain Admins  CN=Domain Admins,CN=Users,DC=test,DC=lab  CN=bob,CN=Users,DC=test,DC=lab            Designated administrators of the domain  bob
 Domain Users   CN=Domain Users,CN=Users,DC=test,DC=lab   CN=Bosses,CN=Users,DC=test,DC=lab         All domain users                         
 Bosses         CN=Bosses,CN=Users,DC=test,DC=lab         CN=Domain Admins,CN=Users,DC=test,DC=lab         

@Meatballs1 Meatballs1 merged commit e8c8c54 into rapid7:master Jan 12, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants