sqlmap源碼分析(一)


Sqlmap源碼分析(一)

此次分析的sqlmap目標版本為1.6.1.2#dev

只對sqlmap的核心檢測代碼進行詳細分析其他的一帶而過

sqlmap.py文件結構

為了不讓篇幅過長下面只寫出了sqlmap.py(入口點)引用的前三個函數,

from __future__ import print_function  # 即使在python2.X,使用print就得像python3.X那樣加括號
try:
    '''
    	代碼作用:
        python版本檢測 導入必要的包 禁止生成__pycache__
        導入官方模塊
        消除一些可忽略的警告
        導入自定義模塊
    '''
except KeyboardInterrupt:
    '''
    代碼作用:
    處理ctrl c v手動中斷
    '''  
	
def modulePath():
    pass 
def checkEnvironment():
    pass # 下方有詳細代碼 這里為了方便展示整體結構不再列出
def main():
    try:
        dirtyPatches() # 補丁 針對python3進行額外配置,對其他第三方的一些參數調整(下方有詳細代碼)
        resolveCrossReferences() # 解決交叉引用(下方有詳細代碼)
        checkEnvironment()  # 檢測環境 sqlmap版本和路徑是否正常(下方有詳細代碼)
        setPaths(modulePath())  # 路徑配置
        banner()  # 見名知意打印banner信息
		'''
		代碼作用:
		對命令行進行處理
		根據信息進行初始化
		下面的if和elif中代碼 測試sqlmap能否能正常運行如果沒問題就進入start()執行sql注入
		'''
        if:           
            pass
        elif:
            pass
        else:
            pass
            start()
            pass
	except:# 長達300行的自定義錯誤處理
        pass
    finally:# 收尾工作
        pass

if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        pass
    except SystemExit:
        raise
    except:
        traceback.print_exc()
    finally:   # 根據線程數設定不同的退出方式
        if threading.active_count() > 1:
            os._exit(getattr(os, "_exitcode", 0))
        else:
            sys.exit(getattr(os, "_exitcode", 0))
else:
    __import__("lib.controller.controller")

dirtyPatches函數

函數作用

  • 對http.client進行參數的修改,以及針對python3相應方法的重新設置
  • 對universaldetector檢測編碼方式的調整
  • 針對Windows操作系統上添加對inet_pton()
  • PLACE.CUSTOM_POST調整
def dirtyPatches():
    """
    在thirdparty\six\init.py中有這樣一行 MovedModule("http_client", "httplib", "http.client"),
    six是Python2和3的兼容性庫。這個項目旨在支持可同時運行在Python2和3上的代碼庫
    如果是python3 _http_client實際就是http.client
    """
    # 可以接收很長的響應頭結果行 在Python\Lib\http\client.py中_MAXLINE=65536
    _http_client._MAXLINE = 1 * 1024 * 1024

    if six.PY3:  # 如果是python3就執行這部分代碼
        '''
            hasattr 返回對象是否具有具有給定名稱的屬性
            如果_http_client.HTTPConnection沒有__send_output(python3中沒有)
            就新建一個並且函數引用,現在執行__send_output函數等同於_send_output
        '''
        if not hasattr(_http_client.HTTPConnection, "__send_output"):
            _http_client.HTTPConnection.__send_output = _http_client.HTTPConnection._send_output

        def _send_output(self, *args, **kwargs):
            '''
            conf是AttribDict類(在lib/core/datatype.py中)的對象
            此類定義了字典,並添加了將成員作為屬性訪問的功能。因為AttribDict繼承了python的dict類重寫了一部分功能
            產生的對象就可以理解為字典
            '''
            if conf.get("chunked") and "encode_chunked" in kwargs:
                kwargs["encode_chunked"] = False
            self.__send_output(*args, **kwargs)

        # 理解為將_send_output函數內容更新
        _http_client.HTTPConnection._send_output = _send_output

        # 現在xx.__send_output的內容為原xx._send_output
        # 現在xx._send_output=自定義函數的內容
        
    if IS_WIN:
        # 針對Windows操作系統上添加對inet_pton()的支持處理ipv4,將ip地址192.168.1.1轉換成二進制的ip地址
        from thirdparty.wininetpton import win_inet_pton

    # 關於編碼的配置
    codecs.register(lambda name: codecs.lookup("utf-8") if name == "cp65001" else None)

    # 與上面_send_output操作流程類似
    if hasattr(_http_client, "LineAndFileWrapper"):
        def _(self, *args):
            return self._readline()

        _http_client.LineAndFileWrapper._readline = _http_client.LineAndFileWrapper.readline
        _http_client.LineAndFileWrapper.readline = _

    # 原值為0.2 universaldetector是Mozilla公司提供的檢測編碼方式的工具
    thirdparty.chardet.universaldetector.MINIMUM_THRESHOLD = 0.90

    # 從命令行中匹配對應值 如果匹配到並且值不等於"POST"進行替換操作
    match = re.search(r" --method[= ](\w+)", " ".join(sys.argv))
    if match and match.group(1).upper() != PLACE.POST:
        PLACE.CUSTOM_POST = PLACE.CUSTOM_POST.replace("POST", "%s (body)" % match.group(1))

    try:
        os.urandom(1)  # 返回包含適合加密使用的隨機字節的字節對象(b'\x03')
    except NotImplementedError:
        if six.PY3:
            os.urandom = lambda size: bytes(random.randint(0, 255) for _ in range(size))
        else:
            os.urandom = lambda size: "".join(chr(random.randint(0, 255)) for _ in xrange(size))

resolveCrossReferences函數

下面全部都是函數的替換,等號右側isDigit、readInput等都是函數。

def resolveCrossReferences():
    lib.core.threads.isDigit = isDigit
    lib.core.threads.readInput = readInput
    lib.core.common.getPageTemplate = getPageTemplate
    lib.core.convert.filterNone = filterNone
    lib.core.convert.isListLike = isListLike
    lib.core.convert.shellExec = shellExec
    lib.core.convert.singleTimeWarnMessage = singleTimeWarnMessage
    lib.core.option._pympTempLeakPatch = pympTempLeakPatch
    lib.request.connect.setHTTPHandlers = _setHTTPHandlers
    lib.utils.search.setHTTPHandlers = _setHTTPHandlers
    lib.controller.checks.setVerbosity = setVerbosity
    lib.utils.sqlalchemy.getSafeExString = getSafeExString
    thirdparty.ansistrm.ansistrm.stdoutEncode = stdoutEncode

checkEnvironment函數

函數作用:

  • 檢測目錄是否正常
  • 檢測sqlmap版本是否在1.0以上
  • 將對應的特殊的字典類型變量放到全局中
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
        
    # 檢測sqlmap版本 如果過低提示更新版本 並退出
    if LooseVersion(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

    if "sqlmap.sqlmap" in sys.modules:
        for _ in ("cmdLineOptions", "conf", "kb"):
            # 將系統路徑lib.core.data中的"cmdLineOptions", "conf", "kb"變為同名的全局變量,這三個是AttribDict(dict)的對象。
            globals()[_] = getattr(sys.modules["lib.core.data"], _)

        for _ in (
                "SqlmapBaseException", "SqlmapShellQuitException", "SqlmapSilentQuitException",
                "SqlmapUserQuitException"):
            globals()[_] = getattr(sys.modules["lib.core.exception"], _)

通過讀代碼發現sqlmap花費了大量的代碼在python2的基礎上進行修補😶😶😶

start函數

@stackedmethod
def start():
    '''
    	這些if並不涉及核心的檢測代碼所以忽略掉
    '''
	if xxx:
		pass
	if xxx:
		pass
	if xxx:
		pass
	for targetUrl, targetMethod, targetData, targetCookie, targetHeaders in kb.targets:
        # 核心代碼 核心代碼 核心代碼
	
	if xxx:
		pass
	if xxx:
		pass
	return True

核心代碼很復雜需要花一些時間 在后續的隨筆中再進行分析


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM