-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy pathgetloggedon.py
executable file
·189 lines (153 loc) · 6.59 KB
/
getloggedon.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
#!/usr/bin/env python
#
# Orginal script downloaded from https://gist.github.com/dirkjanm/acbd85799b23fc7662f9826ace7bd917
#
# Copyright (c) 2012-2018 CORE Security Technologies
#
# This software is provided under under a slightly modified version
# of the Apache Software License. See the accompanying LICENSE file
# for more information.
#
# Gets logged on users via NetrWkstaUserEnum (requires admin on targets).
# Mostly adapted from netview.py and lookupsid.py
#
# Author:
# Dirk-jan Mollema (@_dirkjan)
#
import sys
import logging
import argparse
import codecs
from impacket.examples.logger import ImpacketFormatter
from impacket import version
from impacket.dcerpc.v5 import transport, wkst
class GetLoggedOn(object):
KNOWN_PROTOCOLS = {
139: {'bindstr': r'ncacn_np:%s[\pipe\wkssvc]', 'set_host': True},
445: {'bindstr': r'ncacn_np:%s[\pipe\wkssvc]', 'set_host': True},
}
def __init__(self, username='', password='', domain='', port=None,
hashes=None, show_computer=False):
self.__username = username
self.__password = password
self.__port = port
self.__domain = domain
self.__lmhash = ''
self.__nthash = ''
self.__show_computer = show_computer
if hashes is not None:
self.__lmhash, self.__nthash = hashes.split(':')
def dump(self, remote_host, csv=False):
logging.info('Enumerating users logged in at %s', remote_host)
stringbinding = self.KNOWN_PROTOCOLS[self.__port]['bindstr'] % remote_host
# logging.info('StringBinding %s'%stringbinding)
rpctransport = transport.DCERPCTransportFactory(stringbinding)
rpctransport.set_dport(self.__port)
if self.KNOWN_PROTOCOLS[self.__port]['set_host']:
rpctransport.setRemoteHost(remote_host)
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)
try:
self.lookup(rpctransport, remote_host, csv)
except Exception, e:
if logging.getLogger().level == logging.DEBUG:
import traceback
traceback.print_exc()
logging.critical(str(e))
raise
def lookup(self, rpctransport, host, csv):
dce = rpctransport.get_dce_rpc()
dce.connect()
dce.bind(wkst.MSRPC_UUID_WKST)
try:
resp = wkst.hNetrWkstaUserEnum(dce,1)
except Exception, e:
if str(e).find('Broken pipe') >= 0:
# The connection timed-out. Let's try to bring it back next round
logging.error('Connection failed - skipping host!')
return
elif str(e).upper().find('ACCESS_DENIED'):
# We're not admin, bye
logging.error('Access denied - you must be admin to enumerate sessions this way')
dce.disconnect()
return
else:
raise
try:
users = set()
# Easy way to uniq them
for i in resp['UserInfo']['WkstaUserInfo']['Level1']['Buffer']:
if i['wkui1_username'][-2] == '$' and not self.__show_computer:
continue
users.add((host, i['wkui1_logon_domain'][:-1], i['wkui1_username'][:-1]))
for user in list(users):
if csv:
print u'%s,%s,%s' % user
else:
print u'%s\\%s' % (user[1], user[2])
except IndexError:
logging.info('No sessions found!')
# resp.dump()
dce.disconnect()
return None
# Process command-line arguments.
def main():
# Init the example's logger theme
handler = logging.StreamHandler(sys.stderr)
handler.setFormatter(ImpacketFormatter())
logging.getLogger().addHandler(handler)
logging.getLogger().setLevel(logging.INFO)
# Explicitly changing the stdout encoding format
if sys.stdout.encoding is None:
# Output is redirected to a file
sys.stdout = codecs.getwriter('utf8')(sys.stdout)
logging.info(version.BANNER)
parser = argparse.ArgumentParser()
parser.add_argument('target', action='store', help='[[domain/]username[:password]@]<targetName or address>')
group = parser.add_argument_group('connection')
group.add_argument('-target-file',
action='store',
metavar="file",
help='Use the targets in the specified file instead of the one on'\
' the command line (you must still specify something as target name)')
group.add_argument('-csv', action='store_true', help='Output in host,domain,user format')
group.add_argument('-show-computer', action='store_true', help='Also show computer accounts')
group.add_argument('-port', choices=['139', '445'], nargs='?', default='445', metavar="destination port",
help='Destination port to connect to SMB Server')
group = parser.add_argument_group('authentication')
group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH')
group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful when proxying through smbrelayx)')
if len(sys.argv)==1:
parser.print_help()
sys.exit(1)
options = parser.parse_args()
import re
domain, username, password, remote_name = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match(
options.target).groups('')
#In case the password contains '@'
if '@' in remote_name:
password = password + '@' + remote_name.rpartition('@')[0]
remote_name = remote_name.rpartition('@')[2]
if domain is None:
domain = ''
if password == '' and username != '' and options.hashes is None and options.no_pass is False:
from getpass import getpass
password = getpass("Password:")
remote_names = []
if options.target_file is not None:
with open(options.target_file, 'r') as inf:
for line in inf:
remote_names.append(line.strip())
else:
remote_names.append(remote_name)
lookup = GetLoggedOn(username, password, domain, int(options.port), options.hashes, options.show_computer)
for remote_name in remote_names:
try:
lookup.dump(remote_name, options.csv)
except KeyboardInterrupt:
break
except:
pass
if __name__ == '__main__':
main()