-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy pathlookupadmins.py
executable file
·206 lines (171 loc) · 7.8 KB
/
lookupadmins.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#!/usr/bin/env python
#
# Orginal script downloaded from https://gist.github.com/UrfinJusse/031a708e68f661f1ba000eda6cfab2bd
#
# Title: lookupadmins.py
# Author: @ropnop
# Description: Python script using Impacket to query members of the builtin Administrators group through SAMR
# Similar in function to Get-NetLocalGroup from Powerview
# Won't work against Windows 10 Anniversary Edition unless you already have local admin
# See: http://www.securityweek.com/microsoft-experts-launch-anti-recon-tool-windows-10-server-2016
#
# Heavily based on original Impacket example scripts written by @agsolino and available here: https://github.com/CoreSecurity/impacket
import sys
import logging
import argparse
import codecs
from impacket.examples import logger
from impacket import version
from impacket.dcerpc.v5 import transport, lsat, lsad, samr
from impacket.dcerpc.v5.dtypes import MAXIMUM_ALLOWED
from impacket.dcerpc.v5.rpcrt import DCERPCException
from impacket.smb import SMB_DIALECT
class SAMRQuery:
def __init__(self, username='', password='', domain='', port=445, remoteName='', remoteHost=''):
self.__username = username
self.__password = password
self.__domain = domain
self.__lmhash = ''
self.__nthash = ''
self.__aesKey = None
self.__port = port
self.__remoteName = remoteName
self.__remoteHost = remoteHost
self.dce = self.getDce()
self.serverHandle = self.getServerHandle()
def getTransport(self):
stringbinding = 'ncacn_np:%s[\pipe\samr\]' % self.__remoteName
rpctransport = transport.DCERPCTransportFactory(stringbinding)
rpctransport.set_dport(self.__port)
rpctransport.setRemoteHost(self.__remoteHost)
if hasattr(rpctransport,'preferred_dialect'):
rpctransport.preferred_dialect(SMB_DIALECT)
if hasattr(rpctransport, 'set_credentials'):
# This method exists only for selected protocol sequences.
rpctransport.set_credentials(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey)
rpctransport.set_kerberos(False, None)
return rpctransport
def getDce(self):
rpctransport = self.getTransport()
dce = rpctransport.get_dce_rpc()
dce.connect()
dce.bind(samr.MSRPC_UUID_SAMR)
return dce
def getServerHandle(self):
resp = samr.hSamrConnect(self.dce)
return resp['ServerHandle']
def getDomains(self):
resp = samr.hSamrEnumerateDomainsInSamServer(self.dce, self.serverHandle)
domains = resp['Buffer']['Buffer']
domainNames = []
for domain in domains:
domainNames.append(domain['Name'])
return domainNames
def getDomainHandle(self, domainName):
resp = samr.hSamrLookupDomainInSamServer(self.dce, self.serverHandle, domainName)
resp = samr.hSamrOpenDomain(self.dce, serverHandle = self.serverHandle, domainId = resp['DomainId'])
return resp['DomainHandle']
def getDomainAliases(self, domainHandle):
resp = samr.hSamrEnumerateAliasesInDomain(self.dce, domainHandle)
aliases = {}
for alias in resp['Buffer']['Buffer']:
aliases[alias['Name']] = alias['RelativeId']
return aliases
def getAliasHandle(self, domainHandle, aliasId):
resp = samr.hSamrOpenAlias(self.dce, domainHandle, desiredAccess=MAXIMUM_ALLOWED, aliasId=aliasId)
return resp['AliasHandle']
def getAliasMembers(self, domainHandle, aliasId):
aliasHandle = self.getAliasHandle(domainHandle, aliasId)
resp = samr.hSamrGetMembersInAlias(self.dce, aliasHandle)
memberSids = []
for member in resp['Members']['Sids']:
memberSids.append(member['SidPointer'].formatCanonical())
return memberSids
class LSAQuery:
def __init__(self, username='', password='', domain='', port=445, remoteName='', remoteHost=''):
self.__username = username
self.__password = password
self.__domain = domain
self.__lmhash = ''
self.__nthash = ''
self.__aesKey = None
self.__port = port
self.__remoteName = remoteName
self.__remoteHost = remoteHost
self.dce = self.getDCE()
self.policyHandle = self.getPolicyHandle()
def getTransport(self):
stringbinding = 'ncacn_np:%s[\pipe\lsarpc]' % self.__remoteName
rpctransport = transport.DCERPCTransportFactory(stringbinding)
rpctransport.set_dport(self.__port)
rpctransport.setRemoteHost(self.__remoteHost)
if hasattr(rpctransport, 'set_credentials'):
# This method exists only for selected protocol sequences.
rpctransport.set_credentials(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey)
rpctransport.set_kerberos(False, None)
return rpctransport
def getDCE(self):
rpctransport = self.getTransport()
dce = rpctransport.get_dce_rpc()
dce.connect()
dce.bind(lsat.MSRPC_UUID_LSAT)
return dce
def getPolicyHandle(self):
resp = lsad.hLsarOpenPolicy2(self.dce, MAXIMUM_ALLOWED | lsat.POLICY_LOOKUP_NAMES)
return resp['PolicyHandle']
def lookupSids(self, sids):
try:
resp = lsat.hLsarLookupSids(self.dce, self.policyHandle, sids, lsat.LSAP_LOOKUP_LEVEL.LsapLookupWksta)
except DCERPCException as e:
if str(e).find('STATUS_SOME_NOT_MAPPED') >= 0:
resp = e.get_packet()
else:
raise
names = []
for translatedNames in resp['TranslatedNames']['Names']:
names.append(translatedNames['Name'])
return names
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('target', action='store', help='[[domain/]username[:password]@]<targetName or address>')
group = parser.add_argument_group('authentication')
group.add_argument('-no-pass', action='store_true', help='don\'t ask for password')
if len(sys.argv)==1:
parser.print_help()
sys.exit(1)
options = parser.parse_args()
import re
domain, username, password, remoteName = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match(options.target).groups('')
#In case the password contains '@'
if '@' in remoteName:
password = password + '@' + remoteName.rpartition('@')[0]
remoteName = remoteName.rpartition('@')[2]
if domain is None:
domain = ''
if password == '' and username != '' and options.no_pass is False:
from getpass import getpass
password = getpass("Password:")
print "[+] Connecting to {}".format(remoteName)
SAMRObject = SAMRQuery(username=username, password=password, remoteName=remoteName, remoteHost=remoteName)
domains = SAMRObject.getDomains()
print "[+] Found domains: "
for domain in domains:
print "\t{}".format(domain)
if "Builtin" in domains:
print "[+] Using 'Builtin'"
else:
print "[!] Didn't find 'Builtin' domain. Will not work. Aborting"
sys.exit(1)
domainHandle = SAMRObject.getDomainHandle('Builtin')
domainAliases = SAMRObject.getDomainAliases(domainHandle)
if 'Administrators' in domainAliases:
print "[+] Found Local Administrators Group: RID {}".format(domainAliases['Administrators'])
print "[+] Querying group members"
memberSids = SAMRObject.getAliasMembers(domainHandle, domainAliases['Administrators'])
print "[+] Found {} members: ".format(len(memberSids))
LSAObject = LSAQuery(username=username, password=password, remoteName=remoteName, remoteHost=remoteName)
memberNames = LSAObject.lookupSids(memberSids)
for name in memberNames:
print "\t{}".format(name)
print "\n[+] Good luck!"
sys.exit(1)