-
-
Save cham423/aa63b9cbc2961cef43c32b319100bffa to your computer and use it in GitHub Desktop.
updated python3 version of @_dirkjan's getloggedon.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# Gets logged on users via NetrWkstaUserEnum (requires admin on targets). | |
# Mostly adapted from netview.py and lookupsid.py | |
# | |
# Original Author: | |
# Dirk-jan Mollema (@_dirkjan) | |
# Modifier: | |
# Corey Ham (@cham423) | |
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 as 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 as 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'{},{},{}'.format(user)) | |
else: | |
print('{}\\{}'.format(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() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment