From c3c4b3192d12c62e3c04c5e8003bfbe1a8362e70 Mon Sep 17 00:00:00 2001 From: mpgn Date: Sun, 10 Nov 2019 22:42:04 +0100 Subject: [PATCH 01/13] start python3 migration --- cme/cli.py | 2 +- cme/cmedb.py | 4 ++-- cme/context.py | 4 ++-- cme/crackmapexec.py | 4 ++-- cme/first_run.py | 5 +++-- cme/protocols/http.py | 4 ++-- cme/protocols/mssql.py | 4 ++-- cme/protocols/smb.py | 8 ++++---- cme/protocols/smb/wmiexec.py | 2 +- cme/protocols/ssh.py | 2 +- cme/protocols/winrm.py | 4 ++-- cme/servers/http.py | 4 ++-- cme/servers/smb.py | 2 +- cme/thirdparty/impacket | 2 +- cme/thirdparty/pywerview | 2 +- 15 files changed, 27 insertions(+), 26 deletions(-) diff --git a/cme/cli.py b/cme/cli.py index 699c35d1..8a9ffee7 100755 --- a/cme/cli.py +++ b/cme/cli.py @@ -31,7 +31,7 @@ def gen_cli_args(): highlight(CODENAME)), formatter_class=RawTextHelpFormatter, - version='{} - {}'.format(VERSION, CODENAME), + #version='{} - {}'.format(VERSION, CODENAME), epilog="Ya feelin' a bit buggy all of a sudden?") parser.add_argument("-t", type=int, dest="threads", default=100, help="set how many concurrent threads to use (default: 100)") diff --git a/cme/cmedb.py b/cme/cmedb.py index d4f31e3d..c6237c84 100755 --- a/cme/cmedb.py +++ b/cme/cmedb.py @@ -7,7 +7,7 @@ import requests from time import sleep from terminaltables import AsciiTable from cme.msfrpc import Msfrpc, MsfAuthError -from ConfigParser import ConfigParser +import configparser from cme.loaders.protocol_loader import protocol_loader from requests import ConnectionError @@ -188,7 +188,7 @@ class CMEDBMenu(cmd.Cmd): self.config_path = config_path try: - self.config = ConfigParser() + self.config = configparser.ConfigParser() self.config.read(self.config_path) except Exception as e: print "[-] Error reading cme.conf: {}".format(e) diff --git a/cme/context.py b/cme/context.py index e2058d83..3dce575b 100755 --- a/cme/context.py +++ b/cme/context.py @@ -1,6 +1,6 @@ import logging import os -from ConfigParser import ConfigParser +import configparser class Context: @@ -11,7 +11,7 @@ class Context: self.log_folder_path = os.path.join(os.path.expanduser('~/.cme'), 'logs') self.localip = None - self.conf = ConfigParser() + self.conf = configparser.ConfigParser() self.conf.read(os.path.expanduser('~/.cme/cme.conf')) for key, value in vars(args).iteritems(): diff --git a/cme/crackmapexec.py b/cme/crackmapexec.py index c76cc985..5a819e83 100755 --- a/cme/crackmapexec.py +++ b/cme/crackmapexec.py @@ -15,7 +15,7 @@ from cme.servers.http import CMEServer from cme.first_run import first_run_setup from cme.context import Context from pprint import pformat -from ConfigParser import ConfigParser +import configparser import cme.helpers.powershell as powershell import cme import shutil @@ -44,7 +44,7 @@ def main(): cme_path = os.path.expanduser('~/.cme') - config = ConfigParser() + config = configparser.ConfigParser() config.read(os.path.join(cme_path, 'cme.conf')) module = None diff --git a/cme/first_run.py b/cme/first_run.py index bc518c90..2567499d 100755 --- a/cme/first_run.py +++ b/cme/first_run.py @@ -2,7 +2,8 @@ import os import sqlite3 import shutil import cme -from ConfigParser import ConfigParser, NoSectionError, NoOptionError +import configparser +from configparser import ConfigParser, NoSectionError, NoOptionError from cme.loaders.protocol_loader import protocol_loader from subprocess import check_output, PIPE from sys import exit @@ -65,7 +66,7 @@ def first_run_setup(logger): else: # This is just a quick check to make sure the config file isn't the old 3.x format try: - config = ConfigParser() + config = configparser.ConfigParser() config.read(CONFIG_PATH) config.get('CME', 'workspace') config.get('CME', 'pwn3d_label') diff --git a/cme/protocols/http.py b/cme/protocols/http.py index c250d924..e7dee066 100755 --- a/cme/protocols/http.py +++ b/cme/protocols/http.py @@ -2,7 +2,7 @@ import requests import os from gevent.pool import Pool from gevent.socket import gethostbyname -from urlparse import urlparse +from urllib.parse import urlparse from datetime import datetime from cme.helpers.logger import highlight from cme.logger import CMEAdapter @@ -106,7 +106,7 @@ class single_connection(connection): try: r = requests.get(url, timeout=10, headers={'User-Agent': user_agent}) self.server_headers = r.headers - except ConnectTimeout, ReadTimeout: + except (ConnectTimeout, ReadTimeout): return False except Exception as e: if str(e).find('Read timed out') == -1: diff --git a/cme/protocols/mssql.py b/cme/protocols/mssql.py index b5d0d19c..609a4291 100755 --- a/cme/protocols/mssql.py +++ b/cme/protocols/mssql.py @@ -1,13 +1,13 @@ import socket import logging from cme.logger import CMEAdapter -from StringIO import StringIO +from io import StringIO from cme.protocols.mssql.mssqlexec import MSSQLEXEC from cme.connection import * from cme.helpers.logger import highlight from cme.helpers.powershell import create_ps_command from impacket import tds -from ConfigParser import ConfigParser +import configparser from impacket.smbconnection import SMBConnection, SessionError from impacket.tds import SQLErrorException, TDS_LOGINACK_TOKEN, TDS_ERROR_TOKEN, TDS_ENVCHANGE_TOKEN, TDS_INFO_TOKEN, \ TDS_ENVCHANGE_VARCHAR, TDS_ENVCHANGE_DATABASE, TDS_ENVCHANGE_LANGUAGE, TDS_ENVCHANGE_CHARSET, TDS_ENVCHANGE_PACKETSIZE diff --git a/cme/protocols/smb.py b/cme/protocols/smb.py index 2c158dc4..e313d3e4 100755 --- a/cme/protocols/smb.py +++ b/cme/protocols/smb.py @@ -3,7 +3,7 @@ import socket import os import ntpath -from StringIO import StringIO +from io import StringIO from impacket.smbconnection import SMBConnection, SessionError from impacket.smb import SMB_DIALECT from impacket.examples.secretsdump import RemoteOperations, SAMHashes, LSASecrets, NTDSHashes @@ -184,7 +184,7 @@ class smb(connection): dce.connect() try: dce.bind(MSRPC_UUID_PORTMAP, transfer_syntax=('71710533-BEBA-4937-8319-B5DBEF9CCC36', '1.0')) - except DCERPCException, e: + except (DCERPCException, e): if str(e).find('syntaxes_not_supported') >= 0: dce.disconnect() return 32 @@ -489,7 +489,7 @@ class smb(connection): perms = share['access'] #self.logger.highlight('{:<15} {:<15} {}'.format(name, ','.join(perms), remark)) - self.logger.highlight('{:<15} {:<15} {}'.format(name.encode('utf-8').decode('ascii', 'ignore'), ','.join(perms), remark.encode('utf-8').decode('ascii', 'ignore'))) + self.logger.highlight('{:<15} {:<15} {}'.format(name.encode('utf-8').decode('ascii', 'ignore'), ','.join(perms), remark.encode('utf-8').decode('ascii', 'ignore'))) except Exception as e: self.logger.error('Error enumerating shares: {}'.format(e)) @@ -772,7 +772,7 @@ class smb(connection): sids.append(domainSid + '-%d' % i) try: lsat.hLsarLookupSids(dce, policyHandle, sids,lsat.LSAP_LOOKUP_LEVEL.LsapLookupWksta) - except DCERPCException, e: + except (DCERPCException, e): if str(e).find('STATUS_NONE_MAPPED') >= 0: soFar += SIMULTANEOUS continue diff --git a/cme/protocols/smb/wmiexec.py b/cme/protocols/smb/wmiexec.py index e1df420c..576e6e05 100755 --- a/cme/protocols/smb/wmiexec.py +++ b/cme/protocols/smb/wmiexec.py @@ -56,7 +56,7 @@ class WMIEXEC: def cd(self, s): self.execute_remote('cd ' + s) if len(self.__outputBuffer.strip('\r\n')) > 0: - print self.__outputBuffer + print(self.__outputBuffer) self.__outputBuffer = '' else: self.__pwd = ntpath.normpath(ntpath.join(self.__pwd, s)) diff --git a/cme/protocols/ssh.py b/cme/protocols/ssh.py index e1a5df86..6517b23c 100644 --- a/cme/protocols/ssh.py +++ b/cme/protocols/ssh.py @@ -4,7 +4,7 @@ from cme.connection import * from cme.helpers.logger import highlight from cme.logger import CMEAdapter from paramiko.ssh_exception import AuthenticationException, NoValidConnectionsError, SSHException -from ConfigParser import ConfigParser +import configparser class ssh(connection): diff --git a/cme/protocols/winrm.py b/cme/protocols/winrm.py index d1ff8d22..45979d88 100644 --- a/cme/protocols/winrm.py +++ b/cme/protocols/winrm.py @@ -1,13 +1,13 @@ import winrm as pywinrm import requests import logging -from StringIO import StringIO +from io import StringIO # from winrm.exceptions import InvalidCredentialsError from impacket.smbconnection import SMBConnection, SessionError from cme.connection import * from cme.helpers.logger import highlight from cme.logger import CMEAdapter -from ConfigParser import ConfigParser +import configparser # The following disables the InsecureRequests warning and the 'Starting new HTTPS connection' log message from requests.packages.urllib3.exceptions import InsecureRequestWarning diff --git a/cme/servers/http.py b/cme/servers/http.py index ade0fd15..73ece5c8 100755 --- a/cme/servers/http.py +++ b/cme/servers/http.py @@ -1,10 +1,10 @@ -import BaseHTTPServer +import http.server import threading import ssl import os import sys import logging -from BaseHTTPServer import BaseHTTPRequestHandler +from http.server import BaseHTTPRequestHandler from gevent import sleep from cme.helpers.logger import highlight from cme.logger import CMEAdapter diff --git a/cme/servers/smb.py b/cme/servers/smb.py index a87df786..6124264e 100755 --- a/cme/servers/smb.py +++ b/cme/servers/smb.py @@ -12,7 +12,7 @@ class CMESMBServer(threading.Thread): self.server = smbserver.SimpleSMBServer(listen_address, listen_port) self.server.addShare(share_name.upper(), share_path) if verbose: self.server.setLogFile('') - self.server.setSMB2Support(False) + self.server.setSMB2Support(True) self.server.setSMBChallenge('') except Exception as e: errno, message = e.args diff --git a/cme/thirdparty/impacket b/cme/thirdparty/impacket index a400ca15..10e2a2cc 160000 --- a/cme/thirdparty/impacket +++ b/cme/thirdparty/impacket @@ -1 +1 @@ -Subproject commit a400ca15946c6c1f4d7a9dfc852032510b75816d +Subproject commit 10e2a2cc3bd8c81e97c0aedb821cadab07ca6cbc diff --git a/cme/thirdparty/pywerview b/cme/thirdparty/pywerview index 2dcf6485..cb340028 160000 --- a/cme/thirdparty/pywerview +++ b/cme/thirdparty/pywerview @@ -1 +1 @@ -Subproject commit 2dcf64854b5d111b5ee34b891f7a6480569ab993 +Subproject commit cb340028808b7a1e802d3ace3d40e8f24a56a6c5 From a29cf6760cd5939133eea4fe3fdab88df33a110e Mon Sep 17 00:00:00 2001 From: mpgn Date: Sun, 10 Nov 2019 18:12:35 -0500 Subject: [PATCH 02/13] update python3 --- cme/connection.py | 11 +- cme/context.py | 2 +- cme/logger.py | 2 +- cme/modules/enum_avproducts.py | 4 +- cme/modules/enum_dns.py | 2 +- cme/modules/gpp_password.py | 2 +- cme/protocols/http/db_navigator.py | 2 +- cme/protocols/mssql.py | 12 +- cme/protocols/mssql/db_navigator.py | 12 +- cme/protocols/smb.py | 40 +++--- cme/protocols/smb/database.py | 3 +- cme/protocols/smb/db_navigator.py | 20 +-- cme/protocols/smb/wmiexec.py | 199 ++++++++++++++-------------- cme/protocols/ssh.py | 10 +- cme/protocols/winrm.py | 16 +-- cme/servers/smb.py | 2 +- cme/thirdparty/pywerview | 2 +- 17 files changed, 171 insertions(+), 170 deletions(-) diff --git a/cme/connection.py b/cme/connection.py index fc83a6e3..56fd0174 100755 --- a/cme/connection.py +++ b/cme/connection.py @@ -1,4 +1,5 @@ import logging +from os.path import isfile # from traceback import format_exc from gevent.lock import BoundedSemaphore from gevent.socket import gethostbyname @@ -77,7 +78,7 @@ class connection(object): self.call_cmd_args() def call_cmd_args(self): - for k, v in vars(self.args).iteritems(): + for k, v in vars(self.args).items(): if hasattr(self, k) and hasattr(getattr(self, k), '__call__'): if v is not False and v is not None: logging.debug('Calling {}()'.format(k)) @@ -163,7 +164,7 @@ class connection(object): self.logger.error("Invalid database credential ID!") for user in self.args.username: - if type(user) is file: + if isfile(user): for usr in user: if self.args.hash: with sem: @@ -191,7 +192,7 @@ class connection(object): if self.plaintext_login(self.domain, usr.strip(), f_pass.strip()): return True password.seek(0) - elif type(user) is not file: + elif isfile(user) == False: if hasattr(self.args, 'hash') and self.args.hash: with sem: for ntlm_hash in self.args.hash: @@ -208,14 +209,14 @@ class connection(object): elif self.args.password: with sem: for password in self.args.password: - if type(password) is not file: + if isfile(password) == False: if not self.over_fail_limit(user): if hasattr(self.args, 'domain'): if self.plaintext_login(self.domain, user, password): return True else: if self.plaintext_login(user, password): return True - elif type(password) is file: + elif isfile(password) is file: for f_pass in password: if not self.over_fail_limit(user): if hasattr(self.args, 'domain'): diff --git a/cme/context.py b/cme/context.py index 3dce575b..e65d4f70 100755 --- a/cme/context.py +++ b/cme/context.py @@ -14,5 +14,5 @@ class Context: self.conf = configparser.ConfigParser() self.conf.read(os.path.expanduser('~/.cme/cme.conf')) - for key, value in vars(args).iteritems(): + for key, value in vars(args).items(): setattr(self, key, value) diff --git a/cme/logger.py b/cme/logger.py index ac505660..5efe044e 100755 --- a/cme/logger.py +++ b/cme/logger.py @@ -56,7 +56,7 @@ class CMEAdapter(logging.LoggerAdapter): return u'{:<24} {:<15} {:<6} {:<16} {}'.format(module_name, self.extra['host'], self.extra['port'], - self.extra['hostname'].decode('utf-8') if self.extra['hostname'] else 'NONE', + self.extra['hostname'] if self.extra['hostname'] else 'NONE', msg), kwargs def info(self, msg, *args, **kwargs): diff --git a/cme/modules/enum_avproducts.py b/cme/modules/enum_avproducts.py index 87f95daa..fc8b4e17 100644 --- a/cme/modules/enum_avproducts.py +++ b/cme/modules/enum_avproducts.py @@ -19,12 +19,12 @@ class CMEModule: if output: context.log.success('Found Anti-Spyware product:') for entry in output: - for k,v in entry.iteritems(): + for k,v in entry.items(): context.log.highlight('{} => {}'.format(k,v['value'])) output = connection.wmi('Select * from AntiVirusProduct', 'root\\SecurityCenter2') if output: context.log.success('Found Anti-Virus product:') for entry in output: - for k,v in entry.iteritems(): + for k,v in entry.items(): context.log.highlight('{} => {}'.format(k,v['value'])) \ No newline at end of file diff --git a/cme/modules/enum_dns.py b/cme/modules/enum_dns.py index f5080d41..84b6b273 100644 --- a/cme/modules/enum_dns.py +++ b/cme/modules/enum_dns.py @@ -52,7 +52,7 @@ class CMEModule: else: domain_data[rtype] = ["{}: {}".format(rname, rvalue)] - for k, v in sorted(domain_data.iteritems()): + for k, v in sorted(domain_data.items()): context.log.highlight("Record Type: {}".format(k)) data += "Record Type: {}\n".format(k) for d in sorted(v): diff --git a/cme/modules/gpp_password.py b/cme/modules/gpp_password.py index 2b410f0b..911279f8 100644 --- a/cme/modules/gpp_password.py +++ b/cme/modules/gpp_password.py @@ -68,7 +68,7 @@ class CMEModule: context.log.success('Found credentials in {}'.format(path)) context.log.highlight('Password: {}'.format(password)) - for k,v in props.iteritems(): + for k,v in props.items(): if k != 'cpassword': context.log.highlight('{}: {}'.format(k, v)) diff --git a/cme/protocols/http/db_navigator.py b/cme/protocols/http/db_navigator.py index 8df70aba..f49c4416 100644 --- a/cme/protocols/http/db_navigator.py +++ b/cme/protocols/http/db_navigator.py @@ -13,7 +13,7 @@ class navigator(DatabaseNavigator): # links = self.db.get_links(credID=credID) - data.append([credID, url.decode('utf-8'), username.decode('utf-8'), password.decode('utf-8')]) + data.append([credID, url, username, password]) self.print_table(data, title='Credential(s)') diff --git a/cme/protocols/mssql.py b/cme/protocols/mssql.py index 609a4291..6e28bd9f 100755 --- a/cme/protocols/mssql.py +++ b/cme/protocols/mssql.py @@ -170,9 +170,9 @@ class mssql(connection): if self.admin_privs: self.db.add_admin_user('plaintext', domain, username, password, self.host) - out = u'{}{}:{} {}'.format('{}\\'.format(domain.decode('utf-8')) if self.args.auth_type is 'windows' else '', - username.decode('utf-8'), - password.decode('utf-8'), + out = u'{}{}:{} {}'.format('{}\\'.format(domain) if self.args.auth_type is 'windows' else '', + username, + password, highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else '')) self.logger.success(out) return True @@ -201,8 +201,8 @@ class mssql(connection): if self.admin_privs: self.db.add_admin_user('hash', domain, username, ntlm_hash, self.host) - out = u'{}\\{} {} {}'.format(domain.decode('utf-8'), - username.decode('utf-8'), + out = u'{}\\{} {} {}'.format(domain, + username, ntlm_hash, highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else '')) @@ -230,7 +230,7 @@ class mssql(connection): if hasattr(self, 'server'): self.server.track_host(self.host) - output = u'{}'.format(raw_output.decode('utf-8')) + output = u'{}'.format(raw_output) if self.args.execute or self.args.ps_execute: #self.logger.success('Executed command {}'.format('via {}'.format(self.args.exec_method) if self.args.exec_method else '')) diff --git a/cme/protocols/mssql/db_navigator.py b/cme/protocols/mssql/db_navigator.py index b0484e68..4eb17f4e 100644 --- a/cme/protocols/mssql/db_navigator.py +++ b/cme/protocols/mssql/db_navigator.py @@ -19,7 +19,7 @@ class navigator(DatabaseNavigator): links = self.db.get_admin_relations(userID=credID) - data.append([credID, str(len(links)) + ' Host(s)', credtype, domain.decode('utf-8'), username.decode('utf-8'), password.decode('utf-8')]) + data.append([credID, str(len(links)) + ' Host(s)', credtype, domain, username, password]) self.print_table(data, title='Credentials') @@ -38,7 +38,7 @@ class navigator(DatabaseNavigator): links = self.db.get_admin_relations(hostID=hostID) - data.append([hostID, str(len(links)) + ' Cred(s)', ip, hostname.decode('utf-8'), domain.decode('utf-8'), os, instances]) + data.append([hostID, str(len(links)) + ' Cred(s)', ip, hostname, domain, os, instances]) self.print_table(data, title='Hosts') @@ -67,7 +67,7 @@ class navigator(DatabaseNavigator): domain = host[3] os = host[4] - data.append([hostID, ip, hostname.decode('utf-8'), domain.decode('utf-8'), os]) + data.append([hostID, ip, hostname, domain, os]) self.print_table(data, title='Host(s)') @@ -87,7 +87,7 @@ class navigator(DatabaseNavigator): credtype = cred[4] # pillaged_from = cred[5] - data.append([credID, credtype, domain.decode('utf-8'), username.decode('utf-8'), password.decode('utf-8')]) + data.append([credID, credtype, domain, username, password]) self.print_table(data, title='Credential(s) with Admin Access') @@ -146,7 +146,7 @@ class navigator(DatabaseNavigator): username = cred[3] password = cred[4] - data.append([credID, credType, domain.decode('utf-8'), username.decode('utf-8'), password.decode('utf-8')]) + data.append([credID, credType, domain, username, password]) self.print_table(data, title='Credential(s)') @@ -165,7 +165,7 @@ class navigator(DatabaseNavigator): domain = host[3] os = host[4] - data.append([hostID, ip, hostname.decode('utf-8'), domain.decode('utf-8'), os]) + data.append([hostID, ip, hostname, domain, os]) self.print_table(data, title='Admin Access to Host(s)') diff --git a/cme/protocols/smb.py b/cme/protocols/smb.py index e313d3e4..fc9222ee 100755 --- a/cme/protocols/smb.py +++ b/cme/protocols/smb.py @@ -60,13 +60,13 @@ def requires_smb_server(func): except IndexError: pass - if kwargs.has_key('payload'): + if 'payload' in kwargs: payload = kwargs['payload'] - if kwargs.has_key('get_output'): + if 'get_output' in kwargs: get_output = kwargs['get_output'] - if kwargs.has_key('methods'): + if 'methods' in kwargs: methods = kwargs['methods'] if not payload and self.args.execute: @@ -202,9 +202,9 @@ class smb(connection): try: self.conn.login('' , '') - except SessionError as e: - if "STATUS_ACCESS_DENIED" in e.message: - pass + except: + #if "STATUS_ACCESS_DENIED" in e: + pass self.domain = self.conn.getServerDomain() self.hostname = self.conn.getServerName() @@ -240,8 +240,8 @@ class smb(connection): def print_host_info(self): self.logger.info(u"{}{} (name:{}) (domain:{}) (signing:{}) (SMBv1:{})".format(self.server_os, ' x{}'.format(self.os_arch) if self.os_arch else '', - self.hostname.decode('utf-8'), - self.domain.decode('utf-8'), + self.hostname, + self.domain, self.signing, self.smbv1)) @@ -258,9 +258,9 @@ class smb(connection): if self.admin_privs: self.db.add_admin_user('plaintext', domain, username, password, self.host) - out = u'{}\\{}:{} {}'.format(domain.decode('utf-8'), - username.decode('utf-8'), - password.decode('utf-8'), + out = u'{}\\{}:{} {}'.format(domain, + username, + password, highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else '')) self.logger.success(out) @@ -268,9 +268,9 @@ class smb(connection): return True except SessionError as e: error, desc = e.getErrorString() - self.logger.error(u'{}\\{}:{} {} {}'.format(domain.decode('utf-8'), - username.decode('utf-8'), - password.decode('utf-8'), + self.logger.error(u'{}\\{}:{} {} {}'.format(domain, + username, + password, error, '({})'.format(desc) if self.args.verbose else '')) @@ -303,8 +303,8 @@ class smb(connection): if self.admin_privs: self.db.add_admin_user('hash', domain, username, ntlm_hash, self.host) - out = u'{}\\{} {} {}'.format(domain.decode('utf-8'), - username.decode('utf-8'), + out = u'{}\\{} {} {}'.format(domain, + username, ntlm_hash, highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else '')) @@ -313,8 +313,8 @@ class smb(connection): return True except SessionError as e: error, desc = e.getErrorString() - self.logger.error(u'{}\\{} {} {} {}'.format(domain.decode('utf-8'), - username.decode('utf-8'), + self.logger.error(u'{}\\{} {} {} {}'.format(domain, + username, ntlm_hash, error, '({})'.format(desc) if self.args.verbose else '')) @@ -431,7 +431,7 @@ class smb(connection): if hasattr(self, 'server'): self.server.track_host(self.host) - output = u'{}'.format(exec_method.execute(payload, get_output).strip().decode('utf-8',errors='replace')) + output = u'{}'.format(exec_method.execute(payload, get_output).strip()) if self.args.execute or self.args.ps_execute: self.logger.success('Executed command {}'.format('via {}'.format(self.args.exec_method) if self.args.exec_method else '')) @@ -683,7 +683,7 @@ class smb(connection): wmi_results = query.Next(0xffffffff, 1)[0] record = wmi_results.getProperties() records.append(record) - for k,v in record.iteritems(): + for k,v in record.items(): self.logger.highlight('{} => {}'.format(k,v['value'])) self.logger.highlight('') except Exception as e: diff --git a/cme/protocols/smb/database.py b/cme/protocols/smb/database.py index a7288416..b8474e44 100755 --- a/cme/protocols/smb/database.py +++ b/cme/protocols/smb/database.py @@ -141,8 +141,7 @@ class database: cur.close() - logging.debug('add_credential(credtype={}, domain={}, username={}, password={}, groupid={}, pillaged_from={}) => {}'.encode().format(credtype, domain, username, password, - groupid, pillaged_from, user_rowid)) + logging.debug('add_credential(credtype={}, domain={}, username={}, password={}, groupid={}, pillaged_from={}) => {}'.format(credtype, domain, username, password, groupid, pillaged_from, user_rowid)) return user_rowid diff --git a/cme/protocols/smb/db_navigator.py b/cme/protocols/smb/db_navigator.py index 7324a9d0..efa5c4ff 100644 --- a/cme/protocols/smb/db_navigator.py +++ b/cme/protocols/smb/db_navigator.py @@ -19,7 +19,7 @@ class navigator(DatabaseNavigator): links = self.db.get_admin_relations(userID=credID) - data.append([credID, str(len(links)) + ' Host(s)', credtype, domain.decode('utf-8'), username.decode('utf-8'), password.decode('utf-8')]) + data.append([credID, str(len(links)) + ' Host(s)', credtype, domain, username, password]) self.print_table(data, title='Credentials') @@ -33,7 +33,7 @@ class navigator(DatabaseNavigator): name = group[2] members = len(self.db.get_group_relations(groupID=groupID)) - data.append([groupID, domain.decode('utf-8'), name, members]) + data.append([groupID, domain, name, members]) self.print_table(data, title='Groups') @@ -51,7 +51,7 @@ class navigator(DatabaseNavigator): links = self.db.get_admin_relations(hostID=hostID) - data.append([hostID, str(len(links)) + ' Cred(s)', ip, hostname.decode('utf-8'), domain.decode('utf-8'), os]) + data.append([hostID, str(len(links)) + ' Cred(s)', ip, hostname, domain, os]) self.print_table(data, title='Hosts') @@ -77,7 +77,7 @@ class navigator(DatabaseNavigator): domain = group[1] name = group[2] - data.append([groupID, domain.decode('utf-8'), name.decode('utf-8')]) + data.append([groupID, domain, name]) self.print_table(data, title='Group') @@ -98,7 +98,7 @@ class navigator(DatabaseNavigator): credtype = cred[4] pillaged_from = cred[5] - data.append([credID, credtype, pillaged_from, domain.decode('utf-8'), username.decode('utf-8'), password.decode('utf-8')]) + data.append([credID, credtype, pillaged_from, domain, username, password]) self.print_table(data, title='Member(s)') @@ -128,7 +128,7 @@ class navigator(DatabaseNavigator): os = host[4] dc = host[5] - data.append([hostID, ip, hostname.decode('utf-8'), domain.decode('utf-8'), os, dc]) + data.append([hostID, ip, hostname, domain, os, dc]) self.print_table(data, title='Host(s)') @@ -148,7 +148,7 @@ class navigator(DatabaseNavigator): credtype = cred[4] # pillaged_from = cred[5] - data.append([credID, credtype, domain.decode('utf-8'), username.decode('utf-8'), password.decode('utf-8')]) + data.append([credID, credtype, domain, username, password]) self.print_table(data, title='Credential(s) with Admin Access') @@ -212,7 +212,7 @@ class navigator(DatabaseNavigator): credtype = cred[4] pillaged_from = cred[5] - data.append([credID, credtype, pillaged_from, domain.decode('utf-8'), username.decode('utf-8'), password.decode('utf-8')]) + data.append([credID, credtype, pillaged_from, domain, username, password]) self.print_table(data, title='Credential(s)') @@ -229,7 +229,7 @@ class navigator(DatabaseNavigator): domain = group[1] name = group[2] - data.append([groupID, domain.decode('utf-8'), name.decode('utf-8')]) + data.append([groupID, domain, name]) self.print_table(data, title='Member of Group(s)') @@ -248,7 +248,7 @@ class navigator(DatabaseNavigator): domain = host[3] os = host[4] - data.append([hostID, ip, hostname.decode('utf-8'), domain.decode('utf-8'), os]) + data.append([hostID, ip, hostname, domain, os]) self.print_table(data, title='Admin Access to Host(s)') diff --git a/cme/protocols/smb/wmiexec.py b/cme/protocols/smb/wmiexec.py index 576e6e05..e06b4180 100755 --- a/cme/protocols/smb/wmiexec.py +++ b/cme/protocols/smb/wmiexec.py @@ -8,121 +8,122 @@ from impacket.dcerpc.v5.dcom import wmi from impacket.dcerpc.v5.dtypes import NULL class WMIEXEC: - def __init__(self, target, share_name, username, password, domain, smbconnection, hashes=None, share=None): - self.__target = target - self.__username = username - self.__password = password - self.__domain = domain - self.__lmhash = '' - self.__nthash = '' - self.__share = share - self.__smbconnection = smbconnection - self.__output = None - self.__outputBuffer = '' - self.__share_name = share_name - self.__shell = 'cmd.exe /Q /c ' - self.__pwd = 'C:\\' - self.__aesKey = None - self.__doKerberos = False - self.__retOutput = True + def __init__(self, target, share_name, username, password, domain, smbconnection, hashes=None, share=None): + self.__target = target + self.__username = username + self.__password = password + self.__domain = domain + self.__lmhash = '' + self.__nthash = '' + self.__share = share + self.__smbconnection = smbconnection + self.__output = None + self.__outputBuffer = '' + self.__share_name = share_name + self.__shell = 'cmd.exe /Q /c ' + self.__pwd = 'C:\\' + self.__aesKey = None + self.__doKerberos = False + self.__retOutput = True - if hashes is not None: - #This checks to see if we didn't provide the LM Hash - if hashes.find(':') != -1: - self.__lmhash, self.__nthash = hashes.split(':') - else: - self.__nthash = hashes + if hashes is not None: + #This checks to see if we didn't provide the LM Hash + if hashes.find(':') != -1: + self.__lmhash, self.__nthash = hashes.split(':') + else: + self.__nthash = hashes - if self.__password is None: - self.__password = '' + if self.__password is None: + self.__password = '' - self.__dcom = DCOMConnection(self.__target, self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, oxidResolver = True, doKerberos=self.__doKerberos) - iInterface = self.__dcom.CoCreateInstanceEx(wmi.CLSID_WbemLevel1Login,wmi.IID_IWbemLevel1Login) - iWbemLevel1Login = wmi.IWbemLevel1Login(iInterface) - iWbemServices= iWbemLevel1Login.NTLMLogin('//./root/cimv2', NULL, NULL) - iWbemLevel1Login.RemRelease() + self.__dcom = DCOMConnection(self.__target, self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, oxidResolver = True, doKerberos=self.__doKerberos) + iInterface = self.__dcom.CoCreateInstanceEx(wmi.CLSID_WbemLevel1Login,wmi.IID_IWbemLevel1Login) + iWbemLevel1Login = wmi.IWbemLevel1Login(iInterface) + iWbemServices= iWbemLevel1Login.NTLMLogin('//./root/cimv2', NULL, NULL) + iWbemLevel1Login.RemRelease() - self.__win32Process,_ = iWbemServices.GetObject('Win32_Process') + self.__win32Process,_ = iWbemServices.GetObject('Win32_Process') - def execute(self, command, output=False): - self.__retOutput = output - if self.__retOutput: - self.__smbconnection.setTimeout(100000) + def execute(self, command, output=False): + self.__retOutput = output + if self.__retOutput: + self.__smbconnection.setTimeout(100000) - self.execute_handler(command) - self.__dcom.disconnect() - return self.__outputBuffer + self.execute_handler(command) + self.__dcom.disconnect() + return self.__outputBuffer - def cd(self, s): - self.execute_remote('cd ' + s) - if len(self.__outputBuffer.strip('\r\n')) > 0: - print(self.__outputBuffer) - self.__outputBuffer = '' - else: - self.__pwd = ntpath.normpath(ntpath.join(self.__pwd, s)) - self.execute_remote('cd ') - self.__pwd = self.__outputBuffer.strip('\r\n') - self.__outputBuffer = '' + def cd(self, s): + self.execute_remote('cd ' + s) + if len(self.__outputBuffer.strip('\r\n')) > 0: + print(self.__outputBuffer) + self.__outputBuffer = '' + else: + self.__pwd = ntpath.normpath(ntpath.join(self.__pwd, s)) + self.execute_remote('cd ') + self.__pwd = self.__outputBuffer.strip('\r\n') + self.__outputBuffer = '' - def output_callback(self, data): - self.__outputBuffer += data + def output_callback(self, data): + self.__outputBuffer += data.decode("utf-8") - def execute_handler(self, data): - if self.__retOutput: - try: - self.execute_fileless(data) - except: - self.cd('\\') - self.execute_remote(data) - else: - self.execute_remote(data) + def execute_handler(self, data): + if self.__retOutput: + try: + logging.debug('Executing remote') + self.execute_remote(data) + except: + self.cd('\\') + self.execute_remote(data) + else: + self.execute_remote(data) - def execute_remote(self, data): - self.__output = '\\Windows\\Temp\\' + gen_random_string(6) + def execute_remote(self, data): + self.__output = '\\Windows\\Temp\\' + gen_random_string(6) - command = self.__shell + data - if self.__retOutput: - command += ' 1> ' + '\\\\127.0.0.1\\%s' % self.__share + self.__output + ' 2>&1' + command = self.__shell + data + if self.__retOutput: + command += ' 1> ' + '\\\\127.0.0.1\\%s' % self.__share + self.__output + ' 2>&1' - logging.debug('Executing command: ' + command) - self.__win32Process.Create(command, self.__pwd, None) - self.get_output_remote() + logging.debug('Executing command: ' + command) + self.__win32Process.Create(command, self.__pwd, None) + self.get_output_remote() - def execute_fileless(self, data): - self.__output = gen_random_string(6) - local_ip = self.__smbconnection.getSMBServer().get_socket().getsockname()[0] + def execute_fileless(self, data): + self.__output = gen_random_string(6) + local_ip = self.__smbconnection.getSMBServer().get_socket().getsockname()[0] - command = self.__shell + data + ' 1> \\\\{}\\{}\\{} 2>&1'.format(local_ip, self.__share_name, self.__output) + command = self.__shell + data + ' 1> \\\\{}\\{}\\{} 2>&1'.format(local_ip, self.__share_name, self.__output) - logging.debug('Executing command: ' + command) - self.__win32Process.Create(command, self.__pwd, None) - self.get_output_fileless() + logging.debug('Executing command: ' + command) + self.__win32Process.Create(command, self.__pwd, None) + self.get_output_fileless() - def get_output_fileless(self): - while True: - try: - with open(os.path.join('/tmp', 'cme_hosted', self.__output), 'r') as output: - self.output_callback(output.read()) - break - except IOError: - sleep(2) + def get_output_fileless(self): + while True: + try: + with open(os.path.join('/tmp', 'cme_hosted', self.__output), 'r') as output: + self.output_callback(output.read()) + break + except IOError: + sleep(2) - def get_output_remote(self): - if self.__retOutput is False: - self.__outputBuffer = '' - return + def get_output_remote(self): + if self.__retOutput is False: + self.__outputBuffer = '' + return - while True: - try: - self.__smbconnection.getFile(self.__share, self.__output, self.output_callback) - break - except Exception as e: - if str(e).find('STATUS_SHARING_VIOLATION') >=0: - # Output not finished, let's wait - sleep(2) - pass - else: - #print str(e) - pass + while True: + try: + self.__smbconnection.getFile(self.__share, self.__output, self.output_callback) + break + except Exception as e: + if str(e).find('STATUS_SHARING_VIOLATION') >=0: + # Output not finished, let's wait + sleep(2) + pass + else: + #print str(e) + pass - self.__smbconnection.deleteFile(self.__share, self.__output) + self.__smbconnection.deleteFile(self.__share, self.__output) diff --git a/cme/protocols/ssh.py b/cme/protocols/ssh.py index 6517b23c..5d7367e4 100644 --- a/cme/protocols/ssh.py +++ b/cme/protocols/ssh.py @@ -58,14 +58,14 @@ class ssh(connection): self.conn.connect(self.host, port=self.args.port, username=username, password=password) self.check_if_admin() - self.logger.success(u'{}:{} {}'.format(username.decode('utf-8'), - password.decode('utf-8'), + self.logger.success(u'{}:{} {}'.format(username, + password, highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else ''))) return True except Exception as e: - self.logger.error(u'{}:{} {}'.format(username.decode('utf-8'), - password.decode('utf-8'), + self.logger.error(u'{}:{} {}'.format(username, + password, e)) return False @@ -74,6 +74,6 @@ class ssh(connection): stdin, stdout, stderr = self.conn.exec_command(self.args.execute) self.logger.success('Executed command') for line in stdout: - self.logger.highlight(line.decode('utf-8').strip()) + self.logger.highlight(line.strip()) return stdout diff --git a/cme/protocols/winrm.py b/cme/protocols/winrm.py index 45979d88..bed7013a 100644 --- a/cme/protocols/winrm.py +++ b/cme/protocols/winrm.py @@ -118,17 +118,17 @@ class winrm(connection): # we could just authenticate without running a command :) (probably) self.conn.run_cmd('hostname') self.admin_privs = True - self.logger.success(u'{}\\{}:{} {}'.format(self.domain.decode('utf-8'), - username.decode('utf-8'), - password.decode('utf-8'), + self.logger.success(u'{}\\{}:{} {}'.format(self.domain, + username, + password, highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else ''))) return True except Exception as e: - self.logger.error(u'{}\\{}:{} "{}"'.format(self.domain.decode('utf-8'), - username.decode('utf-8'), - password.decode('utf-8'), + self.logger.error(u'{}\\{}:{} "{}"'.format(self.domain, + username, + password, e)) return False @@ -137,14 +137,14 @@ class winrm(connection): if response_obj.status_code == 0: buf = StringIO(response_obj.std_out).readlines() for line in buf: - self.logger.highlight(line.decode('utf-8').strip()) + self.logger.highlight(line.strip()) return response_obj.std_out else: buf = StringIO(response_obj.std_err).readlines() for line in buf: - self.logger.highlight(line.decode('utf-8').strip()) + self.logger.highlight(line.strip()) return response_obj.std_err diff --git a/cme/servers/smb.py b/cme/servers/smb.py index 6124264e..715d6b63 100755 --- a/cme/servers/smb.py +++ b/cme/servers/smb.py @@ -32,7 +32,7 @@ class CMESMBServer(threading.Thread): pass def shutdown(self): - self._Thread__stop() + #self._Thread__stop() # make sure all the threads are killed for thread in threading.enumerate(): if thread.isAlive(): diff --git a/cme/thirdparty/pywerview b/cme/thirdparty/pywerview index cb340028..2dcf6485 160000 --- a/cme/thirdparty/pywerview +++ b/cme/thirdparty/pywerview @@ -1 +1 @@ -Subproject commit cb340028808b7a1e802d3ace3d40e8f24a56a6c5 +Subproject commit 2dcf64854b5d111b5ee34b891f7a6480569ab993 From 73ab379acc1fc493a23124bfe459a4d94dbd7896 Mon Sep 17 00:00:00 2001 From: mpgn Date: Mon, 11 Nov 2019 05:06:39 -0500 Subject: [PATCH 03/13] Migrate function to python3 * --shares -> OK * --sessions -> OK * --disks -> OK * --loggedon-users -> OK * --users -> Not tested * --rid-brute -> OK * --groups -> Not tested * --local-groups -> OK * --pass-pol -> OK --- README.md | 2 +- cme/cmedb.py | 2 +- cme/crackmapexec.py | 2 +- cme/msfrpc.py | 2 +- cme/protocols/smb.py | 13 ++++++------- cme/protocols/smb/atexec.py | 2 +- cme/protocols/smb/mmcexec.py | 2 +- cme/protocols/smb/passpol.py | 4 +--- cme/protocols/smb/smbexec.py | 2 +- 9 files changed, 14 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index cfc1bfc7..e3756c9c 100755 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![Supported Python versions](https://img.shields.io/badge/python-2.7-blue.svg) +![Supported Python versions](https://img.shields.io/badge/python-3.6+-blue.svg) # CrackMapExec diff --git a/cme/cmedb.py b/cme/cmedb.py index c6237c84..05101ea5 100755 --- a/cme/cmedb.py +++ b/cme/cmedb.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import cmd import sqlite3 import sys diff --git a/cme/crackmapexec.py b/cme/crackmapexec.py index 5a819e83..7725f952 100755 --- a/cme/crackmapexec.py +++ b/cme/crackmapexec.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 from gevent.pool import Pool from gevent import sleep diff --git a/cme/msfrpc.py b/cme/msfrpc.py index 136ba755..324025fc 100755 --- a/cme/msfrpc.py +++ b/cme/msfrpc.py @@ -1,4 +1,4 @@ -#! /usr/bin/env python2.7 +#! /usr/bin/env python3 # MSF-RPC - A Python library to facilitate MSG-RPC communication with Metasploit diff --git a/cme/protocols/smb.py b/cme/protocols/smb.py index fc9222ee..67545c93 100755 --- a/cme/protocols/smb.py +++ b/cme/protocols/smb.py @@ -488,8 +488,7 @@ class smb(connection): remark = share['remark'] perms = share['access'] - #self.logger.highlight('{:<15} {:<15} {}'.format(name, ','.join(perms), remark)) - self.logger.highlight('{:<15} {:<15} {}'.format(name.encode('utf-8').decode('ascii', 'ignore'), ','.join(perms), remark.encode('utf-8').decode('ascii', 'ignore'))) + self.logger.highlight(u'{:<15} {:<15} {}'.format(name, ','.join(perms), remark)) except Exception as e: self.logger.error('Error enumerating shares: {}'.format(e)) @@ -749,7 +748,7 @@ class smb(connection): self.logger.success('Brute forcing RIDs') dce.bind(lsat.MSRPC_UUID_LSAT) - resp = lsat.hLsarOpenPolicy2(dce, MAXIMUM_ALLOWED | lsat.POLICY_LOOKUP_NAMES) + resp = lsad.hLsarOpenPolicy2(dce, MAXIMUM_ALLOWED | lsat.POLICY_LOOKUP_NAMES) policyHandle = resp['PolicyHandle'] resp = lsad.hLsarQueryInformationPolicy2(dce, policyHandle, lsad.POLICY_INFORMATION_CLASS.PolicyAccountDomainInformation) @@ -758,8 +757,8 @@ class smb(connection): soFar = 0 SIMULTANEOUS = 1000 - for j in range(maxRid/SIMULTANEOUS+1): - if (maxRid - soFar) / SIMULTANEOUS == 0: + for j in range(maxRid//SIMULTANEOUS+1): + if (maxRid - soFar) // SIMULTANEOUS == 0: sidsToCheck = (maxRid - soFar) % SIMULTANEOUS else: sidsToCheck = SIMULTANEOUS @@ -768,11 +767,11 @@ class smb(connection): break sids = list() - for i in xrange(soFar, soFar+sidsToCheck): + for i in range(soFar, soFar+sidsToCheck): sids.append(domainSid + '-%d' % i) try: lsat.hLsarLookupSids(dce, policyHandle, sids,lsat.LSAP_LOOKUP_LEVEL.LsapLookupWksta) - except (DCERPCException, e): + except DCERPCException as e: if str(e).find('STATUS_NONE_MAPPED') >= 0: soFar += SIMULTANEOUS continue diff --git a/cme/protocols/smb/atexec.py b/cme/protocols/smb/atexec.py index 043cae74..82826f7d 100755 --- a/cme/protocols/smb/atexec.py +++ b/cme/protocols/smb/atexec.py @@ -43,7 +43,7 @@ class TSCH_EXEC: return self.__outputBuffer def output_callback(self, data): - self.__outputBuffer = data + self.__outputBuffer = data.decode("utf-8") def execute_handler(self, data): if self.__retOutput: diff --git a/cme/protocols/smb/mmcexec.py b/cme/protocols/smb/mmcexec.py index 4552d087..929c3532 100644 --- a/cme/protocols/smb/mmcexec.py +++ b/cme/protocols/smb/mmcexec.py @@ -175,7 +175,7 @@ class MMCEXEC: self.get_output_fileless() def output_callback(self, data): - self.__outputBuffer += data + self.__outputBuffer += data.decode("utf-8") def get_output_fileless(self): if not self.__retOutput: return diff --git a/cme/protocols/smb/passpol.py b/cme/protocols/smb/passpol.py index aa1692bc..91b02257 100644 --- a/cme/protocols/smb/passpol.py +++ b/cme/protocols/smb/passpol.py @@ -13,7 +13,7 @@ def d2b(a): t2bin = tbin[::-1] if len(t2bin) != 8: - for x in xrange(6 - len(t2bin)): + for x in range(6 - len(t2bin)): t2bin.insert(0, 0) return ''.join([str(g) for g in t2bin]) @@ -100,11 +100,9 @@ class PassPolDump: port = protodef[1] except KeyError: self.logger.debug("Invalid Protocol '{}'".format(protocol)) - self.logger.debug("Trying protocol {}".format(protocol)) rpctransport = transport.SMBTransport(self.addr, port, r'\samr', self.username, self.password, self.domain, self.lmhash, self.nthash, self.aesKey, doKerberos = self.doKerberos) - try: self.fetchList(rpctransport) except Exception as e: diff --git a/cme/protocols/smb/smbexec.py b/cme/protocols/smb/smbexec.py index 3c0cd6e5..921b63fd 100755 --- a/cme/protocols/smb/smbexec.py +++ b/cme/protocols/smb/smbexec.py @@ -69,7 +69,7 @@ class SMBEXEC: return self.__outputBuffer def output_callback(self, data): - self.__outputBuffer += data + self.__outputBuffer += data.decode("utf-8") def execute_fileless(self, data): self.__output = gen_random_string(6) From d2c477aafbb4cf6de0da7228148c64ab3ea749b4 Mon Sep 17 00:00:00 2001 From: mpgn Date: Mon, 11 Nov 2019 05:39:44 -0500 Subject: [PATCH 04/13] Migrate file option input * -u user.txt * -p password.txt * -H hashntlm --- cme/connection.py | 20 ++++++++++---------- pass.txt | 1 + user.txt | 1 + 3 files changed, 12 insertions(+), 10 deletions(-) create mode 100644 pass.txt create mode 100644 user.txt diff --git a/cme/connection.py b/cme/connection.py index 56fd0174..43d9c8c9 100755 --- a/cme/connection.py +++ b/cme/connection.py @@ -164,16 +164,16 @@ class connection(object): self.logger.error("Invalid database credential ID!") for user in self.args.username: - if isfile(user): + if not isinstance(user, str) and isfile(user.name): for usr in user: if self.args.hash: with sem: for ntlm_hash in self.args.hash: - if type(ntlm_hash) is not file: + if isinstance(ntlm_hash, str): if not self.over_fail_limit(usr.strip()): if self.hash_login(self.domain, usr.strip(), ntlm_hash): return True - elif type(ntlm_hash) is file: + elif not isinstance(ntlm_hash, str) and isfile(ntlm_hash.name): for f_hash in ntlm_hash: if not self.over_fail_limit(usr.strip()): if self.hash_login(self.domain, usr.strip(), f_hash.strip()): return True @@ -182,25 +182,25 @@ class connection(object): elif self.args.password: with sem: for password in self.args.password: - if type(password) is not file: + if isinstance(password, str): if not self.over_fail_limit(usr.strip()): if self.plaintext_login(self.domain, usr.strip(), password): return True - elif type(password) is file: + elif not isinstance(password, str) and isfile(password.name): for f_pass in password: if not self.over_fail_limit(usr.strip()): if self.plaintext_login(self.domain, usr.strip(), f_pass.strip()): return True password.seek(0) - elif isfile(user) == False: + elif isinstance(user, str): if hasattr(self.args, 'hash') and self.args.hash: with sem: for ntlm_hash in self.args.hash: - if type(ntlm_hash) is not file: + if isinstance(ntlm_hash, str): if not self.over_fail_limit(user): if self.hash_login(self.domain, user, ntlm_hash): return True - elif type(ntlm_hash) is file: + elif not isinstance(ntlm_hash, str) and isfile(ntlm_hash.name): for f_hash in ntlm_hash: if not self.over_fail_limit(user): if self.hash_login(self.domain, user, f_hash.strip()): return True @@ -209,14 +209,14 @@ class connection(object): elif self.args.password: with sem: for password in self.args.password: - if isfile(password) == False: + if isinstance(password, str): if not self.over_fail_limit(user): if hasattr(self.args, 'domain'): if self.plaintext_login(self.domain, user, password): return True else: if self.plaintext_login(user, password): return True - elif isfile(password) is file: + elif not isinstance(password, str) and isfile(password.name): for f_pass in password: if not self.over_fail_limit(user): if hasattr(self.args, 'domain'): diff --git a/pass.txt b/pass.txt new file mode 100644 index 00000000..62a3209f --- /dev/null +++ b/pass.txt @@ -0,0 +1 @@ +ria700 diff --git a/user.txt b/user.txt new file mode 100644 index 00000000..366214b4 --- /dev/null +++ b/user.txt @@ -0,0 +1 @@ +Administrator From dee4b9079233e803af47762d70a8419dfa71266f Mon Sep 17 00:00:00 2001 From: mpgn Date: Mon, 11 Nov 2019 05:41:37 -0500 Subject: [PATCH 05/13] remove useless testing files --- pass.txt | 1 - user.txt | 1 - 2 files changed, 2 deletions(-) delete mode 100644 pass.txt delete mode 100644 user.txt diff --git a/pass.txt b/pass.txt deleted file mode 100644 index 62a3209f..00000000 --- a/pass.txt +++ /dev/null @@ -1 +0,0 @@ -ria700 diff --git a/user.txt b/user.txt deleted file mode 100644 index 366214b4..00000000 --- a/user.txt +++ /dev/null @@ -1 +0,0 @@ -Administrator From 179dfef81162362e5c561eb4baa75c5bcfdd530f Mon Sep 17 00:00:00 2001 From: mpgn Date: Mon, 11 Nov 2019 06:26:38 -0500 Subject: [PATCH 06/13] Fix mimikatz range issue --- cme/modules/mimikatz.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cme/modules/mimikatz.py b/cme/modules/mimikatz.py index a6fe6c98..0312f146 100644 --- a/cme/modules/mimikatz.py +++ b/cme/modules/mimikatz.py @@ -128,7 +128,7 @@ class CMEModule: if len(creds) == 0: # check if we have lsadump output to check for krbtgt # happens on domain controller hashdumps - for x in xrange(8,13): + for x in range(8,13): if lines[x].startswith("Domain :"): domain, sid, krbtgtHash = "", "", "" @@ -143,7 +143,7 @@ class CMEModule: domain = hostDomain sid = domainSid - for x in xrange(0, len(lines)): + for x in range(0, len(lines)): if lines[x].startswith("User : krbtgt"): krbtgtHash = lines[x+2].split(":")[1].strip() break From 38acbbead598b437546e9f62b03486c5e9332b48 Mon Sep 17 00:00:00 2001 From: mpgn Date: Tue, 12 Nov 2019 13:33:14 -0500 Subject: [PATCH 07/13] Fix option --pass-pol in python3 error due to : python2 => 1 / 2 = 0 python3 => 1 / 2 = 0.5 python3 => 1 // 2 = 0 --- cme/protocols/smb/passpol.py | 2 +- cme/thirdparty/pywerview | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cme/protocols/smb/passpol.py b/cme/protocols/smb/passpol.py index 91b02257..81766741 100644 --- a/cme/protocols/smb/passpol.py +++ b/cme/protocols/smb/passpol.py @@ -9,7 +9,7 @@ def d2b(a): tbin = [] while a: tbin.append(a % 2) - a /= 2 + a //= 2 t2bin = tbin[::-1] if len(t2bin) != 8: diff --git a/cme/thirdparty/pywerview b/cme/thirdparty/pywerview index 2dcf6485..2156da64 160000 --- a/cme/thirdparty/pywerview +++ b/cme/thirdparty/pywerview @@ -1 +1 @@ -Subproject commit 2dcf64854b5d111b5ee34b891f7a6480569ab993 +Subproject commit 2156da6431b278bc60f22cf4b66bd671f7d0a0fe From c2698ba8edc456dc6e057651c007ef9d17462ca9 Mon Sep 17 00:00:00 2001 From: mpgn Date: Tue, 12 Nov 2019 14:42:45 -0500 Subject: [PATCH 08/13] Fix HTTP server for module Mimikatz --- cme/modules/mimikittenz.py | 2 +- cme/servers/http.py | 2 +- cme/thirdparty/pywerview | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cme/modules/mimikittenz.py b/cme/modules/mimikittenz.py index b78f1b5f..343926d4 100644 --- a/cme/modules/mimikittenz.py +++ b/cme/modules/mimikittenz.py @@ -1,6 +1,6 @@ from cme.helpers.powershell import * from cme.helpers.logger import write_log -from StringIO import StringIO +from io import StringIO from datetime import datetime class CMEModule: diff --git a/cme/servers/http.py b/cme/servers/http.py index 73ece5c8..09486b58 100755 --- a/cme/servers/http.py +++ b/cme/servers/http.py @@ -45,7 +45,7 @@ class CMEServer(threading.Thread): try: threading.Thread.__init__(self) - self.server = BaseHTTPServer.HTTPServer((srv_host, int(port)), RequestHandler) + self.server = http.server.HTTPServer((srv_host, int(port)), RequestHandler) self.server.hosts = [] self.server.module = module self.server.context = context diff --git a/cme/thirdparty/pywerview b/cme/thirdparty/pywerview index 2156da64..264904bc 160000 --- a/cme/thirdparty/pywerview +++ b/cme/thirdparty/pywerview @@ -1 +1 @@ -Subproject commit 2156da6431b278bc60f22cf4b66bd671f7d0a0fe +Subproject commit 264904bc3fccab26a5cd870fe38b8fa9e04bd8d8 From 2cf0c0fb9096c2b29d423c3b1dcf78b0e41ea224 Mon Sep 17 00:00:00 2001 From: mpgn Date: Tue, 12 Nov 2019 16:39:26 -0500 Subject: [PATCH 09/13] Migrate cmedb to python3 --- .gitignore | 1 + cme/cmedb.py | 38 ++++++++++++++--------------- cme/protocols/http/db_navigator.py | 8 +++--- cme/protocols/mssql/db_navigator.py | 4 +-- cme/protocols/smb/db_navigator.py | 4 +-- 5 files changed, 28 insertions(+), 27 deletions(-) diff --git a/.gitignore b/.gitignore index 8d11b9bf..ce650878 100755 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ data/cme.db +*.bak *.log .venv # Byte-compiled / optimized / DLL files diff --git a/cme/cmedb.py b/cme/cmedb.py index 05101ea5..90aecaba 100755 --- a/cme/cmedb.py +++ b/cme/cmedb.py @@ -38,23 +38,23 @@ class DatabaseNavigator(cmd.Cmd): sys.exit(0) def print_table(self, data, title=None): - print "" + print("") table = AsciiTable(data) if title: table.title = title - print table.table - print "" + print(table.table) + print("") def do_export(self, line): if not line: - print "[-] not enough arguments" + print("[-] not enough arguments") return line = line.split() if line[0].lower() == 'creds': if len(line) < 3: - print "[-] invalid arguments, export creds " + print("[-] invalid arguments, export creds ") return if line[1].lower() == 'plaintext': creds = self.db.get_credentials(credtype="plaintext") @@ -70,21 +70,21 @@ class DatabaseNavigator(cmd.Cmd): export_file.write('{},{},{},{},{},{}\n'.format(credid,domain,user,password,credtype,fromhost)) else: export_file.write('{}\n'.format(password)) - print '[+] creds exported' + print('[+] creds exported') elif line[0].lower() == 'hosts': if len(line) < 2: - print "[-] invalid arguments, export hosts " + print("[-] invalid arguments, export hosts ") return hosts = self.db.get_computers() with open(os.path.expanduser(line[1]), 'w') as export_file: for host in hosts: hostid,ipaddress,hostname,domain,opsys,dc = host export_file.write('{},{},{},{},{},{}\n'.format(hostid,ipaddress,hostname,domain,opsys,dc)) - print '[+] hosts exported' + print('[+] hosts exported') else: - print '[-] invalid argument, specify creds or hosts' + print('[-] invalid argument, specify creds or hosts') def do_import(self, line): @@ -116,12 +116,12 @@ class DatabaseNavigator(cmd.Cmd): self.db.add_credential(cred['credtype'], cred['domain'], cred['username'], cred['password']) - print "[+] Empire credential import successful" + print("[+] Empire credential import successful") else: - print "[-] Error authenticating to Empire's RESTful API server!" + print("[-] Error authenticating to Empire's RESTful API server!") except ConnectionError as e: - print "[-] Unable to connect to Empire's RESTful API server: {}".format(e) + print("[-] Unable to connect to Empire's RESTful API server: {}".format(e)) elif line == 'metasploit': msf = Msfrpc({'host': self.config.get('Metasploit', 'rpc_host'), @@ -130,7 +130,7 @@ class DatabaseNavigator(cmd.Cmd): try: msf.login('msf', self.config.get('Metasploit', 'password')) except MsfAuthError: - print "[-] Error authenticating to Metasploit's MSGRPC server!" + print("[-] Error authenticating to Metasploit's MSGRPC server!") return console_id = str(msf.call('console.create')['id']) @@ -159,7 +159,7 @@ class DatabaseNavigator(cmd.Cmd): msf.call('console.destroy', [console_id]) - print "[+] Metasploit credential import successful" + print("[+] Metasploit credential import successful") def complete_import(self, text, line, begidx, endidx): "Tab-complete 'import' commands." @@ -191,7 +191,7 @@ class CMEDBMenu(cmd.Cmd): self.config = configparser.ConfigParser() self.config.read(self.config_path) except Exception as e: - print "[-] Error reading cme.conf: {}".format(e) + print("[-] Error reading cme.conf: {}".format(e)) sys.exit(1) self.workspace_dir = os.path.expanduser('~/.cme/workspaces') @@ -213,7 +213,7 @@ class CMEDBMenu(cmd.Cmd): self.conn.isolation_level = None def write_configfile(self): - with open(self.config_path, 'wb') as configfile: + with open(self.config_path, 'w') as configfile: self.config.write(configfile) def do_proto(self, proto): @@ -243,7 +243,7 @@ class CMEDBMenu(cmd.Cmd): if line.split()[0] == 'create': new_workspace = line.split()[1].strip() - print "[*] Creating workspace '{}'".format(new_workspace) + print("[*] Creating workspace '{}'".format(new_workspace)) os.mkdir(os.path.join(self.workspace_dir, new_workspace)) for protocol in self.protocols.keys(): @@ -255,7 +255,7 @@ class CMEDBMenu(cmd.Cmd): proto_db_path = os.path.join(self.workspace_dir, new_workspace, protocol + '.db') if not os.path.exists(proto_db_path): - print '[*] Initializing {} protocol database'.format(protocol.upper()) + print('[*] Initializing {} protocol database'.format(protocol.upper())) conn = sqlite3.connect(proto_db_path) c = conn.cursor() @@ -286,7 +286,7 @@ def main(): config_path = os.path.expanduser('~/.cme/cme.conf') if not os.path.exists(config_path): - print "[-] Unable to find config file" + print("[-] Unable to find config file") sys.exit(1) try: diff --git a/cme/protocols/http/db_navigator.py b/cme/protocols/http/db_navigator.py index f49c4416..102465e1 100644 --- a/cme/protocols/http/db_navigator.py +++ b/cme/protocols/http/db_navigator.py @@ -39,14 +39,14 @@ class navigator(DatabaseNavigator): self.db.add_credential(url, username, password) else: - print "[!] Format is 'add url username password" + print("[!] Format is 'add url username password") return elif filterTerm.split()[0].lower() == "remove": args = filterTerm.split()[1:] if len(args) != 1 : - print "[!] Format is 'remove '" + print("[!] Format is 'remove '") return else: self.db.remove_credentials(args) @@ -74,14 +74,14 @@ class navigator(DatabaseNavigator): # self.db.add_host() else: - print "[!] Format is 'add url ip hostname port" + print("[!] Format is 'add url ip hostname port") return elif filterTerm.split()[0].lower() == "remove": args = filterTerm.split()[1:] if len(args) != 1 : - print "[!] Format is 'remove '" + print("[!] Format is 'remove '") return # self.db.remove_host() diff --git a/cme/protocols/mssql/db_navigator.py b/cme/protocols/mssql/db_navigator.py index 4eb17f4e..2064d911 100644 --- a/cme/protocols/mssql/db_navigator.py +++ b/cme/protocols/mssql/db_navigator.py @@ -110,14 +110,14 @@ class navigator(DatabaseNavigator): self.db.add_credential("plaintext", domain, username, password) else: - print "[!] Format is 'add domain username password" + print("[!] Format is 'add domain username password") return elif filterTerm.split()[0].lower() == "remove": args = filterTerm.split()[1:] if len(args) != 1: - print "[!] Format is 'remove '" + print("[!] Format is 'remove '") return else: self.db.remove_credentials(args) diff --git a/cme/protocols/smb/db_navigator.py b/cme/protocols/smb/db_navigator.py index efa5c4ff..352c7363 100644 --- a/cme/protocols/smb/db_navigator.py +++ b/cme/protocols/smb/db_navigator.py @@ -173,14 +173,14 @@ class navigator(DatabaseNavigator): self.db.add_credential("plaintext", domain, username, password) else: - print "[!] Format is 'add domain username password" + print("[!] Format is 'add domain username password") return elif filterTerm.split()[0].lower() == "remove": args = filterTerm.split()[1:] if len(args) != 1: - print "[!] Format is 'remove '" + print("[!] Format is 'remove '") return else: self.db.remove_credentials(args) From 545b59054bed08f30194981446049c7910375381 Mon Sep 17 00:00:00 2001 From: mpgn Date: Thu, 16 Jan 2020 04:34:21 -0500 Subject: [PATCH 10/13] Fix Pipfile python version and submodile version --- Pipfile | 2 +- Pipfile.lock | 322 +++++++++++++++++---------------------- cme/cli.py | 4 +- cme/thirdparty/impacket | 2 +- cme/thirdparty/pywerview | 2 +- requirements.txt | 4 +- setup.py | 4 +- 7 files changed, 146 insertions(+), 194 deletions(-) diff --git a/Pipfile b/Pipfile index 93051c22..a75accfe 100644 --- a/Pipfile +++ b/Pipfile @@ -25,4 +25,4 @@ six = "*" terminaltables = "*" [requires] -python_version = "2.7" +python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock index 628525f0..e8db078e 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,11 +1,11 @@ { "_meta": { "hash": { - "sha256": "63dd45ebb42f9808c2a9f1f775f01ce7f386dbcb376cc8e38d9a044c0ff0e9b1" + "sha256": "2cf34d989e25f27b567739f2c9ce194d11ae104c1794b3c26690ff0f70b08072" }, "pipfile-spec": 6, "requires": { - "python_version": "2.7" + "python_version": "3.7" }, "sources": [ { @@ -16,20 +16,13 @@ ] }, "default": { - "backports.functools-lru-cache": { - "hashes": [ - "sha256:9d98697f088eb1b0fa451391f91afb5e3ebde16bbdb272819fd091151fda4f1a", - "sha256:f0b0e4eba956de51238e17573b7087e852dfe9854afd2e9c873f73fc0ca0a6dd" - ], - "markers": "python_version < '3'", - "version": "==1.5" - }, "bcrypt": { "hashes": [ "sha256:0258f143f3de96b7c14f762c770f5fc56ccd72f8a1857a451c1cd9a655d9ac89", "sha256:0b0069c752ec14172c5f78208f1863d7ad6755a6fae6fe76ec2c80d13be41e42", "sha256:19a4b72a6ae5bb467fea018b825f0a7d917789bcfe893e53f15c92805d187294", "sha256:5432dd7b34107ae8ed6c10a71b4397f1c853bd39a4d6ffa7e35f40584cffd161", + "sha256:6305557019906466fc42dbc53b46da004e72fd7a551c044a827e572c82191752", "sha256:69361315039878c0680be456640f8705d76cb4a3a3fe1e057e0f261b74be4b31", "sha256:6fe49a60b25b584e2f4ef175b29d3a83ba63b3a4df1b4c0605b826668d1b6be5", "sha256:74a015102e877d0ccd02cdeaa18b32aa7273746914a6c5d0456dd442cb65b99c", @@ -40,6 +33,7 @@ "sha256:a595c12c618119255c90deb4b046e1ca3bcfad64667c43d1166f2b04bc72db09", "sha256:c9457fa5c121e94a58d6505cadca8bed1c64444b83b3204928a866ca2e599105", "sha256:cb93f6b2ab0f6853550b74e051d297c27a638719753eb9ff66d1e4072be67133", + "sha256:ce4e4f0deb51d38b1611a27f330426154f2980e66582dc5f438aad38b5f24fc1", "sha256:d7bdc26475679dd073ba0ed2766445bb5b20ca4793ca0db32b399dccc6bc84b7", "sha256:ff032765bb8716d9387fd5376d987a937254b0619eff0972779515b5c98820bc" ], @@ -47,11 +41,11 @@ }, "beautifulsoup4": { "hashes": [ - "sha256:5279c36b4b2ec2cb4298d723791467e3000e5384a43ea0cdf5d45207c7e97169", - "sha256:6135db2ba678168c07950f9a16c4031822c6f4aec75a65e0a97bc5ca09789931", - "sha256:dcdef580e18a76d54002088602eba453eec38ebbcafafeaabd8cab12b6155d57" + "sha256:05fd825eb01c290877657a56df4c6e4c311b3965bda790c613a3d6fb01a5462a", + "sha256:9fbb4d6e48ecd30bcacc5b63b94088192dcda178513b2ae3c394229f8911b887", + "sha256:e1505eeed31b0f4ce2dbb3bc8eb256c04cc2b3b72af7d551a4ab6efd5cbe5dae" ], - "version": "==4.8.1" + "version": "==4.8.2" }, "bs4": { "hashes": [ @@ -62,47 +56,48 @@ }, "certifi": { "hashes": [ - "sha256:e4f3620cfea4f83eedc95b24abd9cd56f3c4b146dd0177e83a21b4eb49e21e50", - "sha256:fd7c7c74727ddcf00e9acd26bba8da604ffec95bf1c2144e67aff7a8b50e6cef" + "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3", + "sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f" ], - "version": "==2019.9.11" + "version": "==2019.11.28" }, "cffi": { "hashes": [ - "sha256:08f99e8b38d5134d504aa7e486af8e4fde66a2f388bbecc270cdd1e00fa09ff8", - "sha256:1112d2fc92a867a6103bce6740a549e74b1d320cf28875609f6e93857eee4f2d", - "sha256:1b9ab50c74e075bd2ae489853c5f7f592160b379df53b7f72befcbe145475a36", - "sha256:24eff2997436b6156c2f30bed215c782b1d8fd8c6a704206053c79af95962e45", - "sha256:2eff642fbc9877a6449026ad66bf37c73bf4232505fb557168ba5c502f95999b", - "sha256:362e896cea1249ed5c2a81cf6477fabd9e1a5088aa7ea08358a4c6b0998294d2", - "sha256:40eddb3589f382cb950f2dcf1c39c9b8d7bd5af20665ce273815b0d24635008b", - "sha256:5ed40760976f6b8613d4a0db5e423673ca162d4ed6c9ed92d1f4e58a47ee01b5", - "sha256:632c6112c1e914c486f06cfe3f0cc507f44aa1e00ebf732cedb5719e6aa0466a", - "sha256:64d84f0145e181f4e6cc942088603c8db3ae23485c37eeda71cb3900b5e67cb4", - "sha256:6cb4edcf87d0e7f5bdc7e5c1a0756fbb37081b2181293c5fdf203347df1cd2a2", - "sha256:6f19c9df4785305669335b934c852133faed913c0faa63056248168966f7a7d5", - "sha256:719537b4c5cd5218f0f47826dd705fb7a21d83824920088c4214794457113f3f", - "sha256:7b0e337a70e58f1a36fb483fd63880c9e74f1db5c532b4082bceac83df1523fa", - "sha256:853376efeeb8a4ae49a737d5d30f5db8cdf01d9319695719c4af126488df5a6a", - "sha256:85bbf77ffd12985d76a69d2feb449e35ecdcb4fc54a5f087d2bd54158ae5bb0c", - "sha256:8978115c6f0b0ce5880bc21c967c65058be8a15f1b81aa5fdbdcbea0e03952d1", - "sha256:8f7eec920bc83692231d7306b3e311586c2e340db2dc734c43c37fbf9c981d24", - "sha256:8fe230f612c18af1df6f348d02d682fe2c28ca0a6c3856c99599cdacae7cf226", - "sha256:92068ebc494b5f9826b822cec6569f1f47b9a446a3fef477e1d11d7fac9ea895", - "sha256:b57e1c8bcdd7340e9c9d09613b5e7fdd0c600be142f04e2cc1cc8cb7c0b43529", - "sha256:ba956c9b44646bc1852db715b4a252e52a8f5a4009b57f1dac48ba3203a7bde1", - "sha256:ca42034c11eb447497ea0e7b855d87ccc2aebc1e253c22e7d276b8599c112a27", - "sha256:dc9b2003e9a62bbe0c84a04c61b0329e86fccd85134a78d7aca373bbbf788165", - "sha256:dd308802beb4b2961af8f037becbdf01a1e85009fdfc14088614c1b3c383fae5", - "sha256:e77cd105b19b8cd721d101687fcf665fd1553eb7b57556a1ef0d453b6fc42faa", - "sha256:f56dff1bd81022f1c980754ec721fb8da56192b026f17f0f99b965da5ab4fbd2", - "sha256:fa4cc13c03ea1d0d37ce8528e0ecc988d2365e8ac64d8d86cafab4038cb4ce89", - "sha256:fa8cf1cb974a9f5911d2a0303f6adc40625c05578d8e7ff5d313e1e27850bd59", - "sha256:fb003019f06d5fc0aa4738492ad8df1fa343b8a37cbcf634018ad78575d185df", - "sha256:fd409b7778167c3bcc836484a8f49c0e0b93d3e745d975749f83aa5d18a5822f", - "sha256:fe5d65a3ee38122003245a82303d11ac05ff36531a8f5ce4bc7d4bbc012797e1" + "sha256:0b49274afc941c626b605fb59b59c3485c17dc776dc3cc7cc14aca74cc19cc42", + "sha256:0e3ea92942cb1168e38c05c1d56b0527ce31f1a370f6117f1d490b8dcd6b3a04", + "sha256:135f69aecbf4517d5b3d6429207b2dff49c876be724ac0c8bf8e1ea99df3d7e5", + "sha256:19db0cdd6e516f13329cba4903368bff9bb5a9331d3410b1b448daaadc495e54", + "sha256:2781e9ad0e9d47173c0093321bb5435a9dfae0ed6a762aabafa13108f5f7b2ba", + "sha256:291f7c42e21d72144bb1c1b2e825ec60f46d0a7468f5346841860454c7aa8f57", + "sha256:2c5e309ec482556397cb21ede0350c5e82f0eb2621de04b2633588d118da4396", + "sha256:2e9c80a8c3344a92cb04661115898a9129c074f7ab82011ef4b612f645939f12", + "sha256:32a262e2b90ffcfdd97c7a5e24a6012a43c61f1f5a57789ad80af1d26c6acd97", + "sha256:3c9fff570f13480b201e9ab69453108f6d98244a7f495e91b6c654a47486ba43", + "sha256:415bdc7ca8c1c634a6d7163d43fb0ea885a07e9618a64bda407e04b04333b7db", + "sha256:42194f54c11abc8583417a7cf4eaff544ce0de8187abaf5d29029c91b1725ad3", + "sha256:4424e42199e86b21fc4db83bd76909a6fc2a2aefb352cb5414833c030f6ed71b", + "sha256:4a43c91840bda5f55249413037b7a9b79c90b1184ed504883b72c4df70778579", + "sha256:599a1e8ff057ac530c9ad1778293c665cb81a791421f46922d80a86473c13346", + "sha256:5c4fae4e9cdd18c82ba3a134be256e98dc0596af1e7285a3d2602c97dcfa5159", + "sha256:5ecfa867dea6fabe2a58f03ac9186ea64da1386af2159196da51c4904e11d652", + "sha256:62f2578358d3a92e4ab2d830cd1c2049c9c0d0e6d3c58322993cc341bdeac22e", + "sha256:6471a82d5abea994e38d2c2abc77164b4f7fbaaf80261cb98394d5793f11b12a", + "sha256:6d4f18483d040e18546108eb13b1dfa1000a089bcf8529e30346116ea6240506", + "sha256:71a608532ab3bd26223c8d841dde43f3516aa5d2bf37b50ac410bb5e99053e8f", + "sha256:74a1d8c85fb6ff0b30fbfa8ad0ac23cd601a138f7509dc617ebc65ef305bb98d", + "sha256:7b93a885bb13073afb0aa73ad82059a4c41f4b7d8eb8368980448b52d4c7dc2c", + "sha256:7d4751da932caaec419d514eaa4215eaf14b612cff66398dd51129ac22680b20", + "sha256:7f627141a26b551bdebbc4855c1157feeef18241b4b8366ed22a5c7d672ef858", + "sha256:8169cf44dd8f9071b2b9248c35fc35e8677451c52f795daa2bb4643f32a540bc", + "sha256:aa00d66c0fab27373ae44ae26a66a9e43ff2a678bf63a9c7c1a9a4d61172827a", + "sha256:ccb032fda0873254380aa2bfad2582aedc2959186cce61e3a17abc1a55ff89c3", + "sha256:d754f39e0d1603b5b24a7f8484b22d2904fa551fe865fd0d4c3332f078d20d4e", + "sha256:d75c461e20e29afc0aee7172a0950157c704ff0dd51613506bd7d82b718e7410", + "sha256:dcd65317dd15bc0451f3e01c80da2216a31916bdcffd6221ca1202d96584aa25", + "sha256:e570d3ab32e2c2861c4ebe6ffcad6a8abf9347432a37608fe1fbd157b3f0036b", + "sha256:fd43a88e045cf992ed09fa724b5315b790525f2676883a6ea64e3263bae6549d" ], - "version": "==1.13.0" + "version": "==1.13.2" }, "chardet": { "hashes": [ @@ -137,16 +132,6 @@ ], "version": "==2.8" }, - "enum34": { - "hashes": [ - "sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850", - "sha256:644837f692e5f550741432dd3f223bbb9852018674981b1664e5dc339387588a", - "sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79", - "sha256:8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1" - ], - "markers": "python_version < '3'", - "version": "==1.1.6" - }, "gevent": { "hashes": [ "sha256:0774babec518a24d9a7231d4e689931f31b332c4517a771e532002614e270a64", @@ -208,14 +193,6 @@ ], "version": "==2.8" }, - "ipaddress": { - "hashes": [ - "sha256:6e0f4a39e66cb5bb9a137b00276a2eff74f93b71dcbdad6f10ff7df9d3557fcc", - "sha256:b7f8e0369580bb4a24d5ba1d7cc29660a4a6987763faf1d8a8046830e020e7e2" - ], - "markers": "python_version < '3'", - "version": "==1.0.23" - }, "msgpack-python": { "hashes": [ "sha256:378cc8a6d3545b532dfd149da715abae4fda2a3adb6d74e525d0d5e51f46909b" @@ -240,19 +217,19 @@ }, "paramiko": { "hashes": [ - "sha256:3c16b2bfb4c0d810b24c40155dbfd113c0521e7e6ee593d704e84b4c658a1f3b", - "sha256:a8975a7df3560c9f1e2b43dc54ebd40fd00a7017392ca5445ce7df409f900fcb" + "sha256:920492895db8013f6cc0179293147f830b8c7b21fdfc839b6bad760c27459d9f", + "sha256:9c980875fa4d2cb751604664e9a2d0f69096643f5be4db1b99599fe114a97b2f" ], "index": "pypi", - "version": "==2.4.2" + "version": "==2.7.1" }, "pyasn1": { "hashes": [ - "sha256:da2420fe13a9452d8ae97a0e478adde1dee153b11ba832a95b223a2ba01c10f7", - "sha256:da6b43a8c9ae93bc80e2739efb38cc776ba74a886e3e9318d65fe81a8b8a2c6e" + "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d", + "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba" ], "index": "pypi", - "version": "==0.4.5" + "version": "==0.4.8" }, "pycparser": { "hashes": [ @@ -262,37 +239,41 @@ }, "pycryptodomex": { "hashes": [ - "sha256:0bda549e20db1eb8e29fb365d10acf84b224d813b1131c828fc830b2ce313dcd", - "sha256:1210c0818e5334237b16d99b5785aa0cee815d9997ee258bd5e2936af8e8aa50", - "sha256:2090dc8cd7843eae75bd504b9be86792baa171fc5a758ea3f60188ab67ca95cf", - "sha256:22e6784b65dfdd357bf9a8a842db445192b227103e2c3137a28c489c46742135", - "sha256:2edb8c3965a77e3092b5c5c1233ffd32de083f335202013f52d662404191ac79", - "sha256:310fe269ac870135ff610d272e88dcb594ee58f40ac237a688d7c972cbca43e8", - "sha256:456136b7d459f000794a67b23558351c72e21f0c2d4fcaa09fc99dae7844b0ef", - "sha256:463e49a9c5f1fa7bd36aff8debae0b5c487868c1fb66704529f2ad7e92f0cc9f", - "sha256:4a33b2828799ef8be789a462e6645ea6fe2c42b0df03e6763ccbfd1789c453e6", - "sha256:5ff02dff1b03929e6339226b318aa59bd0b5c362f96e3e0eb7f3401d30594ed3", - "sha256:6b1db8234b8ee2b30435d9e991389c2eeae4d45e09e471ffe757ba1dfae682bb", - "sha256:6eb67ee02de143cd19e36a52bd3869a9dc53e9184cd6bed5c39ff71dee2f6a45", - "sha256:6f42eea5afc7eee29494fdfddc6bb7173953d4197d9200e4f67096c2a24bc21b", - "sha256:87bc8082e2de2247df7d0b161234f8edb1384294362cc0c8db9324463097578b", - "sha256:8df93d34bc0e3a28a27652070164683a07d8a50c628119d6e0f7710f4d01b42f", - "sha256:989952c39e8fef1c959f0a0f85656e29c41c01162e33a3f5fd8ce71e47262ae9", - "sha256:a4a203077e2f312ec8677dde80a5c4e6fe5a82a46173a8edc8da668602a3e073", - "sha256:a793c1242dffd39f585ae356344e8935d30f01f6be7d4c62ffc87af376a2f5f9", - "sha256:b70fe991564e178af02ccf89435a8f9e8d052707a7c4b95bf6027cb785da3175", - "sha256:b83594196e3661cb78c97b80a62fbfbba2add459dfd532b58e7a7c62dd06aab4", - "sha256:ba27725237d0a3ea66ec2b6b387259471840908836711a3b215160808dffed0f", - "sha256:d1ab8ad1113cdc553ca50c4d5f0142198c317497364c0c70443d69f7ad1c9288", - "sha256:dce039a8a8a318d7af83cae3fd08d58cefd2120075dfac0ae14d706974040f63", - "sha256:e3213037ea33c85ab705579268cbc8a4433357e9fb99ec7ce9fdcc4d4eec1d50", - "sha256:ec8d8023d31ef72026d46e9fb301ff8759eff5336bcf3d1510836375f53f96a9", - "sha256:ece65730d50aa57a1330d86d81582a2d1587b2ca51cb34f586da8551ddc68fee", - "sha256:ed21fc515e224727793e4cc3fb3d00f33f59e3a167d3ad6ac1475ab3b05c2f9e", - "sha256:eec1132d878153d61a05424f35f089f951bd6095a4f6c60bdd2ef8919d44425e" + "sha256:0943b65fb41b7403a9def6214061fdd9ab9afd0bbc581e553c72eebe60bded36", + "sha256:0a1dbb5c4d975a4ea568fb7686550aa225d94023191fb0cca8747dc5b5d77857", + "sha256:0f43f1608518347fdcb9c8f443fa5cabedd33f94188b13e4196a3a7ba90d169c", + "sha256:11ce5fec5990e34e3981ed14897ba601c83957b577d77d395f1f8f878a179f98", + "sha256:17a09e38fdc91e4857cf5a7ce82f3c0b229c3977490f2146513e366923fc256b", + "sha256:22d970cee5c096b9123415e183ae03702b2cd4d3ba3f0ced25c4e1aba3967167", + "sha256:2a1793efcbae3a2264c5e0e492a2629eb10d895d6e5f17dbbd00eb8b489c6bda", + "sha256:30a8a148a0fe482cec1aaf942bbd0ade56ec197c14fe058b2a94318c57e1f991", + "sha256:32fbbaf964c5184d3f3e349085b0536dd28184b02e2b014fc900f58bbc126339", + "sha256:347d67faee36d449dc9632da411cc318df52959079062627f1243001b10dc227", + "sha256:45f4b4e5461a041518baabc52340c249b60833aa84cea6377dc8016a2b33c666", + "sha256:4717daec0035034b002d31c42e55431c970e3e38a78211f43990e1b7eaf19e28", + "sha256:51a1ac9e7dda81da444fed8be558a60ec88dfc73b2aa4b0efa310e87acb75838", + "sha256:53e9dcc8f14783f6300b70da325a50ac1b0a3dbaee323bd9dc3f71d409c197a1", + "sha256:5519a2ed776e193688b7ddb61ab709303f6eb7d1237081e298283c72acc44271", + "sha256:583450e8e80a0885c453211ed2bd69ceea634d8c904f23ff8687f677fe810e95", + "sha256:60f862bd2a07133585a4fc2ce2b1a8ec24746b07ac44307d22ef2b767cb03435", + "sha256:612091f1d3c84e723bec7cb855cf77576e646045744794c9a3f75ba80737762f", + "sha256:629a87b87c8203b8789ccefc7f2f2faecd2daaeb56bdd0b4e44cd89565f2db07", + "sha256:6e56ec4c8938fb388b6f250ddd5e21c15e8f25a76e0ad0e2abae9afee09e67b4", + "sha256:8e8092651844a11ec7fa534395f3dfe99256ce4edca06f128efc9d770d6e1dc1", + "sha256:8f5f260629876603e08f3ce95c8ccd9b6b83bf9a921c41409046796267f7adc5", + "sha256:9a6b74f38613f54c56bd759b411a352258f47489bbefd1d57c930a291498b35b", + "sha256:a5a13ebb52c4cd065fb673d8c94f39f30823428a4de19e1f3f828b63a8882d1e", + "sha256:a77ca778a476829876a3a70ae880073379160e4a465d057e3c4e1c79acdf1b8a", + "sha256:a9f7be3d19f79429c2118fd61bc2ec4fa095e93b56fb3a5f3009822402c4380f", + "sha256:dc15a467c4f9e4b43748ba2f97aea66f67812bfd581818284c47cadc81d4caec", + "sha256:e13cdeea23059f7577c230fd580d2c8178e67ebe10e360041abe86c33c316f1c", + "sha256:e45b85c8521bca6bdfaf57e4987743ade53e9f03529dd3adbc9524094c6d55c4", + "sha256:e87f17867b260f57c88487f943eb4d46c90532652bb37046e764842c3b66cbb1", + "sha256:ee40a5b156f6c1192bc3082e9d73d0479904433cdda83110546cd67f5a15a5be", + "sha256:ef63ffde3b267043579af8830fc97fc3b9b8a526a24e3ba23af9989d4e9e689a" ], "index": "pypi", - "version": "==3.7.3" + "version": "==3.9.4" }, "pylnk": { "hashes": [ @@ -312,6 +293,7 @@ "sha256:30f36a9c70450c7878053fa1344aca0145fd47d845270b43a7ee9192a051bf39", "sha256:37aa336a317209f1bb099ad177fef0da45be36a2aa664507c5d72015f956c310", "sha256:4943decfc5b905748f0756fdd99d4f9498d7064815c4cf3643820c9028b711d1", + "sha256:53126cd91356342dcae7e209f840212a58dcf1177ad52c1d938d428eebc9fee5", "sha256:57ef38a65056e7800859e5ba9e6091053cd06e1038983016effaffe0efcd594a", "sha256:5bd61e9b44c543016ce1f6aef48606280e45f892a928ca7068fba30021e9b786", "sha256:6482d3017a0c0327a49dddc8bd1074cc730d45db2ccb09c3bac1f8f32d1eb61b", @@ -320,6 +302,7 @@ "sha256:a39f54ccbcd2757d1d63b0ec00a00980c0b382c62865b61a505163943624ab20", "sha256:aabb0c5232910a20eec8563503c153a8e78bbf5459490c49ab31f6adf3f3a415", "sha256:bd4ecb473a96ad0f90c20acba4f0bf0df91a4e03a1f4dd6a4bdc9ca75aa3a715", + "sha256:bf459128feb543cfca16a95f8da31e2e65e4c5257d2f3dfa8c0c1031139c9c92", "sha256:e2da3c13307eac601f3de04887624939aca8ee3c9488a0bb0eca4fb9401fc6b1", "sha256:f67814c38162f4deb31f68d590771a29d5ae3b1bd64b75cf232308e5c74777e0" ], @@ -327,19 +310,19 @@ }, "pyopenssl": { "hashes": [ - "sha256:aeca66338f6de19d1aa46ed634c3b9ae519a64b458f8468aec688e7e3c20f200", - "sha256:c727930ad54b10fc157015014b666f2d8b41f70c0d03e83ab67624fd3dd5d1e6" + "sha256:621880965a720b8ece2f1b2f54ea2071966ab00e2970ad2ce11d596102063504", + "sha256:9a24494b2602aaf402be5c9e30a0b82d4a5c67528fe8fb475e3f3bc00dd69507" ], "index": "pypi", - "version": "==19.0.0" + "version": "==19.1.0" }, "requests": { "hashes": [ - "sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e", - "sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b" + "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4", + "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31" ], "index": "pypi", - "version": "==2.21.0" + "version": "==2.22.0" }, "requests-ntlm": { "hashes": [ @@ -358,26 +341,26 @@ }, "six": { "hashes": [ - "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", - "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" + "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a", + "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c" ], "index": "pypi", - "version": "==1.12.0" + "version": "==1.14.0" }, "soupsieve": { "hashes": [ - "sha256:605f89ad5fdbfefe30cdc293303665eff2d188865d4dbe4eb510bba1edfbfce3", - "sha256:b91d676b330a0ebd5b21719cb6e9b57c57d433671f65b9c28dd3461d9a1ed0b6" + "sha256:bdb0d917b03a1369ce964056fc195cfdff8819c40de04695a80bc813c3cfa1f5", + "sha256:e2c1c5dee4a1c36bcb790e0fabd5492d874b8ebd4617622c4f6a731701060dda" ], - "version": "==1.9.4" + "version": "==1.9.5" }, "splinter": { "hashes": [ - "sha256:2d9f370536e6c1607824f5538e0bff9808bc02f086b07622b3790424dd3daff4", - "sha256:5d9913bddb6030979c18d6801578813b02bbf8a03b43fb057f093228ed876d62" + "sha256:62b5876757f0ac09324a7d5e5f94886110219c2b85300516ec39a914d7992d91", + "sha256:9e92535f273622507ac157612c3bb0e9cee7b5ccd2aa097d47b408e34c2ca356" ], "index": "pypi", - "version": "==0.10.0" + "version": "==0.13.0" }, "termcolor": { "hashes": [ @@ -395,11 +378,10 @@ }, "urllib3": { "hashes": [ - "sha256:4c291ca23bbb55c76518905869ef34bdd5f0e46af7afe6861e8375643ffee1a0", - "sha256:9a247273df709c4fedb38c711e44292304f73f39ab01beda9f6b9fc375669ac3" + "sha256:a8a318824cc77d1fd4b2bec2ded92646630d7fe8619497b142c84a9e6f5a7293", + "sha256:f3c5fd51747d450d4dcf6f923c81f78f811aab8205fda64b0aba34a4e48b0745" ], - "index": "pypi", - "version": "==1.24.2" + "version": "==1.25.7" }, "xmltodict": { "hashes": [ @@ -411,39 +393,27 @@ } }, "develop": { - "backports.shutil-get-terminal-size": { + "backcall": { "hashes": [ - "sha256:0975ba55054c15e346944b38956a4c9cbee9009391e41b86c68990effb8c1f64", - "sha256:713e7a8228ae80341c70586d1cc0a8caa5207346927e23d09dcbcaf18eadec80" + "sha256:38ecd85be2c1e78f77fd91700c76e14667dc21e2713b63876c0eb901196e01e4", + "sha256:bbbf4b1e5cd2bdb08f915895b51081c041bac22394fdfcfdfbe9f14b77c08bf2" ], - "markers": "python_version == '2.7'", - "version": "==1.0.0" + "version": "==0.1.0" }, "decorator": { "hashes": [ - "sha256:86156361c50488b84a3f148056ea716ca587df2f0de1d34750d35c21312725de", - "sha256:f069f3a01830ca754ba5258fde2278454a0b5b79e0d7f5c13b3b97e57d4acff6" + "sha256:54c38050039232e1db4ad7375cfce6748d7b41c29e95a081c8a6d2c30364a2ce", + "sha256:5d19b92a3c8f7f101c8dd86afd86b0f061a8ce4540ab8cd401fa2542756bce6d" ], - "version": "==4.4.0" - }, - "enum34": { - "hashes": [ - "sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850", - "sha256:644837f692e5f550741432dd3f223bbb9852018674981b1664e5dc339387588a", - "sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79", - "sha256:8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1" - ], - "markers": "python_version < '3'", - "version": "==1.1.6" + "version": "==4.4.1" }, "ipython": { "hashes": [ - "sha256:0371b7e4bd74954a35086eac949beeac5b1c9f5ce231e2e77df2286a293765e3", - "sha256:37101b8cbe072fe17bff100bc03d096404e4a9a0357097aeb5b61677c042cab1", - "sha256:4bac649857611baaaf76bc82c173aa542f7486446c335fe1a6c05d0d491c8906" + "sha256:0f4bcf18293fb666df8511feec0403bdb7e061a5842ea6e88a3177b0ceb34ead", + "sha256:387686dd7fc9caf29d2fddcf3116c4b07a11d9025701d220c589a430b0171d8a" ], "index": "pypi", - "version": "==5.8.0" + "version": "==7.11.1" }, "ipython-genutils": { "hashes": [ @@ -452,13 +422,19 @@ ], "version": "==0.2.0" }, - "pathlib2": { + "jedi": { "hashes": [ - "sha256:0ec8205a157c80d7acc301c0b18fbd5d44fe655968f5d947b6ecef5290fc35db", - "sha256:6cd9a47b597b37cc57de1c05e56fb1a1c9cc9fab04fe78c29acd090418529868" + "sha256:1349c1e8c107095a55386628bb3b2a79422f3a2cab8381e34ce19909e0cf5064", + "sha256:e909527104a903606dd63bea6e8e888833f0ef087057829b89a18364a856f807" ], - "markers": "python_version in '2.6 2.7 3.2 3.3'", - "version": "==2.3.5" + "version": "==0.15.2" + }, + "parso": { + "hashes": [ + "sha256:55cf25df1a35fd88b878715874d2c4dc1ad3f0eebd1e0266a67e1f55efccfbe1", + "sha256:5c1f7791de6bd5dbbeac8db0ef5594b36799de198b3f7f7014643b0c5536b9d3" + ], + "version": "==0.5.2" }, "pexpect": { "hashes": [ @@ -477,11 +453,10 @@ }, "prompt-toolkit": { "hashes": [ - "sha256:37925b37a4af1f6448c76b7606e0285f79f434ad246dda007a27411cca730c6d", - "sha256:dd4fca02c8069497ad931a2d09914c6b0d1b50151ce876bc15bde4c747090126", - "sha256:f7eec66105baf40eda9ab026cd8b2e251337eea8d111196695d82e0c5f0af852" + "sha256:0278d2f51b5ceba6ea8da39f76d15684e84c996b325475f6e5720edc584326a7", + "sha256:63daee79aa8366c8f1c637f1a4876b890da5fc92a19ebd2f7080ebacb901e990" ], - "version": "==1.0.18" + "version": "==3.0.2" }, "ptyprocess": { "hashes": [ @@ -492,41 +467,18 @@ }, "pygments": { "hashes": [ - "sha256:71e430bc85c88a430f000ac1d9b331d2407f681d6f6aec95e8bcfbc3df5b0127", - "sha256:881c4c157e45f30af185c1ffe8d549d48ac9127433f2c380c24b84572ad66297" + "sha256:2a3fe295e54a20164a9df49c75fa58526d3be48e14aceba6d6b1e8ac0bfd6f1b", + "sha256:98c8aa5a9f778fcd1026a17361ddaf7330d1b7c62ae97c3bb0ae73e0b9b6b0fe" ], - "version": "==2.4.2" - }, - "scandir": { - "hashes": [ - "sha256:2586c94e907d99617887daed6c1d102b5ca28f1085f90446554abf1faf73123e", - "sha256:2ae41f43797ca0c11591c0c35f2f5875fa99f8797cb1a1fd440497ec0ae4b022", - "sha256:2b8e3888b11abb2217a32af0766bc06b65cc4a928d8727828ee68af5a967fa6f", - "sha256:2c712840c2e2ee8dfaf36034080108d30060d759c7b73a01a52251cc8989f11f", - "sha256:4d4631f6062e658e9007ab3149a9b914f3548cb38bfb021c64f39a025ce578ae", - "sha256:67f15b6f83e6507fdc6fca22fedf6ef8b334b399ca27c6b568cbfaa82a364173", - "sha256:7d2d7a06a252764061a020407b997dd036f7bd6a175a5ba2b345f0a357f0b3f4", - "sha256:8c5922863e44ffc00c5c693190648daa6d15e7c1207ed02d6f46a8dcc2869d32", - "sha256:92c85ac42f41ffdc35b6da57ed991575bdbe69db895507af88b9f499b701c188", - "sha256:b24086f2375c4a094a6b51e78b4cf7ca16c721dcee2eddd7aa6494b42d6d519d", - "sha256:cb925555f43060a1745d0a321cca94bcea927c50114b623d73179189a4e100ac" - ], - "markers": "python_version < '3.5'", - "version": "==1.10.0" - }, - "simplegeneric": { - "hashes": [ - "sha256:dc972e06094b9af5b855b3df4a646395e43d1c9d0d39ed345b7393560d0b9173" - ], - "version": "==0.8.1" + "version": "==2.5.2" }, "six": { "hashes": [ - "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", - "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" + "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a", + "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c" ], "index": "pypi", - "version": "==1.12.0" + "version": "==1.14.0" }, "traitlets": { "hashes": [ @@ -537,10 +489,10 @@ }, "wcwidth": { "hashes": [ - "sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e", - "sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c" + "sha256:8fd29383f539be45b20bd4df0dc29c20ba48654a41e661925e612311e9f3c603", + "sha256:f28b3e8a6483e5d49e7f8949ac1a78314e740333ae305b4ba5defd3e74fb37a8" ], - "version": "==0.1.7" + "version": "==0.1.8" } } } diff --git a/cme/cli.py b/cme/cli.py index 8a9ffee7..7d781bb2 100755 --- a/cme/cli.py +++ b/cme/cli.py @@ -6,8 +6,8 @@ from cme.helpers.logger import highlight def gen_cli_args(): - VERSION = '4.0.1dev' - CODENAME = 'Bug Pr0n' + VERSION = '5.0.0dev' + CODENAME = 'P3l1as' p_loader = protocol_loader() protocols = p_loader.get_protocols() diff --git a/cme/thirdparty/impacket b/cme/thirdparty/impacket index 10e2a2cc..bf437b9c 160000 --- a/cme/thirdparty/impacket +++ b/cme/thirdparty/impacket @@ -1 +1 @@ -Subproject commit 10e2a2cc3bd8c81e97c0aedb821cadab07ca6cbc +Subproject commit bf437b9c0a489a17e199cdc8899a89914c1c3113 diff --git a/cme/thirdparty/pywerview b/cme/thirdparty/pywerview index 264904bc..acd8db86 160000 --- a/cme/thirdparty/pywerview +++ b/cme/thirdparty/pywerview @@ -1 +1 @@ -Subproject commit 264904bc3fccab26a5cd870fe38b8fa9e04bd8d8 +Subproject commit acd8db86c6189c8006b9795e15614479665136c2 diff --git a/requirements.txt b/requirements.txt index ca4995e8..2066f3bc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,11 +7,11 @@ certifi==2019.9.11 cffi==1.13.0 chardet==3.0.4 cryptography==2.8 -enum34==1.1.6 ; python_version < '3' +enum34==1.1.6 gevent==1.4.0 greenlet==0.4.15 ; platform_python_implementation == 'CPython' idna==2.8 -ipaddress==1.0.23 ; python_version < '3' +ipaddress==1.0.23 msgpack-python==0.5.6 netaddr==0.7.19 ntlm-auth==1.4.0 diff --git a/setup.py b/setup.py index 0ec4e001..f1ff8dbb 100755 --- a/setup.py +++ b/setup.py @@ -3,12 +3,12 @@ from setuptools import setup, find_packages setup(name='crackmapexec', - version='4.0.1dev', + version='5.0.0dev', description='A swiss army knife for pentesting networks', classifiers=[ 'Environment :: Console', 'License :: OSI Approved :: BSD License', - 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3.7', 'Topic :: Security', ], keywords='pentesting security windows active-directory networks', From 83c8e5b5a3783bba6158d2db6777f7b1d30c0087 Mon Sep 17 00:00:00 2001 From: mpgn Date: Sat, 18 Jan 2020 07:20:10 -0500 Subject: [PATCH 11/13] Add module compatibility for Python3 Mimikatz, Bloodhound etc --- cme/crackmapexec.py | 4 ++-- cme/modules/Get-ComputerDetails.py | 6 +++--- cme/modules/bloodhound.py | 6 +++--- cme/modules/enum_chrome.py | 6 +++--- cme/modules/get_netdomaincontroller.py | 6 +++--- cme/modules/get_netrdpsession.py | 6 +++--- cme/modules/gpp_autologin.py | 2 +- cme/modules/gpp_password.py | 2 +- cme/modules/invoke_sessiongopher.py | 6 +++--- cme/modules/met_inject.py | 2 +- cme/modules/mimikatz.py | 8 +++----- cme/modules/mimikatz_enum_chrome.py | 10 +++++----- cme/modules/mimikatz_enum_vault_creds.py | 8 ++++---- cme/modules/mimikittenz.py | 6 +++--- cme/modules/multirdp.py | 6 +++--- cme/modules/pe_inject.py | 2 +- cme/modules/shellcode_inject.py | 2 +- cme/modules/tokens.py | 8 ++++---- cme/servers/http.py | 4 ++-- 19 files changed, 49 insertions(+), 51 deletions(-) diff --git a/cme/crackmapexec.py b/cme/crackmapexec.py index 7725f952..53b996a7 100755 --- a/cme/crackmapexec.py +++ b/cme/crackmapexec.py @@ -168,12 +168,12 @@ def main(): exit(1) if getattr(module, 'opsec_safe') is False: - ans = raw_input(highlight('[!] Module is not opsec safe, are you sure you want to run this? [Y/n] ', 'red')) + ans = input(highlight('[!] Module is not opsec safe, are you sure you want to run this? [Y/n] ', 'red')) if ans.lower() not in ['y', 'yes', '']: sys.exit(1) if getattr(module, 'multiple_hosts') is False and len(targets) > 1: - ans = raw_input(highlight("[!] Running this module on multiple hosts doesn't really make any sense, are you sure you want to continue? [Y/n] ", 'red')) + ans = input(highlight("[!] Running this module on multiple hosts doesn't really make any sense, are you sure you want to continue? [Y/n] ", 'red')) if ans.lower() not in ['y', 'yes', '']: sys.exit(1) diff --git a/cme/modules/Get-ComputerDetails.py b/cme/modules/Get-ComputerDetails.py index 0bab41ab..542a4fcb 100644 --- a/cme/modules/Get-ComputerDetails.py +++ b/cme/modules/Get-ComputerDetails.py @@ -1,7 +1,7 @@ from cme.helpers.powershell import * from cme.helpers.logger import write_log, highlight from datetime import datetime -from StringIO import StringIO +from io import StringIO class CMEModule: @@ -57,8 +57,8 @@ class CMEModule: def on_response(self, context, response): response.send_response(200) response.end_headers() - length = int(response.headers.getheader('content-length')) - data = response.rfile.read(length) + length = int(response.headers.get('content-length')) + data = response.rfile.read(length).decode() response.stop_tracking_host() diff --git a/cme/modules/bloodhound.py b/cme/modules/bloodhound.py index 77dd150a..67e8c528 100644 --- a/cme/modules/bloodhound.py +++ b/cme/modules/bloodhound.py @@ -70,7 +70,7 @@ class CMEModule: if 'BloodHound-modified.ps1' == request.path[1:]: request.send_response(200) request.end_headers() - request.wfile.write(self.ps_script) + request.wfile.write(self.ps_script.encode()) context.log.success('Executing payload... this can take a few minutes...') else: request.send_response(404) @@ -79,8 +79,8 @@ class CMEModule: def on_response(self, context, response): response.send_response(200) response.end_headers() - length = int(response.headers.getheader('content-length')) - data = response.rfile.read(length) + length = int(response.headers.get('content-length')) + data = response.rfile.read(length).decode() response.stop_tracking_host() if self.neo4j_URI == "" and self.neo4j_user == "" and self.neo4j_pass == "" : self.parse_ouput(data, context, response) diff --git a/cme/modules/enum_chrome.py b/cme/modules/enum_chrome.py index 9102e4ef..459a50a1 100644 --- a/cme/modules/enum_chrome.py +++ b/cme/modules/enum_chrome.py @@ -1,7 +1,7 @@ from cme.helpers.powershell import * from cme.helpers.logger import write_log from datetime import datetime -from StringIO import StringIO +from io import StringIO class CMEModule: ''' @@ -52,8 +52,8 @@ class CMEModule: def on_response(self, context, response): response.send_response(200) response.end_headers() - length = int(response.headers.getheader('content-length')) - data = response.rfile.read(length) + length = int(response.headers.get('content-length')) + data = response.rfile.read(length).decode() #We've received the response, stop tracking this host response.stop_tracking_host() diff --git a/cme/modules/get_netdomaincontroller.py b/cme/modules/get_netdomaincontroller.py index 8bcf77f4..ad1d8fbd 100644 --- a/cme/modules/get_netdomaincontroller.py +++ b/cme/modules/get_netdomaincontroller.py @@ -1,7 +1,7 @@ from cme.helpers.powershell import * from cme.helpers.logger import write_log, highlight from datetime import datetime -from StringIO import StringIO +from io import StringIO class CMEModule: @@ -56,8 +56,8 @@ class CMEModule: def on_response(self, context, response): response.send_response(200) response.end_headers() - length = int(response.headers.getheader('content-length')) - data = response.rfile.read(length) + length = int(response.headers.get('content-length')) + data = response.rfile.read(length).decode() #We've received the response, stop tracking this host response.stop_tracking_host() diff --git a/cme/modules/get_netrdpsession.py b/cme/modules/get_netrdpsession.py index 987342ee..ebb89f60 100644 --- a/cme/modules/get_netrdpsession.py +++ b/cme/modules/get_netrdpsession.py @@ -1,7 +1,7 @@ from cme.helpers.powershell import * from cme.helpers.logger import write_log, highlight from datetime import datetime -from StringIO import StringIO +from io import StringIO class CMEModule: @@ -56,8 +56,8 @@ class CMEModule: def on_response(self, context, response): response.send_response(200) response.end_headers() - length = int(response.headers.getheader('content-length')) - data = response.rfile.read(length) + length = int(response.headers.get('content-length')) + data = response.rfile.read(length).decode() #We've received the response, stop tracking this host response.stop_tracking_host() diff --git a/cme/modules/gpp_autologin.py b/cme/modules/gpp_autologin.py index fe5f9311..8b0bcd4a 100644 --- a/cme/modules/gpp_autologin.py +++ b/cme/modules/gpp_autologin.py @@ -1,5 +1,5 @@ import xml.etree.ElementTree as ET -from StringIO import StringIO +from io import StringIO class CMEModule: ''' diff --git a/cme/modules/gpp_password.py b/cme/modules/gpp_password.py index 911279f8..c100cb30 100644 --- a/cme/modules/gpp_password.py +++ b/cme/modules/gpp_password.py @@ -2,7 +2,7 @@ import xml.etree.ElementTree as ET from Cryptodome.Cipher import AES from base64 import b64decode from binascii import unhexlify -from StringIO import StringIO +from io import StringIO class CMEModule: ''' diff --git a/cme/modules/invoke_sessiongopher.py b/cme/modules/invoke_sessiongopher.py index e7c815d1..c312bfd8 100644 --- a/cme/modules/invoke_sessiongopher.py +++ b/cme/modules/invoke_sessiongopher.py @@ -1,6 +1,6 @@ from cme.helpers.powershell import * from cme.helpers.logger import write_log -from StringIO import StringIO +from io import StringIO from datetime import datetime class CMEModule: @@ -64,8 +64,8 @@ class CMEModule: def on_response(self, context, response): response.send_response(200) response.end_headers() - length = int(response.headers.getheader('content-length')) - data = response.rfile.read(length) + length = int(response.headers.get('content-length')) + data = response.rfile.read(length).decode() #We've received the response, stop tracking this host response.stop_tracking_host() diff --git a/cme/modules/met_inject.py b/cme/modules/met_inject.py index 9a6c2e76..4820f7ff 100644 --- a/cme/modules/met_inject.py +++ b/cme/modules/met_inject.py @@ -69,7 +69,7 @@ class CMEModule: if 'Invoke-Shellcode.ps1' == request.path[1:]: request.send_response(200) request.end_headers() - request.wfile.write(self.ps_script) + request.wfile.write(self.ps_script.encode()) request.stop_tracking_host() else: request.send_response(404) diff --git a/cme/modules/mimikatz.py b/cme/modules/mimikatz.py index 0312f146..849645a8 100644 --- a/cme/modules/mimikatz.py +++ b/cme/modules/mimikatz.py @@ -38,8 +38,7 @@ class CMEModule: if 'Invoke-Mimikatz.ps1' == request.path[1:]: request.send_response(200) request.end_headers() - - request.wfile.write(self.ps_script) + request.wfile.write(self.ps_script.encode()) else: request.send_response(404) @@ -72,7 +71,6 @@ class CMEModule: hostDomain = "" domainSid = "" hostName = "" - lines = data.split("\n") for line in lines[0:2]: if line.startswith("Hostname:"): @@ -181,8 +179,8 @@ class CMEModule: def on_response(self, context, response): response.send_response(200) response.end_headers() - length = int(response.headers.getheader('content-length')) - data = response.rfile.read(length) + length = int(rresponse.headers.get('content-length')) + data = response.rfile.read(length).decode().decode() # We've received the response, stop tracking this host response.stop_tracking_host() diff --git a/cme/modules/mimikatz_enum_chrome.py b/cme/modules/mimikatz_enum_chrome.py index b3e43183..1dc801d1 100644 --- a/cme/modules/mimikatz_enum_chrome.py +++ b/cme/modules/mimikatz_enum_chrome.py @@ -1,7 +1,7 @@ from cme.helpers.powershell import * from cme.helpers.logger import write_log from datetime import datetime -from StringIO import StringIO +from io import StringIO class CMEModule: ''' @@ -37,7 +37,7 @@ class CMEModule: the entries with Mimikatz, not ideal but it works. ''' - payload = ''' + payload = r''' $cmd = "privilege::debug sekurlsa::dpapi" $userdirs = get-childitem "$Env:SystemDrive\Users" foreach ($dir in $userdirs) {{ @@ -75,7 +75,7 @@ class CMEModule: request.send_response(200) request.end_headers() - request.wfile.write(self.ps_script) + request.wfile.write(self.ps_script.encode()) else: request.send_response(404) @@ -84,8 +84,8 @@ class CMEModule: def on_response(self, context, response): response.send_response(200) response.end_headers() - length = int(response.headers.getheader('content-length')) - data = response.rfile.read(length) + length = int(response.headers.get('content-length')) + data = response.rfile.read(length).decode() #We've received the response, stop tracking this host response.stop_tracking_host() diff --git a/cme/modules/mimikatz_enum_vault_creds.py b/cme/modules/mimikatz_enum_vault_creds.py index 099abd7e..20cf9273 100644 --- a/cme/modules/mimikatz_enum_vault_creds.py +++ b/cme/modules/mimikatz_enum_vault_creds.py @@ -1,7 +1,7 @@ from cme.helpers.powershell import * from cme.helpers.logger import write_log from datetime import datetime -from StringIO import StringIO +from io import StringIO class CMEModule: ''' @@ -48,7 +48,7 @@ class CMEModule: request.send_response(200) request.end_headers() - request.wfile.write(self.ps_script) + request.wfile.write(self.ps_script.encode()) else: request.send_response(404) @@ -57,8 +57,8 @@ class CMEModule: def on_response(self, context, response): response.send_response(200) response.end_headers() - length = int(response.headers.getheader('content-length')) - data = response.rfile.read(length) + length = int(response.headers.get('content-length')) + data = response.rfile.read(length).decode() #We've received the response, stop tracking this host response.stop_tracking_host() diff --git a/cme/modules/mimikittenz.py b/cme/modules/mimikittenz.py index 343926d4..eae367b0 100644 --- a/cme/modules/mimikittenz.py +++ b/cme/modules/mimikittenz.py @@ -35,7 +35,7 @@ class CMEModule: #with open(get_ps_script('mimikittenz/Invoke-mimikittenz.ps1'), 'r') as ps_script: # ps_script = obfs_ps_script(ps_script.read(), function_name=self.obfs_name) - request.wfile.write(self.ps_script) + request.wfile.write(self.ps_script.encode()) else: request.send_response(404) @@ -44,8 +44,8 @@ class CMEModule: def on_response(self, context, response): response.send_response(200) response.end_headers() - length = int(response.headers.getheader('content-length')) - data = response.rfile.read(length) + length = int(response.headers.get('content-length')) + data = response.rfile.read(length).decode() #We've received the response, stop tracking this host response.stop_tracking_host() diff --git a/cme/modules/multirdp.py b/cme/modules/multirdp.py index 114b2a73..41c68f50 100644 --- a/cme/modules/multirdp.py +++ b/cme/modules/multirdp.py @@ -26,7 +26,7 @@ class CMEModule: request.send_response(200) request.end_headers() - request.wfile.write(self.ps_script) + request.wfile.write(self.ps_script.encode()) else: request.send_response(404) @@ -35,8 +35,8 @@ class CMEModule: def on_response(self, context, response): response.send_response(200) response.end_headers() - length = int(response.headers.getheader('content-length')) - data = response.rfile.read(length) + length = int(response.headers.get('content-length')) + data = response.rfile.read(length).decode() #We've received the response, stop tracking this host response.stop_tracking_host() diff --git a/cme/modules/pe_inject.py b/cme/modules/pe_inject.py index 199faab1..4f13e928 100644 --- a/cme/modules/pe_inject.py +++ b/cme/modules/pe_inject.py @@ -66,7 +66,7 @@ class CMEModule: request.send_response(200) request.end_headers() - request.wfile.write(self.ps_script) + request.wfile.write(self.ps_script.encode()) elif os.path.basename(self.payload_path) == request.path[1:]: request.send_response(200) diff --git a/cme/modules/shellcode_inject.py b/cme/modules/shellcode_inject.py index 1f1be529..247407db 100644 --- a/cme/modules/shellcode_inject.py +++ b/cme/modules/shellcode_inject.py @@ -58,7 +58,7 @@ class CMEModule: request.send_response(200) request.end_headers() - request.wfile.write(self.ps_script) + request.wfile.write(self.ps_script.encode()) elif os.path.basename(self.shellcode_path) == request.path[1:]: request.send_response(200) diff --git a/cme/modules/tokens.py b/cme/modules/tokens.py index 041ee8e7..8af18e4d 100644 --- a/cme/modules/tokens.py +++ b/cme/modules/tokens.py @@ -1,6 +1,6 @@ from cme.helpers.powershell import * from datetime import datetime -from StringIO import StringIO +from io import StringIO import os import sys @@ -55,7 +55,7 @@ class CMEModule: request.send_response(200) request.end_headers() - request.wfile.write(self.ps_script) + request.wfile.write(self.ps_script.encode()) else: request.send_response(404) @@ -64,8 +64,8 @@ class CMEModule: def on_response(self, context, response): response.send_response(200) response.end_headers() - length = int(response.headers.getheader('content-length')) - data = response.rfile.read(length) + length = int(response.headers.get('content-length')) + data = response.rfile.read(length).decode() #We've received the response, stop tracking this host response.stop_tracking_host() diff --git a/cme/servers/http.py b/cme/servers/http.py index 09486b58..a3129085 100755 --- a/cme/servers/http.py +++ b/cme/servers/http.py @@ -90,12 +90,12 @@ class CMEServer(threading.Thread): self.server.shutdown() self.server.socket.close() self.server.server_close() - self._Thread__stop() + self._stop() # make sure all the threads are killed for thread in threading.enumerate(): if thread.isAlive(): try: - thread._Thread__stop() + thread._stop() except: pass From f34820939f037f7ef25fdcbf035663935f6442fc Mon Sep 17 00:00:00 2001 From: mpgn Date: Fri, 24 Jan 2020 03:40:02 -0500 Subject: [PATCH 12/13] Remove impacket and pywinrm thirdparty impacket and pywinrm are pip package, no need to have them in the thirdparty folder anymore --- MANIFEST.in | 4 ---- cme/thirdparty/impacket | 1 - cme/thirdparty/pywinrm | 1 - 3 files changed, 6 deletions(-) delete mode 160000 cme/thirdparty/impacket delete mode 160000 cme/thirdparty/pywinrm diff --git a/MANIFEST.in b/MANIFEST.in index 1a641cd2..ec7357c9 100755 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -4,10 +4,6 @@ include LICENSE recursive-include cme/data * recursive-include cme/modules * recursive-include cme/thirdparty * -prune cme/thirdparty/impacket/impacket/testcases -prune cme/thirdparty/impacket/examples -prune cme/thirdparty/pywinrm/winrm/tests -prune cme/thirdparty/pywinrm/scripts prune cme/data/powersploit/Tests prune cme/data/powersploit/CodeExecution/Invoke-ReflectivePEInjection_Resources prune cme/data/powersploit/Exfiltration/LogonUser diff --git a/cme/thirdparty/impacket b/cme/thirdparty/impacket deleted file mode 160000 index bf437b9c..00000000 --- a/cme/thirdparty/impacket +++ /dev/null @@ -1 +0,0 @@ -Subproject commit bf437b9c0a489a17e199cdc8899a89914c1c3113 diff --git a/cme/thirdparty/pywinrm b/cme/thirdparty/pywinrm deleted file mode 160000 index ffec9542..00000000 --- a/cme/thirdparty/pywinrm +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ffec9542d2063305efab9242ffb3623ed618756f From 6ad97132af7de3d8da23e47900cac39ceb1f71a0 Mon Sep 17 00:00:00 2001 From: mpgn Date: Fri, 14 Feb 2020 09:50:15 -0500 Subject: [PATCH 13/13] Fix pylnk error thx to @blshkv --- Pipfile | 2 +- requirements.txt | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Pipfile b/Pipfile index a75accfe..d5813f79 100644 --- a/Pipfile +++ b/Pipfile @@ -17,7 +17,7 @@ netaddr = "*" pyopenssl = "*" termcolor = "*" msgpack-python = "*" -pylnk = "*" +pylnk3 = "*" splinter = "*" paramiko = "*" xmltodict = "*" diff --git a/requirements.txt b/requirements.txt index 2066f3bc..1570a2c4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -19,7 +19,7 @@ paramiko==2.4.2 pyasn1==0.4.5 pycparser==2.19 pycryptodomex==3.7.3 -pylnk==0.2 +pylnk3==0.2.1 pynacl==1.3.0 pyopenssl==19.0.0 requests-ntlm==1.1.0 diff --git a/setup.py b/setup.py index f1ff8dbb..b153e766 100755 --- a/setup.py +++ b/setup.py @@ -30,7 +30,7 @@ setup(name='crackmapexec', 'pyOpenSSL', 'termcolor', 'msgpack-python', - 'pylnk', + 'pylnk3', 'splinter', 'paramiko', 'xmltodict',