def init_bruteforce(self, domain, dict_user, dict_password): self.logger = Logger().get_logger() self.target = Target() self.request = Request() self.domain = domain self.dict_user = dict_user self.dict_password = dict_password self.logger.debug("init_bruteforce")
class Request: _instance = None session = None logger = None def __new__(cls, domain=None, username=None, password=None): # Creating Logger as a Singleton and init the colored output if cls._instance is None: cls._instance = super(Request, cls).__new__(cls) cls._instance.init_requests(domain, username, password) return cls._instance def init_requests(self, domain, username, password): self.logger = Logger().get_logger() # create the sessions object for the requests self.session = requests.Session() self.session.verify = False # update the ua flag self.session.headers.update({'User-Agent': constants.USER_AGENT}) # check if we have to add the auth to our requests if username and password: if domain: username = '******' % (domain, username) self.session.auth = HttpNtlmAuth(username, password) def request_get(self, url): self.logger.debug("request_get") try: r = self.session.get(url, timeout=constants.REQUESTS_TIMEOUT) # close the connection r.close() except requests.exceptions.Timeout: raise ValueError("Request timed out, server is unreachable.") return r def request_post(self, url, json): self.logger.debug("request_post") try: r = self.session.post(url, timeout=constants.REQUESTS_TIMEOUT, json=json) # close the connection r.close() except requests.exceptions.Timeout: raise ValueError("Request timed out, server is unreachable.") return r
def init_requests(self, domain, username, password): self.logger = Logger().get_logger() # create the sessions object for the requests self.session = requests.Session() self.session.verify = False # update the ua flag self.session.headers.update({'User-Agent': constants.USER_AGENT}) # check if we have to add the auth to our requests if username and password: if domain: username = '******' % (domain, username) self.session.auth = HttpNtlmAuth(username, password)
class UserEnum: _instance = None logger = None target = None request = None def __new__(cls): # Creating Logger as a Singleton and init the colored output if cls._instance is None: cls._instance = super(UserEnum, cls).__new__(cls) cls._instance.init_userenum() return cls._instance def init_userenum(self): self.logger = Logger().get_logger() self.target = Target() self.request = Request() def user_enumeration(self): self.logger.debug("user_enumeration") url = "%s%s" % (self.target.url, constants.SHAREPOINT_SITEUSER_API_URL) # Starting User Enumeration try: r = self.request.request_get(url) if r.status_code != '200': self.logger.warning( "User enumeration API is unreachable or current account is not authorized :(" ) else: xml = BeautifulSoup(r.text.encode("utf-8"), "lxml") for child in xml.find_all("m:properties"): info_sid_issuer = child.find("d:userid") found_user = {} found_user["login name"] = child.find("d:loginname").text found_user["title"] = child.find("d:title").text found_user["isSiteAdmin"] = child.find( "d:issiteadmin").text if [t_child for t_child in info_sid_issuer.children]: found_user["sid"] = info_sid_issuer.find( "d:nameid").text found_user["issuer"] = info_sid_issuer.find( "d:nameidissuer").text self.target.found_users.append(found_user) self.logger.info("#################") for key in found_user: logger.info("%s : %s" (key, found_user[key])) self.logger.info("#################") except Exception: raise ValueError("Unhandled exception in user_enumeration.")
class Database: _instance = None logger = None def __new__(cls): # Creating Logger as a Singleton and init the colored output if cls._instance is None: cls._instance = super(Database, cls).__new__(cls) cls._instance.init_database() return cls._instance def init_database(self): self.logger = Logger().get_logger() def verify_installation(self): self.logger.debug("Check if the constants.DATABASE_FOLDER exist.") if not os.path.exists(constants.DATABASE_FOLDER): raise ValueError( "Please run the update flag in order to create the folder db.") # check if our database exist if not os.path.exists('%s%sversions.csv' % (constants.DATABASE_FOLDER, os.path.sep)): raise ValueError( 'Please run the update flag in order to create the version db.' ) # check if our database exist if not os.path.exists('%s%scves.csv' % (constants.DATABASE_FOLDER, os.path.sep)): raise ValueError( 'Please run the update flag in order to create the CVE db.') def update(self): self.logger.info("Running database update.") try: r = requests.get(constants.DB_VERSION_URL, timeout=constants.REQUESTS_TIMEOUT) with open( '%s%scves.csv' % (constants.DATABASE_FOLDER, os.path.sep), 'wb') as f: f.write(r.content) except Exception: raise ValueError("Error while retrieving versions file.") try: r = requests.get(constants.DB_CVE_URL, timeout=constants.REQUESTS_TIMEOUT) with open( '%s%sversions.csv' % (constants.DATABASE_FOLDER, os.path.sep), 'wb') as f: f.write(r.content) except Exception: raise ValueError("Error while retrieving versions file.") self.logger.info("Database updated.")
class BruteForce: _instance = None logger = None target = None request = None domain = None dict_user = None dict_password = None def __new__(cls, domain, dict_user, dict_password): # Creating Logger as a Singleton and init the colored output if cls._instance is None: cls._instance = super(BruteForce, cls).__new__(cls) cls._instance.init_bruteforce(domain, dict_user, dict_password) return cls._instance def init_bruteforce(self, domain, dict_user, dict_password): self.logger = Logger().get_logger() self.target = Target() self.request = Request() self.domain = domain self.dict_user = dict_user self.dict_password = dict_password self.logger.debug("init_bruteforce") def bruteforce(self): self.logger.debug("Starting bruteforce") url = "%s%s" % (self.target.url,constants.SHAREPOINT_DEFAULT_URL) if not path.exists(self.dict_user): raise ValueError("User file does not exists (wrong path?)") if not path.exists(self.dict_password): raise ValueError("Password file does not exists (wrong path?)") file_user = open(self.dict_user, "r") file_password = open(self.dict_password, "r") # save the current session tmp = self.request.session # Starting bruteforce for user in file_user: user = user.rstrip() for passwd in file_password: passwd = passwd.rstrip() # create a new session for each request self.request.init_requests(self.domain, user, passwd) try: r = self.request.request_get(url) if str(r.status_code)[0] != '4': self.logger.debug("Found user and password: %s - %s" % (user, passwd)) self.target.credentials.append({"username":user,"password":passwd}) except Exception as e: raise ValueError("Unhandled error during running the brute force.") # restore the index of the file file_password.seek(0) # restore the old session self.request.session = tmp file_user.close() file_password.close()
def init_userenum(self): self.logger = Logger().get_logger() self.target = Target() self.request = Request()
def init_sharepoint(self): self.logger = Logger().get_logger() self.target = Target() self.request = Request()
class Sharepoint: _instance = None logger = None target = None request = None def __new__(cls): # Creating Logger as a Singleton and init the colored output if cls._instance is None: cls._instance = super(Sharepoint, cls).__new__(cls) cls._instance.init_sharepoint() return cls._instance def init_sharepoint(self): self.logger = Logger().get_logger() self.target = Target() self.request = Request() def check_availability(self): self.logger.debug("check_availability") try: r = self.request.request_get(self.target.url) if r.status_code != 200: self.logger.warning("Please take attention, the target answered with %i code." % r.status_code) except Exception: raise ValueError("Unhandled error on check_availability().") return r def check_iis_target(self, headers): self.logger.debug("check_iis_target") # Detection by header parse detected_version_iis = detect_server_by_headers(headers) if detected_version_iis: self.target.server = detected_version_iis self.logger.debug("Server version Detected (headers parse): {}".format(detected_version_iis)) # detect the technology if present detected_tec = detect_tec_by_headers(headers) if detected_tec: self.target.technology = detected_tec self.logger.debug("Technology detected (headers parse): {}".format(detected_tec)) def check_share_point(self, headers): self.logger.debug("check_share_point") # Detection by header parse detected_version_share_point = self.detect_sharepoint_by_headers(headers) if detected_version_share_point: self.logger.debug("SharePoint version Detected (headers parse): {}".format(detected_version_share_point)) # Detection by conf file parse # if not detected_version_share_point: detected_version_share_point = self.detect_sharepoint_by_servicefile() if detected_version_share_point: self.logger.debug( "SharePoint version Detected (service.cnf parse): {}".format(detected_version_share_point)) self.get_version(detected_version_share_point) def detect_sharepoint_by_headers(self, headers): self.logger.debug("detect_sharepoint_by_headers") useful_headers = [header for header in headers if "sharepoint" in header.lower()] if "MicrosoftSharePointTeamServices" in headers.keys(): version = headers["MicrosoftSharePointTeamServices"].split(";")[0].split(":")[0] return version elif len(useful_headers) > 0: self.logger.warning( "Header %s was found, it may not bring the exact version." % headers[useful_headers[0]].replace("\r\n", "")) return None def detect_sharepoint_by_servicefile(self): self.logger.debug("detect_sharepoint_by_servicefile") version = None for service_url in constants.SHAREPOINT_SERVICE_URLS: try: # request the url and save the data into the session variable r = self.request.request_get(self.target.url + service_url) if r.status_code == 200: if "vti_extenderversion" in r.text: version = r.text.split("vti_extenderversion:SR|")[1].replace("\n", "") break if "vti_buildversion" in r.text: version = r.text.split("vti_extenderversion:SR|")[1].replace("\n", "") break except Exception: raise ValueError("Unhandled error detect_sharepoint_by_servicefile().") return version def get_version(self,patch_number): _patch_tokens = patch_number.split(".") _major_version = int(_patch_tokens[0]) _minor_version = int(_patch_tokens[1]) _build_version = int(_patch_tokens[3]) _patch_number = "%s.%s.%s" % (_major_version,_minor_version,_build_version) _last_version = "" _last_date = "" db_version = { "version": "", "date": "" } with open('%s%sversions.csv' % (constants.DATABASE_FOLDER, os.path.sep),"r") as file_versions: for line in file_versions: _line_tokens = line.split(",") _checked_version = _line_tokens[0].split(".") _checked_version_date = _line_tokens[2] #### if there are not enough tokens, we skip it ####### if(len(_checked_version)<4): continue #### Extract major, minor and build version ####### _checked_version_major = int(_checked_version[0]) _checked_version_minor = int(_checked_version[1]) _checked_version_build = int(_checked_version[2]) #### reformat checked version date ####### if(_checked_version_date!="N/A"): _checked_version_date = datetime.strptime(_checked_version_date, "%Y %B %d") #### reformat checked version structure ####### _checked_version = "%s.%s.%s" % (_checked_version_major,_checked_version_minor,_checked_version_build) #### check if we found a version ####### if(_checked_version == _patch_number): db_version["version"] = _checked_version db_version["date"] = _checked_version_date self.logger.info("Version details found.") break #### if not a suitable version is found, we return the closer one (since they are ordered) ####### if((_major_version > _checked_version_major) or (_major_version == _checked_version_major and _build_version > _checked_version_build)): db_version["version"] = _checked_version db_version["date"] = _checked_version_date self.logger.info("Version could not be found, performing best guess.") break self.target.sharepoint = db_version
def main(): # print banner print_banner() # init logger logger_instance = Logger() logger = logger_instance.get_logger() try: # init options and parse the arguments args = gen_cli_args() # set the verbose level if flagged if args.verbose: logger_instance.enable_debug() # init request and their auth if needed Request(args.domain, args.username, args.password) # init target tg = Target(args.url) # check if we need to update the database an verify the installation db = Database() if args.update: db.update() db.verify_installation() # check if the target is online sh = Sharepoint() # verify if the target is online or not response_obj = sh.check_availability() # check the headers in order to look into the technology and the server sh.check_iis_target(response_obj.headers) # check if we have a sharepoint or something else sh.check_share_point(response_obj.headers) # check cve based on the build number if tg.sharepoint: check_cve = CheckCVE() check_cve.get_cve() # verify if we have to to other checks if args.type != 'i': if args.type == 'a' or args.type == 'ad': # Api scan, checking SOAP stuff detailed = args.type == 'ad' soap_api = CheckSoapApi() soap_api.check_soap_api(detailed) if args.bruteforce: bt = BruteForce(args.domain, args.username_file, args.password_file) bt.bruteforce() if args.enum_users: ue = UserEnum() ue.user_enumeration() logger.info("Scan completed!") logger.info("Results:") logger.info(tg.to_string()) except (KeyboardInterrupt, SystemExit): sys.exit(2) except Exception as e: logger.error(e) sys.exit(1)
def init_checkcve(self): self.logger = Logger().get_logger() self.target = Target() self.db = Database()
def init_database(self): self.logger = Logger().get_logger()
def init_soap_api(self): self.logger = Logger().get_logger() self.target = Target() self.request = Request()
class CheckSoapApi: _instance = None logger = None target = None request = None def __new__(cls): # Creating Logger as a Singleton and init the colored output if cls._instance is None: cls._instance = super(CheckSoapApi, cls).__new__(cls) cls._instance.init_soap_api() return cls._instance def init_soap_api(self): self.logger = Logger().get_logger() self.target = Target() self.request = Request() def check_soap_api(self, detailed): self.logger.debug("starting check_soap_api") url = self.target.url # TODO check more https://docs.microsoft.com/en-us/previous-versions/office/developer/sharepoint-2010/ms467069 for path in constants.SHAREPOINT_ASMX_PATHS: self.check_soap_availability( constants.SHAREPOINT_ASMX_START_PATH % (url, path), detailed) for path in constants.SHAREPOINT_SVC_PATHS: self.check_soap_availability( constants.SHAREPOINT_SVC_START_PATH % (url, path), detailed) def check_soap_availability(self, url, detailed): self.logger.debug("starting check_soap_availability") try: # request the url and save the data into the session variable r = self.request.request_get(url) if r.status_code == 200: self.logger.info("%s is reachable :)." % url) elif r.status_code == 401: self.logger.warning("%s unauthorized :(." % url) return False except Exception: raise ValueError("Unhandled error check_soap_availability().") if detailed: client = Client(url, transport=Transport(session=self.request.session)) for service in client.wsdl.services.values(): for port in service.ports.values(): for operation in port.binding._operations.values(): parameters = {} if operation.input.body: for parameter in operation.input.body.type.elements: parameters[parameter[0]] = xsd.SkipValue with client.settings(raw_response=True): response = client.service[operation.name]( **parameters) if str(response.status_code)[0] == "2": self.logger.info( "--- Available method: %s" % operation.name) if str(response.status_code)[0] == "5": self.logger.info( "--- Maybe available (double check) method: %s" % operation.name)