ISC Stormcast For Wednesday, March 20th 2019

Using AD to find hosts that aren't in AD - fun with the [IPAddress] construct!

Published: 2019-03-20
Last Updated: 2019-03-20 01:45:16 UTC
by Rob VandenBrink (Version: 1)
3 comment(s)

In many internal assessments or "recon mission" style engagements, you'll need to figure out what all the internal subnets are before you can start assessing that address space for issues, targets or whatever you are looking for in that project.  Or, as I had this week, the request was for enumeration of all the hosts that AREN'T in AD.

In many environments, the DHCP server is quick to find, and you can dump the scopes out Easy as Pi (or pie if you prefer) - we covered this a while back:

But say the DHCP servers are dispersed throughout the environment, it's still pretty common to see DHCP servers in each remote location for instance.  Or if you have subnets that don't have a DHCP scope.  How can you enumerate those remote subnets?

Well, you could certainly hijack the routing protocol and dump the routing table, but that's often a tough thing to get permission for.  

How about from the individual host entries in AD?  The IP address is listed there, and in a lot of shops you can assume a /24 for all subnets.  Or if not, larger subnets will just show up as contiguous /24's in your list if you make that assumption.  How does this look like in Powershell?

Let's start by collecting all the IPv4 addresses in play.  This is a "quick and dirty" collection, and will only collect the "first" adapter if  you have any multi-homed windows windows hosts.  We'll start with our old pal "get-ADComputer"

$addrs = get-adcomputer -filter * -property IPV4Address

Now, there are a ton of ways to get the /24's from this list, but since I'm lazy I'll use the "[IPAddress]" construct in PowerShell.  Let's take one element in the list above, and cast it into the "IPv4Address" type, then look at what's there:

[IPAddress] $addrs[6].IPv4Address

Address            : 873890058
AddressFamily      : InterNetwork
ScopeId            :
IsIPv6Multicast    : False
IsIPv6LinkLocal    : False
IsIPv6SiteLocal    : False
IsIPv6Teredo       : False
IsIPv4MappedToIPv6 : False
IPAddressToString  :

Perfect, that "Address" member is a straight numeric representation of the IP, and we can do a binary mask of it with the "-band" operator:

[ipaddress] ((([Ipaddress] $pcs.ipv4address[6]).address -band ([Ipaddress] "").address))

Address            : 1474826
AddressFamily      : InterNetwork
ScopeId            :
IsIPv6Multicast    : False
IsIPv6LinkLocal    : False
IsIPv6SiteLocal    : False
IsIPv6Teredo       : False
IsIPv4MappedToIPv6 : False
IPAddressToString  :

That final member, IPAddressToString is the final value we want top use going forward!  Let's add "/24" to that, and dump it to a file.  Cleaned up, with a bit of error checking, our final code looks like:

$pcs = get-adcomputer -filter * -property IPV4Address
$subnets = @()
foreach ($addr in $pcs.ipv4address) {
    if ($addr.length -ne 0) {          # because lots of $pcs will have a null address
        $sub = [ipaddress] ((([ipaddress] $addr).address -band ([Ipaddress] "").address))
        $subnets += $sub.IPAddressToString + "/24"
$subnets | sort | get-unique > subnets.csv

But what if we wanted just the AD members?  That's easy:

$pcs.ipv4address | sort > AD-hosts.csv

Or just the IP Addresses that are *NOT* AD?  This one is particularly useful in finding things on the network that may have been "flying under the radar" - computers that don't belong to the company for instance, or gear that was purchased by other departments.  Or even gear that was purchased by IT, but never properly inventoried so is now "lost".  Or (perish the thought) malicious hosts!

$targetnets = $subnets | sort  | get-unique
$domainips = $pcs.ipv4address | sort | get-unique
$NonADIPs = @()

foreach ($t in $targetnets) {
    $netbits = $t.Substring(0,($t.length-4))
    for ($hostbits = 1; $hostbits -le 254; $hostbits++) {
        if ( -not $domainips.contains($netbits+$hostbits)) {
            $NonADIPs += ($netbits+$hostbits)
$NonADIPs > non-adips.csv

Next step?  Now that we have these lists, take the file of choice and dump it into nmap.  For instance, using the "nonad-ips.csv" file will scan any hosts that are not AD members.
for a simple ping scan:

nmap --open -sn -iL non-adips.csv -oA non-adips.pingscan

or for a simple tcp port scan (note that this not a scan of all ports):

nmap --open -Pn -iL non-adips.out -oA non-adips.scanned

or, if you are looking for non-firewalled windows hosts that aren't AD members (this is one of the concerns that had me writing this in the first place)

nmap -p445,139 --open -Pn -iL nonadips.out -oA nofw-win-non-ad.scanned

Pretty this up as needed - maybe add "--top-ports n" for the top "n" ports, or "-p0-65535" for all ports, but the defaults give you decent coverage to "see what's out there" fairly quickly.  Or if you're looking for something more specific, maybe non-ad hosts with SMBv1 enabled, run

nmap -p445,139 --open -Pn -iL nonadips.out --script smb-protocols.nse -oA nofw-win-non-ad-smb1.out

Then filter the output for just the problem children with:

type smb1.out.nmap | grep "scan report\|SMBv1"

Of course, you can use the subnets file for a more complete scan (which will include AD members), or you could also use the ad-hosts file to scan only AD members for whatever today's target of interest might be.

Or if you (or your client) is in a hurry, use MASSCAN (don't forget to use that bandwidth limiter!!!).  Play with the rate value a bit so that you end up with decent scan results without saturating any WAN or VPN links.  

Using a faster scanner means that you can maybe also scan the complete tcp port range, depending on your time budget and requirements:

masscan -p0-65535 --rate=1000 -iL non-adips.out -oX scan.out.xml

Note that you can still use --top-ports in masscan, so if you only want to hit the top 1000 ports, use "--top-ports 1000" in your final command.  

Finally, no matter what scanner you use, if you have enough information and enough bandwidth you can usually run multiple scans at different rates, depending on the architecture of the network.

If you're digging a bit deeper, of course you can take those same lists and use them as input to Nessus, OpenVAS or any other tool that you have in your arsenal, or whatever tool, script or playbook you may need to write that day.

Note that in any consulting engagement, time matters!  While your scanner is running, you should be off doing other things, not drinking coffee waiting for that scan to finish.  If this is an internal penetration test, you should be off getting domain admin and will likely have obtained all of your engagement targets by the time the scan finishes.  If this is an assessment, the subnet list will be useful, but most likely your final report will be mostly done by the time the scan wraps up - - or 90%-ish done if you needed those scan results for something specific, or if the scans find something surprising.

Keep in mind that this method will only find subnets that AD knows about directly.  So if you've got subnets that are dedicated to non-AD members - things like IP Phones, scales, shipping printers, scanners and the like (stuff that we call "IoT" these days), those subnets are "ships in the night" to AD.  You might find them using DNS or DHCP recon ( ), or you may need to look at actual routing tables for that (stay tuned for that).

Back to the PowerShell bits, the final scripts above are the ones I've been using for a while, mostly because they took all of 20 minutes to bust out, and they work well and "fast enough" for me, so I never did optimize them further.  I'm sure that there's a one-liner here or there that you could use to make it more efficient - please, use our comment form if you've got some suggestions there!  Or if you've found something spectacular with a portscan that didn't show up in the get-adcomputer list (we all have I'm sure), we're all kinds of interested in that too!!

Rob VandenBrink

Keywords: powershell recon
3 comment(s)


Diary Archives