PowerShellEmpire / PowerTools

PowerTools is a collection of PowerShell projects with a focus on offensive operations.
Other
2.03k stars 817 forks source link

Get-NetGroup fails with Large > 1500 members #39

Closed Meatballs1 closed 8 years ago

Meatballs1 commented 9 years ago

The result I'm getting back is a count of 0 members :(

However net group "groupname" /domain brings back lots

http://itq.nl/get-more-than-1500-members-from-an-active-directory-group/

If the 'member' count is 0 we should check if there is a property member;range=0-1499 and then member;1500-2999 etc

Meatballs1 commented 9 years ago

http://www.adilhindistan.com/2013/01/getting-members-of-large-groups-via.html

Meatballs1 commented 9 years ago

This is what I ended up using:

$GroupSearcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://DC=BLAH,DC=COM")
$GroupSearcher.filter = "(&(objectClass=group)(name=Large Group))"
$GroupSearcher.PageSize = 500
$out = $GroupSearcher.FindOne()
if ($out.properties.member.count -eq 0) {
    $retrievedAllMembers=$false          
    $rangeBottom =0
    $rangeTop= 0
    while (! $retrievedAllMembers) {
        $rangeTop=$rangeBottom+1499
        $memberRange="member;range=$rangeBottom-$rangeTop"  

        $GroupSearcher.PropertiesToLoad.Clear()
        [void]$GroupSearcher.PropertiesToLoad.Add("$memberRange")
        $rangeBottom+=1500
        try {
            $result = $GroupSearcher.FindOne() 
            $rangedProperty = $result.Properties.PropertyNames -like "member;range=*"
            $results = $result.Properties.item($rangedProperty)
            if ($results.count -eq 0) { 
                $retrievedAllMembers=$true
            } else {
                $results.count | Out-Host
                $results | % {
                    $output = New-Object psobject
                    $properties = ([adsi]"LDAP://$_").Properties
                    $output | add-member Noteproperty 'sAMAccountName' $properties.sAMAccountName.value
                    $output | add-member Noteproperty 'mail' $properties.mail.value
                    $output | Out-File -Append -FilePath out.txt
                }
            }       
        } catch [System.Management.Automation.MethodInvocationException] {
            $retrievedAllMembers=$true
        }
    }
}

A version of this would be useful as a function that Get-NetGroup could call if member.count == 0

Meatballs1 commented 9 years ago

Would also had to look at recursion...

Meatballs1 commented 9 years ago

Diff looks summat like:

        if ($GroupSearcher){
            $GroupSearcher.PageSize = 200
            $GroupSearcher.FindAll() | % {
                try{
                    $GroupFoundName = $_.properties.name[0]
                    $members = @()
                    if ($_.properties.member.Count -eq 0) {
                        $retrievedAllMembers = $false          
                        $rangeBottom = 0
                        $rangeTop = 0
                        while (! $retrievedAllMembers) {
                            $rangeTop=$rangeBottom+1499
                            $memberRange="member;range=$rangeBottom-$rangeTop"  

                            $GroupSearcher.PropertiesToLoad.Clear()
                            [void]$GroupSearcher.PropertiesToLoad.Add("$memberRange")
                            $rangeBottom+=1500
                            try {
                                $result = $GroupSearcher.FindOne() 
                                $rangedProperty = $result.Properties.PropertyNames -like "member;range=*"
                                $results = $result.Properties.item($rangedProperty)
                                if ($results.count -eq 0) { 
                                    $retrievedAllMembers=$true
                                } else {
                                    $results | % {
                                        $members += $_
                                    }
                                }       
                            } catch [System.Management.Automation.MethodInvocationException] {
                                $retrievedAllMembers=$true
                            }
                        }
                    } else {
                        $members = $_.properties.member
                    }

                    $members | ForEach-Object {
Meatballs1 commented 9 years ago

Sorry cant do a proper PR request from where I am at the moment

Meatballs1 commented 9 years ago
    process {

        # if a domain is specified, try to grab that domain
        if ($Domain){

            # try to grab the primary DC for the current domain
            try{
                $PrimaryDC = ([Array](Get-NetDomainControllers))[0].Name
            }
            catch{
                $PrimaryDC = $Null
            }

            try {
                # reference - http://blogs.msdn.com/b/javaller/archive/2013/07/29/searching-across-active-directory-domains-in-powershell.aspx

                $dn = "DC=$($Domain.Replace('.', ',DC='))"

                # if we could grab the primary DC for the current domain, use that for the query
                if($PrimaryDC){
                    $GroupSearcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://$PrimaryDC/$dn")
                }
                else{
                    # otherwise try to connect to the DC for the target domain
                    $GroupSearcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://$dn")
                }
                # samAccountType=805306368 indicates user objects
                $GroupSearcher.filter = "(&(objectClass=group)(name=$GroupName))"
            }
            catch{
                Write-Warning "The specified domain $Domain does not exist, could not be contacted, or there isn't an existing trust."
            }
        }
        else{
            $Domain = (Get-NetDomain).Name

            # otherwise, use the current domain
            $GroupSearcher = [adsisearcher]"(&(objectClass=group)(name=$GroupName))"
        }

        if ($GroupSearcher){
            $GroupSearcher.PageSize = 200
            $GroupSearcher.FindAll() | % {
                try{
                    $GroupFoundName = $_.properties.name[0]
                    $members = @()
                    if ($_.properties.member.Count -eq 0) {
                        $retrievedAllMembers = $false          
                        $rangeBottom = 0
                        $rangeTop = 0
                        while (! $retrievedAllMembers) {
                            $rangeTop=$rangeBottom+1499
                            $memberRange="member;range=$rangeBottom-$rangeTop"  

                            $GroupSearcher.PropertiesToLoad.Clear()
                            [void]$GroupSearcher.PropertiesToLoad.Add("$memberRange")
                            $rangeBottom+=1500
                            try {
                                $result = $GroupSearcher.FindOne() 
                                $rangedProperty = $result.Properties.PropertyNames -like "member;range=*"
                                $results = $result.Properties.item($rangedProperty)
                                if ($results.count -eq 0) { 
                                    $retrievedAllMembers=$true
                                } else {
                                    $results | % {
                                        $members += $_
                                    }
                                }       
                            } catch [System.Management.Automation.MethodInvocationException] {
                                $retrievedAllMembers=$true
                            }
                        }
                    } else {
                        $members = $_.properties.member
                    }

                    $members | ForEach-Object {
                        # for each user/member, do a quick adsi object grab
                        if ($PrimaryDC){
                            $properties = ([adsi]"LDAP://$PrimaryDC/$_").Properties
                        }
                        else {
                            $properties = ([adsi]"LDAP://$_").Properties
                        }

                        # check if the result is a user account- if not assume it's a group
                        if ($properties.samAccountType -ne "805306368"){
                            $isGroup = $True
                        }
                        else{
                            $isGroup = $False
                        }

                        $out = New-Object psobject
                        $out | add-member Noteproperty 'GroupDomain' $Domain
                        $out | Add-Member Noteproperty 'GroupName' $GroupFoundName

                        if ($FullData){
                            $properties.PropertyNames | % {
                                # TODO: errors on cross-domain users?
                                if ($_ -eq "objectsid"){
                                    # convert the SID to a string
                                    $out | Add-Member Noteproperty $_ ((New-Object System.Security.Principal.SecurityIdentifier($properties[$_][0],0)).Value)
                                }
                                elseif($_ -eq "objectguid"){
                                    # convert the GUID to a string
                                    $out | Add-Member Noteproperty $_ (New-Object Guid (,$properties[$_][0])).Guid
                                }
                                else {
                                    if ($properties[$_].count -eq 1) {
                                        $out | Add-Member Noteproperty $_ $properties[$_][0]
                                    }
                                    else {
                                        $out | Add-Member Noteproperty $_ $properties[$_]
                                    }
                                }
                            }
                        }
                        else {
                            $MemberDN = $properties.distinguishedName[0]
                            # extract the FQDN from the Distinguished Name
                            $MemberDomain = $MemberDN.subString($MemberDN.IndexOf("DC=")) -replace 'DC=','' -replace ',','.'

                            if ($properties.samAccountType -ne "805306368"){
                                $isGroup = $True
                            }
                            else{
                                $isGroup = $False
                            }

                            if ($properties.samAccountName){
                                # forest users have the samAccountName set
                                $MemberName = $properties.samAccountName[0]
                            }
                            else {
                                # external trust users have a SID, so convert it
                                try {
                                    $MemberName = Convert-SidToName $properties.cn[0]
                                }
                                catch {
                                    # if there's a problem contacting the domain to resolve the SID
                                    $MemberName = $properties.cn
                                }
                            }
                            $out | add-member Noteproperty 'MemberDomain' $MemberDomain
                            $out | add-member Noteproperty 'MemberName' $MemberName
                            $out | add-member Noteproperty 'IsGroup' $IsGroup
                            $out | add-member Noteproperty 'MemberDN' $MemberDN
                            $out | add-member Noteproperty 'Mail' $Mail

                        $out

                        if($Recurse) {
                            # if we're recursiving and  the returned value isn't a user account, assume it's a group
                            if($IsGroup){
                                if($FullData){
                                    Get-NetGroup -Domain $Domain -PrimaryDC $PrimaryDC -FullData -Recurse -GroupName $properties.SamAccountName[0]
                                }
                                else {
                                    Get-NetGroup -Domain $Domain -PrimaryDC $PrimaryDC -Recurse -GroupName $properties.SamAccountName[0]
                                }
                            }
                        }
                    }
                    }
                }
                catch {
                    write-verbose $_
                }
            }
        }
    }
}