def start(): if kb.targets and kb.targets.qsize() > 1: infoMsg = "pocsuite got a total of %d targets" % kb.targets.qsize() logger.log(CUSTOM_LOGGING.SYSINFO, infoMsg) runThreads(conf.threads, pocThreads) resultTable = PrettyTable(["target-url", "poc-name", "poc-id", "component", "version", "status"]) resultTable.padding_width = 1 if not kb.results: return toNum, sucNum = 0, 0 for row in kb.results: resultTable.add_row(list(row)[:-2]) toNum += 1 if row[5] == 'success': sucNum += 1 if not conf.quiet: print resultTable # infoMsg = "{} of {} success !".format(sucNum, toNum) # logger.log(CUSTOM_LOGGING.SYSINFO, infoMsg) print "success : {} / {}".format(sucNum, toNum) _createTargetDirs() _setRecordFiles() if conf.report: _setReport()
def showResult(tag): for key1, value1 in resultJson[tag].iteritems(): for key2, value2 in value1.iteritems(): if key1 != 'verifyInfo': logger.log(CUSTOM_LOGGING.SUCCESS, key2 + " : " + resultJson[tag][key1][key2]) pass
def execReq(poc, mode, targetUrl): pocInfo, devilJson = poc['pocInfo'], poc["pocExecute"] result = False infoMsg = "poc-%s '%s' has already been detected against '%s'." % (pocInfo["vulID"], pocInfo["name"], targetUrl) logger.log(CUSTOM_LOGGING.SUCCESS, infoMsg) for targetJson in devilJson[mode]: if mode == 'verify': result = _executeVerify(pocInfo, targetJson, targetUrl, 'verify') if targetJson['step'] == '0' and result: return True elif targetJson['step'] != '0' and not result: return False else: result = _executeAttack(pocInfo, targetJson, targetUrl) if targetJson['step'] == '0' and result: showResult(targetUrl + pocInfo['vulID']) return True elif targetJson['step'] != '0' and not result: return False if result: showResult(targetUrl + pocInfo['vulID']) return result
def _createTargetDirs(): """ Create the output directory. """ if not os.path.isdir(paths.POCSUITE_OUTPUT_PATH): try: if not os.path.isdir(paths.POCSUITE_OUTPUT_PATH): os.makedirs(paths.POCSUITE_OUTPUT_PATH, 0755) warnMsg = "using '%s' as the output directory" % paths.POCSUITE_OUTPUT_PATH logger.log(CUSTOM_LOGGING.WARNING, warnMsg) except (OSError, IOError), ex: try: tempDir = tempfile.mkdtemp(prefix="pocsuiteoutput") except Exception, _: errMsg = "unable to write to the temporary directory ('%s'). " % _ errMsg += "Please make sure that your disk is not full and " errMsg += "that you have sufficient write permissions to " errMsg += "create temporary files and/or directories" raise PocsuiteSystemException(errMsg) warnMsg = "unable to create regular output directory " warnMsg += "'%s' (%s). " % (paths.POCSUITE_OUTPUT_PATH, getUnicode(ex)) warnMsg += "Using temporary directory '%s' instead" % getUnicode(tempDir) logger.log(CUSTOM_LOGGING.WARNING, warnMsg) paths.POCUSITE_OUTPUT_PATH = tempDir
def setPoc(): """ @function 重新设置conf.pocFile """ if conf.isPocString: retVal = loadPoc(conf.pocFile) kb.pocs.update(retVal) elif len(conf.pocFile.split(",")) > 1: for pocFile in conf.pocFile.split(","): pocFile = os.path.abspath(pocFile) retVal = loadPoc(pocFile) kb.pocs.update(retVal) else: conf.pocFile = os.path.abspath(conf.pocFile) if os.path.isfile(conf.pocFile): retVal = loadPoc(conf.pocFile) kb.pocs.update(retVal) elif os.path.isdir(conf.pocFile): pyFiles = glob.glob(os.path.join(conf.pocFile, "*.py")) jsonFiles = glob.glob(os.path.join(conf.pocFile, "*.json")) pocFiles = pyFiles + jsonFiles for pocFile in pocFiles: retVal = loadPoc(pocFile) kb.pocs.update(retVal) else: errMsg = "can't find any valid PoCs" logger.log(CUSTOM_LOGGING.ERROR, errMsg)
def loadPoc(pocFile): if pocFile.endswith(".pyc"): conf.isPycFile = True if conf.isPocString: poc = conf.pocFile if not conf.pocname: if conf.pocFile: conf.pocname = os.path.split(conf.pocFile)[1] else: errMsg = "Use pocString must provide pocname" logger.log(CUSTOM_LOGGING.ERROR, errMsg) pocname = conf.pocname else: pocname = os.path.split(pocFile)[1] poc = readFile(pocFile) if not conf.isPycFile: if not re.search(POC_REGISTER_REGEX, poc): warnMsg = "poc: %s register is missing" % pocname logger.log(CUSTOM_LOGGING.WARNING, warnMsg) className = getPocClassName(poc) poc += POC_REGISTER_STRING.format(className) retVal = multipleReplace(poc, POC_IMPORTDICT) else: retVal = poc return {pocname: retVal}
def run(self): threads = [] try: for thread_num in xrange(self.threads_num): thread = threading.Thread(target=self.brute_names, name=str(thread_num)) thread.setDaemon(True) thread.start() threads.append(thread) alive = True while alive: alive = False for thread in threads: if thread.isAlive(): alive = True time.sleep(0.1) except KeyboardInterrupt: if self.threads_num > 1: logger.log(CUSTOM_LOGGING.SYSINFO, "waiting for threads to finish (Ctrl+C was pressed)") try: while (threading.activeCount() > 1): pass except KeyboardInterrupt: raise PocsuiteThreadException("user aborted (Ctrl+C was pressed multiple times)")
def execute(self, target, headers=None, params=None, mode='verify', verbose=True): """ :param url: the target url :param headers: a :class dict include some fields for request header. :param params: a instance of Params, includ extra params :return: A instance of Output """ self.target = target self.url = parseTargetUrl(target) self.headers = headers self.params = strToDict(params) if params else {} self.mode = mode self.verbose = verbose self.expt = 'None' # TODO output = None try: if self.mode == 'attack': output = self._attack() else: output = self._verify() except NotImplementedError, e: self.expt = (ERROR_TYPE_ID.NOTIMPLEMENTEDERROR, e) logger.log( CUSTOM_LOGGING.ERROR, 'POC: %s not defined ' '%s mode' % (self.name, self.mode)) output = Output(self)
def pocThreads(): """ @function multiThread executing """ kb.pCollect = set() while not kb.targets.empty() and kb.threadContinue: target, poc, pocname = kb.targets.get() infoMsg = "poc:'%s' target:'%s'" % (pocname, target) logger.log(CUSTOM_LOGGING.SYSINFO, infoMsg) # TODO json if isinstance(poc, dict): pocInfo = poc['pocInfo'] result = execReq(poc, conf.mode, target) output = (target, pocname, pocInfo["vulID"], pocInfo["appName"], pocInfo["appVersion"], "success" if result else "failed", time.strftime("%Y-%m-%d %X", time.localtime()), str(result.result)) else: kb.pCollect.add(poc.__module__) result = poc.execute(target, headers=conf.httpHeaders, mode=conf.mode, params=conf.params, verbose=True) if not result: continue output = (target, pocname, result.vulID, result.appName, result.appVersion, "success" if result.is_success() else result.error, time.strftime("%Y-%m-%d %X", time.localtime()), str(result.result)) result.show_result() kb.results.add(output) if isinstance(conf.delay, (int, float)) and conf.delay > 0: time.sleep(conf.delay / 1000)
def setPoc(): """ @function 重新设置conf.pocFile """ if conf.isPocString: retVal = loadPoc(conf.pocFile) kb.pocs.update(retVal) elif len(conf.pocFile.split(",")) > 1: for pocFile in conf.pocFile.split(","): pocFile = os.path.abspath(pocFile) retVal = loadPoc(pocFile) kb.pocs.update(retVal) else: conf.pocFile = os.path.abspath(conf.pocFile) if os.path.isfile(conf.pocFile): retVal = loadPoc(conf.pocFile) kb.pocs.update(retVal) elif os.path.isdir(conf.pocFile): pyFiles = glob.glob(os.path.join(conf.pocFile, "*.py")) jsonFiles = glob.glob(os.path.join(conf.pocFile, "*.json")) pocFiles = pyFiles + jsonFiles for pocFile in pocFiles: retVal = loadPoc(pocFile) kb.pocs.update(retVal) else: errMsg = "can't find any valid PoCs" logger.log(CUSTOM_LOGGING.ERROR, errMsg) conf.pocFile = None
def execute(self, target, headers=None, params=None, mode='verify', verbose=True): """ :param url: the target url :param headers: a :class dict include some fields for request header. :param params: a instance of Params, includ extra params :return: A instance of Output """ self.target = target self.url = parseTargetUrl(target) self.headers = headers self.params = strToDict(params) if params else {} self.mode = mode self.verbose = verbose self.expt = 'None' # TODO output = None try: if self.mode == 'attack': output = self._attack() else: output = self._verify() except NotImplementedError, e: self.expt = (ERROR_TYPE_ID.NOTIMPLEMENTEDERROR, e) logger.log(CUSTOM_LOGGING.ERROR, 'POC: %s not defined ' '%s mode' % (self.name, self.mode)) output = Output(self)
def check_param(self, *args): poc_name = getattr(self, "name") params = getattr(self, "params") if field not in params: errMsg = "poc: %s need params \"%s\"" % (poc_name, field) logger.log(CUSTOM_LOGGING.ERROR, errMsg) return return function(self, *args)
def check_header(self, *args): poc_name = getattr(self, "name") headers = getattr(self, "headers") if field.lower() not in map(str.lower, headers.keys()): errMsg = "poc: %s need headers \"%s\"" % (poc_name, field) logger.log(CUSTOM_LOGGING.ERROR, errMsg) return return function(self, *args)
def show_result(self): if self.status == OUTPUT_STATUS.SUCCESS: for k, v in self.result.items(): if isinstance(v, dict): for kk, vv in v.items(): logger.log(CUSTOM_LOGGING.SUCCESS, "%s : %s" % (kk, vv)) else: logger.log(CUSTOM_LOGGING.SUCCESS, "%s : %s" % (k, v))
def registerPoc(self): pocString = multipleReplace(self.pocString, POC_IMPORTDICT) _, self.moduleName = filepathParser(self.pocName) try: importer = StringImporter(self.moduleName, pocString) importer.load_module(self.moduleName) except ImportError, ex: logger.log(CUSTOM_LOGGING.ERROR, ex)
def _register_poc(self): poc_string = multiple_replace(self.poc_string, POC_IMPORTDICT) path, self.module_name = file_path_parser(self.poc_name) try: string_importer(self.module_name, poc_string) except ImportError as e: err_msg = "{0} register failed '{1!s}'".format(self.module_name, e) logger.log(CUSTOM_LOGGING.ERROR.value, err_msg)
def registerPyPoc(pocDict): pocname = pocDict.keys()[0] _, moduleName = filepathParser(pocname) try: importer = StringImporter(moduleName, pocDict[pocname]) importer.load_module(moduleName) except ImportError, ex: errMsg = "%s register failed \"%s\"" % (moduleName, str(ex)) logger.log(CUSTOM_LOGGING.ERROR, errMsg)
class POCBase(object): def __init__(self): self.type = None self.target = None self.url = None self.mode = None self.params = None self.verbose = None def execute(self, target, headers=None, params=None, mode='verify', verbose=True): """ :param url: the target url :param headers: a :class dict include some fields for request header. :param params: a instance of Params, includ extra params :return: A instance of Output """ self.target = target self.url = parseTargetUrl(target) self.headers = headers self.params = strToDict(params) if params else {} self.mode = mode self.verbose = verbose self.expt = (0, 'None') # TODO output = None try: if self.mode == 'attack': output = self._attack() else: output = self._verify() except NotImplementedError, e: self.expt = (ERROR_TYPE_ID.NOTIMPLEMENTEDERROR, e) logger.log(CUSTOM_LOGGING.ERROR, 'POC: %s not defined ' '%s mode' % (self.name, self.mode)) output = Output(self) except ConnectTimeout, e: self.expt = (ERROR_TYPE_ID.CONNECTTIMEOUT, e) while conf.retry > 0: logger.log(CUSTOM_LOGGING.WARNING, 'POC: %s timeout, start it over.' % self.name) try: if self.mode == 'attack': output = self._attack() else: output = self._verify() break except ConnectTimeout: logger.log(CUSTOM_LOGGING.ERROR, 'POC: %s time-out retry failed!' % self.name) output = Output(self) conf.retry -= 1 else: logger.log(CUSTOM_LOGGING.ERROR, str(e)) output = Output(self)
def exceptionHandledFunction(threadFunction): try: threadFunction() except KeyboardInterrupt: kb.threadContinue = False kb.threadException = True raise except Exception, errMsg: # thread is just going to be silently killed logger.log(CUSTOM_LOGGING.ERROR, "thread %s: %s" % (threading.currentThread().getName(), errMsg))
def check_type(self, *args): poc_name = getattr(self, "name") require_type = getattr(self, type) fields = [field] if isinstance(field, basestring) else field for _ in fields: if (not require_type) or (_.lower() not in map(str.lower, require_type.keys())): errMsg = "poc: %s need %s \"%s\"" % (poc_name, type, _) logger.log(CUSTOM_LOGGING.ERROR, errMsg) return return function(self, *args)
def registerPoc(self): pocString = multipleReplace(self.pocString, POC_IMPORTDICT) _, fileName = filepathParser(self.pocName) self.moduleName = "%s%s" % (fileName, hashlib.md5( self.target).hexdigest()[:8]) try: importer = StringImporter(self.moduleName, pocString) importer.load_module(self.moduleName) except ImportError, ex: logger.log(CUSTOM_LOGGING.ERROR, ex)
def writeBinary(fileName, content, encoding='utf8'): """ write file with given fileName and encoding """ try: fp = codecs.open(fileName, mode='wb+', encoding=encoding) fp.write(content) fp.close() logger.log(CUSTOM_LOGGING.SYSINFO, '"%s" write to Text file "%s"' % (content, fileName)) except Exception as e: logger.log(CUSTOM_LOGGING.WARNING, e)
def run(self): try: poc = kb.registeredPocs[self.moduleName] result = poc.execute(self.target, headers=conf.httpHeaders, mode=self.mode, params=self.params) output = (self.target, self.pocName, result.vulID, result.appName, result.appVersion, (1, "success") if result.is_success() else result.error, time.strftime("%Y-%m-%d %X", time.localtime()), str(result.result)) if self.delmodule: delModule(self.moduleName) return output except Exception, ex: logger.log(CUSTOM_LOGGING.ERROR, ex)
def check_type(self, *args): poc_name = getattr(self, "name") require_type = getattr(self, type) fields = [field] if isinstance(field, basestring) else field for _ in fields: if (not require_type) or (_.lower() not in map( str.lower, require_type.keys())): errMsg = "poc: %s need %s \"%s\"" % (poc_name, type, _) logger.log(CUSTOM_LOGGING.ERROR, errMsg) return return function(self, *args)
def openerHeaders(op): headers = {} try: assert isinstance(op, urllib2.OpenerDirector) _ = op.addheaders for pair in _: # pair_copy = [part for part in pair] headers.update({pair[0]: pair[1]}) except: errMsg = 'unable to fetch headers from given opener' logger.log(CUSTOM_LOGGING.ERROR, errMsg) return headers
def openerHeaders(op): headers = {} try: assert isinstance(op, urllib2.OpenerDirector) _ = op.addheaders for pair in _: pair_copy = [part for part in pair] headers.update({pair[0]: pair[1]}) except: errMsg = 'unable to fetch headers from given opener' logger.log(CUSTOM_LOGGING.ERROR, errMsg) return headers
def loadText(fileName, encoding='utf8'): """ read file with given fileName and encoding """ try: fp = codecs.open(fileName, mode='r', encoding=encoding) content = fp.readlines() fp.close() logger.log(CUSTOM_LOGGING.SYSINFO, 'return file "%s" content .' % fileName) return content except Exception as e: logger.log(CUSTOM_LOGGING.WARNING, e)
def checkPocInfo(pocName, pocInstance): infos = [] infoMsg = "checking %s" % pocName logger.log(CUSTOM_LOGGING.SYSINFO, infoMsg) for attr in POC_ATTRS: if hasattr(pocInstance, attr) and getattr(pocInstance, attr): continue infos.append(attr) if infos: warnMsg = "missing %s in %s" % (infos, pocName) logger.log(CUSTOM_LOGGING.WARNING, warnMsg) return False return True
def checkPocInfo(pocName, pocInstance): infos = [] infoMsg = "checking %s" % pocInstance.name logger.log(CUSTOM_LOGGING.SYSINFO, infoMsg) for attr in POC_ATTRS: if hasattr(pocInstance, attr) and getattr(pocInstance, attr): continue infos.append(attr) if infos: warnMsg = "missing %s in %s" % (infos, pocName) logger.log(CUSTOM_LOGGING.WARNING, warnMsg) return False return True
def checkJsonInfo(pocName, pocInstance): infos = [] infoMsg = "checking %s" % pocName logger.log(CUSTOM_LOGGING.SYSINFO, infoMsg) if 'pocInfo' in pocInstance: for attr in POC_ATTRS: if attr in pocInstance['pocInfo'] and pocInstance['pocInfo'].get(attr): continue infos.append(attr) if infos: warnMsg = "missing %s in %s" % (infos, pocName) logger.log(CUSTOM_LOGGING.WARNING, warnMsg) return False return True
def requiresCheck(): if not conf.requires: return requires_regex = re.compile(POC_REQUIRES_REGEX) install_requires = [] for _, poc in kb.pocs.items(): try: requires = requires_regex.search(poc).group(1) install_requires += [require[1:-1] for require in requires.split(",")] except: pass infoMsg = "install_requires:\n" + "\n".join(install_requires) logger.log(CUSTOM_LOGGING.SYSINFO, infoMsg)
def _setHTTPProxy(): """ Check and set the HTTP/SOCKS proxy for all HTTP requests. """ if not conf.proxy: return infoMsg = "setting the HTTP/SOCKS proxy for all HTTP requests" logger.log(CUSTOM_LOGGING.SYSINFO, infoMsg) try: _ = urlparse.urlsplit(conf.proxy) except Exception, ex: errMsg = "invalid proxy address '%s' ('%s')" % (conf.proxy, ex) raise PocsuiteSyntaxException(errMsg)
def _executeVerify(pocInfo, targetJson, targetUrl, mode): url, startTime = parseTargetUrl(targetUrl), time.time() step, method, path, params, headers, match, status_code = initilizeJson(targetJson) if (targetUrl + pocInfo['vulID']) not in resultJson: resultJson[targetUrl + pocInfo['vulID']] = {} resultJson[targetUrl + pocInfo['vulID']]['verifyInfo'] = {'URL': url, 'Postdata': params, 'Path': path} try: if method == 'get': r = req.get('%s/%s' % (url, path), params=params, headers=headers) else: r = req.post('%s/%s' % (url, path), data=params, headers=headers) except Exception, ex: logger.log(CUSTOM_LOGGING.ERROR, str(ex)) return False
def runThreads(numThreads, threadFunction, forwardException=True, startThreadMsg=True): threads = [] kb.multiThreadMode = True kb.threadContinue = True kb.threadException = False try: if numThreads > 1: if startThreadMsg: infoMsg = "starting %d threads" % numThreads logger.log(CUSTOM_LOGGING.SYSINFO, infoMsg) else: threadFunction() return for numThread in xrange(numThreads): thread = threading.Thread(target=exceptionHandledFunction, name=str(numThread), args=[threadFunction]) setDaemon(thread) try: thread.start() except threadError, errMsg: errMsg = "error occurred while starting new thread ('%s')" % errMsg logger.log(CUSTOM_LOGGING.ERROR, errMsg) break threads.append(thread) # And wait for them to all finish alive = True while alive: alive = False for thread in threads: if thread.isAlive(): alive = True time.sleep(0.1)
def _setHTTPExtraHeaders(): if conf.headers: infoMsg = "setting extra HTTP headers" logger.log(CUSTOM_LOGGING.SYSINFO, infoMsg) conf.headers = conf.headers.split("\n") if "\n" in conf.headers else conf.headers.split("\\n") for headerValue in conf.headers: if not headerValue.strip(): continue if headerValue.count(':') >= 1: header, value = (_.lstrip() for _ in headerValue.split(":", 1)) if header and value: conf.httpHeaders[header] = value else: errMsg = "invalid header value: %s. Valid header format is 'name:value'" % repr(headerValue).lstrip('u') raise PocsuiteSyntaxException(errMsg)
def execute(self, target, headers=None, params=None, mode='verify', verbose=True): """ :param url: the target url :param headers: a :class dict include some fields for request header. :param params: a instance of Params, includ extra params :return: A instance of Output """ self.target = target self.url = parseTargetUrl(target) self.headers = headers self.params = params self.mode = mode self.verbose = verbose # TODO output = None try: if self.mode == 'attack': output = self._attack() else: output = self._verify() except NotImplementedError: logger.log( CUSTOM_LOGGING.ERROR, 'POC: %s not defined ' '%s mode' % (self.name, self.mode)) output = Output(self) except ConnectTimeout, e: while conf.retry > 0: logger.log(CUSTOM_LOGGING.WARNING, 'POC: %s timeout, start it over.' % self.name) try: if self.mode == 'attack': output = self._attack() else: output = self._verify() break except ConnectTimeout: logger.log(CUSTOM_LOGGING.ERROR, 'POC: %s time-out retry failed!' % self.name) output = Output(self) conf.retry -= 1 else: logger.log(CUSTOM_LOGGING.ERROR, str(e)) output = Output(self)
def _setHTTPTimeout(): """ Set the HTTP timeout """ if conf.timeout: infoMsg = "setting the HTTP timeout" logger.log(CUSTOM_LOGGING.SYSINFO, infoMsg) conf.timeout = float(conf.timeout) if conf.timeout < 3.0: warnMsg = "the minimum HTTP timeout is 3 seconds, pocsuite will going to reset it" logger.log(CUSTOM_LOGGING.WARNING, warnMsg) conf.timeout = 3.0 else: conf.timeout = 30.0 socket.setdefaulttimeout(conf.timeout)
def registerPocFromDict(): """ @function import方式导入Poc文件, import Poc的时候自动rigister了 """ for pocname, poc in kb.pocs.items(): pocDict = {pocname: poc} if pocname.endswith(".py"): if not isOldVersionPoc(poc): registerPyPoc(pocDict) else: warnMsg = "%s is old version poc" % pocname logger.log(CUSTOM_LOGGING.WARNING, warnMsg) elif poc.endswith(".json"): registerJsonPoc(pocDict) else: if conf.isPycFile: registerPyPoc(pocDict) else: warnMsg = "invalid PoC %s" % pocDict["pocname"] logger.log(CUSTOM_LOGGING.WARNING, errMsg)
def show_result(self): if self.status == OUTPUT_STATUS.SUCCESS: infoMsg = "poc-%s '%s' has already been detected against '%s'." % (self.vulID, self.name, self.url) logger.log(CUSTOM_LOGGING.SUCCESS, infoMsg) for k, v in self.result.items(): if isinstance(v, dict): for kk, vv in v.items(): logger.log(CUSTOM_LOGGING.SUCCESS, "%s : %s" % (kk, vv)) else: logger.log(CUSTOM_LOGGING.SUCCESS, "%s : %s" % (k, v)) else: errMsg = "poc-%s '%s' failed." % (self.vulID, self.name) logger.log(CUSTOM_LOGGING.ERROR, errMsg)
def pocViolation(): violation = False if conf.requiresFreeze: install_requires = [] for pocName, pocInstance in kb.registeredPocs.items(): if isinstance(pocInstance, dict): continue requires = getRequires(pocName, pocInstance) if not requires: continue install_requires += list(requires) infoMsg = "install_requires:\n" + "\n".join(install_requires) logger.log(CUSTOM_LOGGING.SYSINFO, infoMsg) return for pocName, pocInstance in kb.registeredPocs.items(): if isinstance(pocInstance, dict): violation = checkJsonInfo(pocName, pocInstance) else: violation = checkPocInfo(pocName, pocInstance) return violation
def _setHTTPUserAgent(): """ @function Set the HTTP User-Agent header. """ if conf.agent: debugMsg = "setting the HTTP User-Agent header" logger.debug(debugMsg) conf.httpHeaders[HTTP_HEADER.USER_AGENT] = conf.agent if conf.randomAgent: infoMsg = "loading random HTTP User-Agent header(s) from " infoMsg += "file '%s'" % paths.USER_AGENTS logger.log(CUSTOM_LOGGING.SYSINFO, infoMsg) try: userAgents = getFileItems(paths.USER_AGENTS) except IOError: warnMsg = "unable to read HTTP User-Agent header " warnMsg += "file '%s'" % paths.USER_AGENTS logger.log(CUSTOM_LOGGING.WARNING, warnMsg) return userAgent = random.sample(userAgents, 1) infoMsg = "fetched random HTTP User-Agent header from " infoMsg += "file '%s': '%s'" % (paths.USER_AGENTS, userAgent) logger.log(CUSTOM_LOGGING.SYSINFO, infoMsg) conf.httpHeaders[HTTP_HEADER.USER_AGENT] = userAgent