时间:2021-07-01 10:21:17 帮助过:6人阅读
我们可以看到这里,首先调用了checkEnvironment()函数,根据名字我们知道这个函数的作用是检测环境。我们跟进来看这个函数:
def checkEnvironment(): try: os.path.isdir(modulePath()) except UnicodeEncodeError: errMsg = "your system does not properly handle non-ASCII paths. " errMsg += "Please move the sqlmap‘s directory to the other location" logger.critical(errMsg) raise SystemExit if distutils.version.LooseVersion(VERSION) < distutils.version.LooseVersion("1.0"): errMsg = "your runtime environment (e.g. PYTHONPATH) is " errMsg += "broken. Please make sure that you are not running " errMsg += "newer versions of sqlmap with runtime scripts for older " errMsg += "versions" logger.critical(errMsg) raise SystemExit # Patch for pip (import) environment if "sqlmap.sqlmap" in sys.modules: for _ in ("cmdLineOptions", "conf", "kb"): globals()[_] = getattr(sys.modules["lib.core.data"], _) for _ in ("SqlmapBaseException", "SqlmapShellQuitException", "SqlmapSilentQuitException", "SqlmapUserQuitException"): globals()[_] = getattr(sys.modules["lib.core.exception"], _)
调用了module()函数并且判断是否是一个正确的路径,如果不是的话,那么将会打印错误信息并且抛出一个异常终止程序继续运行。
我们继续来看module()函数中做了一些什么:
def modulePath(): """ This will get us the program‘s directory, even if we are frozen using py2exe """ try: _ = sys.executable if weAreFrozen() else __file__ #如果用py2exe封装,那么_为python的绝对路径否则就是当前文件名也就是sqlmap.py except NameError: _ = inspect.getsourcefile(modulePath) return getUnicode(os.path.dirname(os.path.realpath(_)), encoding=sys.getfilesystemencoding() or UNICODE_ENCODING)
我们在注释中可以看到是为了获取程序所在的目录。为了防止乱码,返回unicode编码的路径。
getUnicode()函数在这里:sqlmap\lib\core\common.py。这里就不贴代码了。
然后checkEnvironment()判断版本。接着判断sqlmap.sqlmap是否已经加载,如果加载,那么就获取到cmdLineOptions, conf, kb几个属性并且把它们作为全局变量。
接下来,setPaths(modulePath())设置了一下系统各个部分的绝对路径,并且判断.txt, .xml, .zip为扩展名的文件是否存在并且是否可读。
这里我们来思考一个问题,为什么全局要用绝对路径呢?做过开发的同学就知道了,用绝对路径可以避免很多不必要的麻烦,比如说包含文件时候,用相对路径,互相包含,最后越搞越乱,一旦换了一个目录,就会出问题。也不方便日后的维护。用绝对路径,所有的调用全部放在主入口文件,这样单一入口的原则使得系统不仅调用方便,而且看起来还紧凑有序。
然后就是打印banner的信息。这里还有一个值得注意的点就是AttribDict这个数据类型。是这样定义的:
class AttribDict(dict): """ This class defines the sqlmap object, inheriting from Python data type dictionary. >>> foo = AttribDict() >>> foo.bar = 1 >>> foo.bar 1 """ def __init__(self, indict=None, attribute=None): if indict is None: indict = {} # Set any attributes here - before initialisation # these remain as normal attributes self.attribute = attribute dict.__init__(self, indict) self.__initialised = True # After initialisation, setting attributes # is the same as setting an item def __getattr__(self, item): """ Maps values to attributes Only called if there *is NOT* an attribute with this name """ try: return self.__getitem__(item) except KeyError: raise AttributeError("unable to access item ‘%s‘" % item) def __setattr__(self, item, value): """ Maps attributes to values Only if we are initialised """ # This test allows attributes to be set in the __init__ method if "_AttribDict__initialised" not in self.__dict__: return dict.__setattr__(self, item, value) # Any normal attributes are handled normally elif item in self.__dict__: dict.__setattr__(self, item, value) else: self.__setitem__(item, value) def __getstate__(self): return self.__dict__ def __setstate__(self, dict): self.__dict__ = dict def __deepcopy__(self, memo): retVal = self.__class__() memo[id(self)] = retVal for attr in dir(self): if not attr.startswith(‘_‘): value = getattr(self, attr) if not isinstance(value, (types.BuiltinFunctionType, types.FunctionType, types.MethodType)): setattr(retVal, attr, copy.deepcopy(value, memo)) for key, value in self.items(): retVal.__setitem__(key, copy.deepcopy(value, memo)) return retVal
继承了内置的dict,并且重写了一些方法。然后就可以这样去访问键值对:var.key。感慨 一下,好牛!!!
0x01 获取命令行参数选项
这里主要使用了optparse这个函数库。python中十分好用的一个命令行工具。具体可以参考这里:https://docs.python.org/2/library/optparse.html
首先将获取到的命令行参数选项进行判断和拆分以后转变成dict键值对的形式存入到cmdLineOptions。然后开始依据传入的参数进行后续操作。
在获取命令行参数的时候,有很多dirty hack写法,感兴趣可以好好品味。这个层次的认知来源于对底层库函数的熟悉。再次感慨,好牛!!!
这里重要的一个操作是_mergeOptions(),主要的作用是将配置项中的参数和命令行获得的参数选项以及缺省选项进行合并。函数是这么写的:
def _mergeOptions(inputOptions, overrideOptions): """ Merge command line options with configuration file and default options. @param inputOptions: optparse object with command line options. @type inputOptions: C{instance} """ if inputOptions.pickledOptions: try: unpickledOptions = base64unpickle(inputOptions.pickledOptions, unsafe=True) if type(unpickledOptions) == dict: unpickledOptions = AttribDict(unpickledOptions) _normalizeOptions(unpickledOptions) unpickledOptions["pickledOptions"] = None for key in inputOptions: if key not in unpickledOptions: unpickledOptions[key] = inputOptions[key] inputOptions = unpickledOptions except Exception, ex: errMsg = "provided invalid value ‘%s‘ for option ‘--pickled-options‘" % inputOptions.pickledOptions errMsg += " (%s)" % repr(ex) raise SqlmapSyntaxException(errMsg) if inputOptions.configFile: configFileParser(inputOptions.configFile) if hasattr(inputOptions, "items"): inputOptionsItems = inputOptions.items() else: inputOptionsItems = inputOptions.__dict__.items() for key, value in inputOptionsItems: if key not in conf or value not in (None, False) or overrideOptions: conf[key] = value if not hasattr(conf, "api"): for key, value in conf.items(): if value is not None: kb.explicitSettings.add(key) for key, value in defaults.items(): if hasattr(conf, key) and conf[key] is None: conf[key] = value lut = {} for group in optDict.keys(): lut.update((_.upper(), _) for _ in optDict[group]) envOptions = {} for key, value in os.environ.items(): if key.upper().startswith(SQLMAP_ENVIRONMENT_PREFIX): _ = key[len(SQLMAP_ENVIRONMENT_PREFIX):].upper() if _ in lut: envOptions[lut[_]] = value if envOptions: _normalizeOptions(envOptions) for key, value in envOptions.items(): conf[key] = value mergedOptions.update(conf)
然后我们来调试一下,打印一下最后的mergedOptions,结果如下:
{‘code‘: None, ‘getUsers‘: None, ‘resultsFilename‘: None, ‘excludeSysDbs‘: None, ‘ignoreTimeouts‘: None, ‘skip‘: None, ‘db‘: None, ‘prefix‘: None, ‘osShell‘: None, ‘googlePage‘: 1, ‘query‘: None, ‘getComments‘: None, ‘randomAgent‘: None, ‘testSkip‘: None, ‘authType‘: None, ‘getPasswordHashes‘: None, ‘parameters‘: {}, ‘predictOutput‘: None, ‘wizard‘: None, ‘stopFail‘: None, ‘forms‘: None, ‘uChar‘: None, ‘authUsername‘: None, ‘pivotColumn‘: None, ‘dropSetCookie‘: None, ‘dbmsCred‘: None, ‘tests‘: [], ‘paramExclude‘: None, ‘risk‘: 1, ‘sqlFile‘: None, ‘rParam‘: None, ‘getCurrentUser‘: None, ‘notString‘: None, ‘getRoles‘: None, ‘getPrivileges‘: None, ‘testParameter‘: None, ‘tbl‘: None, ‘offline‘: None, ‘trafficFile‘: None, ‘osSmb‘: None, ‘level‘: 1, ‘dnsDomain‘: None, ‘skipStatic‘: None, ‘secondOrder‘: None, ‘hashDBFile‘: None, ‘method‘: None, ‘skipWaf‘: None, ‘osBof‘: None, ‘hostname‘: None, ‘firstChar‘: None, ‘torPort‘: None, ‘wFile‘: None, ‘binaryFields‘: None, ‘checkTor‘: None, ‘commonTables‘: None, ‘direct‘: None, ‘paramDict‘: {}, ‘proxyList‘: None, ‘titles‘: None, ‘getSchema‘: None, ‘timeSec‘: 5, ‘paramDel‘: None, ‘safeReqFile‘: None, ‘port‘: None, ‘getColumns‘: None, ‘headers‘: None, ‘crawlExclude‘: None, ‘authCred‘: None, ‘boundaries‘: [], ‘loadCookies‘: None, ‘showVersion‘: None, ‘outputDir‘: None, ‘tmpDir‘: None, ‘disablePrecon‘: None, ‘murphyRate‘: None, ‘invalidLogical‘: None, ‘getCurrentDb‘: None, ‘hexConvert‘: None, ‘proxyFile‘: None, ‘answers‘: None, ‘resultsFP‘: None, ‘host‘: None, ‘dependencies‘: None, ‘cookie‘: None, ‘dbmsHandler‘: None, ‘path‘: None, ‘alert‘: None, ‘optimize‘: None, ‘safeUrl‘: None, ‘limitStop‘: None, ‘search‘: None, ‘uFrom‘: None, ‘requestFile‘: None, ‘noCast‘: None, ‘testFilter‘: None, ‘eta‘: None, ‘dumpPath‘: None, ‘csrfToken‘: None, ‘threads‘: 1, ‘logFile‘: None, ‘os‘: None, ‘col‘: None, ‘proxy‘: None, ‘proxyCred‘: None, ‘verbose‘: 1, ‘crawlDepth‘: None, ‘updateAll‘: None, ‘privEsc‘: None, ‘forceDns‘: None, ‘getAll‘: None, ‘cj‘: None, ‘hpp‘: None, ‘tmpPath‘: None, ‘header‘: None, ‘url‘: u‘www.baidu.com‘, ‘invalidBignum‘: None, ‘regexp‘: None, ‘getDbs‘: None, ‘httpHeaders‘: [], ‘outputPath‘: None, ‘freshQueries‘: None, ‘uCols‘: None, ‘smokeTest‘: None, ‘ignoreProxy‘: None, ‘regData‘: None, ‘udfInject‘: None, ‘invalidString‘: None, ‘tor‘: None, ‘forceSSL‘: None, ‘ignore401‘: None, ‘beep‘: None, ‘noEscape‘: None, ‘configFile‘: None, ‘ipv6‘: False, ‘scope‘: None, ‘scheme‘: None, ‘authFile‘: None, ‘dbmsConnector‘: None, ‘torType‘: ‘SOCKS5‘, ‘regVal‘: None, ‘string‘: None, ‘hashDB‘: None, ‘mnemonics‘: None, ‘skipUrlEncode‘: None, ‘referer‘: None, ‘agent‘: None, ‘regType‘: None, ‘purgeOutput‘: None, ‘retries‘: 3, ‘wFileType‘: None,