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 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()
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
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)