<pre id="vvttv"><mark id="vvttv"><progress id="vvttv"></progress></mark></pre>
    <pre id="vvttv"></pre>

      <p id="vvttv"></p>

          <p id="vvttv"></p>

                <p id="vvttv"></p>

                <pre id="vvttv"><cite id="vvttv"><progress id="vvttv"></progress></cite></pre>

                  <output id="vvttv"><dfn id="vvttv"><th id="vvttv"></th></dfn></output>

                    <p id="vvttv"></p>

                    原文地址:http://drops.wooyun.org/tips/7301

                    0x00 概述


                    1.drops之前的文檔 SQLMAP進階使用介紹過SQLMAP的高級使用方法,網上也有幾篇介紹過SQLMAP源碼的文章曾是土木人,都寫的非常好,建議大家都看一下。
                    2.我準備分幾篇文章詳細的介紹下SQLMAP的源碼,讓想了解的朋友們熟悉一下SQLMAP的原理和一些手工注入的語句,今天先開始第一篇:流程篇。
                    3.之前最好了解SQMAP各個選項的意思,可以參考sqlmap用戶手冊和SQLMAP目錄doc/README.pdf
                    4.內容中如有錯誤或者沒有寫清楚的地方,歡迎指正交流。有部分內容是參考上面介紹的幾篇文章的,在此一并說明,感謝他們。

                    0x01 流程圖

                    enter image description here

                    0x02 調試方法


                    1.我用的IDE是PyCharm。
                    2.在菜單欄Run->Edit Configurations。點擊左側的“+”,選擇Python,Script中選擇sqlmap.py的路徑,Script parameters中填入注入時的命令,如下圖。 enter image description here

                    3.打開sqlmap.py,開始函數是main函數,在main函數處下斷點。 enter image description here

                    4.右鍵Debug 'sqlmap',然后程序就自動跳到我們下斷點的main()函數處,后面可以繼續添加斷點進行調試。如下圖,左邊紅色的代表跳轉到下一個斷點處,上面紅色的表示跳到下一句代碼處

                    enter image description here

                    5.另外,如果要在代碼中加中文注釋,需要在開始處添加以下語句:#coding:utf-8。

                    0x03 流程


                    3.1 初始化

                    我這里用的版本是:1.0-dev-nongit-20150614
                    miin()函數開始73行:

                    #!python
                    paths.SQLMAP_ROOT_PATH = modulePath()
                    setPaths()
                    

                    進入common.py中的setPaths()函數后,就可以看到這個函數是定義SQLMAP路徑和文件的,類似于:

                    #!python
                    paths.SQLMAP_EXTRAS_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "extra")
                    paths.SQLMAP_PROCS_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "procs")
                    paths.SQLMAP_SHELL_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "shell")
                    paths.SQLMAP_TAMPER_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "tamper")
                    paths.SQLMAP_WAF_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "waf")
                    

                    接下來的78行函數initOptions(cmdLineOptions),包含了三個函數,作用如流程圖所示,設置conf,KB,參數. conf會保存用戶輸入的一些參數,比如url,端口
                    kb會保存注入時的一些參數,其中有兩個是比較特殊的kb.chars.start和kb.chars.stop,這兩個是隨機字符串,后面會有介紹。

                    #!python
                    _setConfAttributes()
                    _setKnowledgeBaseAttributes()
                    _mergeOptions(inputOptions, overrideOptions)
                    

                    3.2 start

                    102行的start函數,算是檢測開始的地方.start()函數位于controller.py中。

                    #!python
                    if conf.direct:        
                        initTargetEnv()
                        setupTargetEnv()
                        action()
                        return True
                    

                    首先這四句,意思是,如果你使用-d選項,那么sqlmap就會直接進入action()函數,連接數據庫,語句類似為:

                    #!python
                    python sqlmap.py -d "mysql://admin:[email protected]:3306/testdb" -f --banner --dbs --user
                    
                    
                    #!python
                    if conf.url and not any((conf.forms, conf.crawlDepth)):
                        kb.targets.add((conf.url, conf.method, conf.data, conf.cookie, None))
                    

                    上面代碼會把url,methos,data,cookie加入到kb.targets,這些參數就是我們輸入的

                    enter image description here

                    接下來從274行的for循環中,可以進入檢測環節

                    #!python
                    for targetUrl, targetMethod, targetData, targetCookie, targetHeaders in kb.targets:
                    

                    此循環先初始化一些一些變量,然后判斷之前是否注入過,如果沒有注入過,testSqlInj=True,否則testSqlInj=false。后面會進行判斷是否檢測過。

                    #!python
                    def setupTargetEnv():
                        _createTargetDirs()
                        _setRequestParams()
                        _setHashDB()
                        _resumeHashDBValues()
                        _setResultsFile()
                        _setAuthCred()
                    

                    372行setupTargetEnv()函數中包含了5個函數,這些函數作用是

                    1.創建輸出結果目錄

                    2.解析請求參數

                    3.設置session信息,就是session.sqlite。

                    4.恢復session的數據,繼續掃描。

                    5.存儲掃描結果。

                    6.添加認證信息

                    其中比較重要的就是session.sqlite,這個文件在sqlmap的輸出目錄中,測試的結果都會保存在這個文件里。

                    3.2.1 checkWaf

                    #!python
                    checkWaf()
                    if conf.identifyWaf:
                        identifyWaf()
                    

                    377行checkWaf()是檢測是否有WAF,檢測方法是NMAP的http-waf-detect.nse,比如頁面為index.php?id=1,那現在添加一個隨機變量index.php?id=1&aaa=2,設置paoyload類似為AND 1=1 UNION ALL SELECT 1,2,3,table_name FROM information_schema.tables WHERE 2>1-- ../../../etc/passwd,如果沒有WAF,頁面不會變化,如果有WAF,因為payload中有很多敏感字符,大多數時候頁面都會發生改變。
                    接下來的conf.identifyWaf代表sqlmap的參數--identify-waf,如果指定了此參數,就會進入identifyWaf()函數,主要檢測的waf都在sqlmap的waf目錄下。

                    enter image description here

                    當然檢測的方法都比較簡單,都是查看返回的數據庫包種是否包含了某些特征字符。如:

                    #!python
                    __product__ = "360 Web Application Firewall (360)"
                    
                    def detect(get_page):
                        retval = False
                    
                        for vector in WAF_ATTACK_VECTORS:
                            page, headers, code = get_page(get=vector)
                            retval = re.search(r"wangzhan\.360\.cn", headers.get("X-Powered-By-360wzb", ""), re.I) is not None
                            if retval:
                                break
                    
                        return retval
                    
                    
                    
                    if (len(kb.injections) == 0 or (len(kb.injections) == 1 and kb.injections[0].place is None)) \
                                    and (kb.injection.place is None or kb.injection.parameter is None):
                    

                    回到start函數,385行會判斷是否注入過,如果還沒有測試過參數是否可以注入,則進入if語句中。如果之前測試過,則不會進入此語句。

                    #!python
                    for place in parameters:
                        # Test User-Agent and Referer headers only if
                        # --level >= 3
                        skip = (place == PLACE.USER_AGENT and conf.level < 
                        skip |= (place == PLACE.REFERER and conf.level < 3)
                        # Test Host header only if
                        # --level >= 5
                        skip |= (place == PLACE.HOST and conf.level < 5)
                        # Test Cookie header only if --level >= 2
                        skip |= (place == PLACE.COOKIE and conf.level < 2)
                    

                    這中間sqlmap給了我們一些注釋,可以看到,level>=3時,會測試user-agent,referer,level>=5時,會測試HOST,level>=2時,會測試cookie。當然最終的測試判斷還要在相應的xml中指定,后面會介紹。

                    #!python
                    check = checkDynParam(place, parameter, value)
                    

                    480行的checkDynParam()函數會判斷參數是否是動態的,比如index.php?id=1,通過更改id的值,如果參數是動態的,頁面會不同。

                    3.2.2 heuristicCheckSqlInjection

                    #!python
                    check = heuristicCheckSqlInjection(place, parameter)
                    

                    502行有個heuristicCheckSqlInjection()函數,翻譯過來是啟發性sql注入測試,其實就是先進行一個簡單的測試,設置一個payload,然后解析請求結果。
                    heuristicCheckSqlInjection()在checks.py中,821行開始如下:

                    #!python
                    if conf.prefix or conf.suffix:
                            if conf.prefix:
                                prefix = conf.prefix
                    
                            if conf.suffix:
                                suffix = conf.suffix
                    
                        randStr = ""
                    
                        while '\'' not in randStr:
                            randStr = randomStr(length=10, alphabet=HEURISTIC_CHECK_ALPHABET)   
                    
                        kb.heuristicMode = True
                    
                        payload = "%s%s%s" % (prefix, randStr, suffix)
                        payload = agent.payload(place, parameter, newValue=payload)
                        page, _ = Request.queryPage(payload, place, content=True, raise404=False)
                    
                        kb.heuristicMode = False
                    
                        parseFilePaths(page)
                        result = wasLastResponseDBMSError()
                    

                    首先conf.prefix和conf.suffix代表用戶指定的前綴和后綴;在while '\'' not in randStr中,隨機選擇'"', '\'', ')', '(', ',', '.'中的字符,選10個,并且單引號要在。接下來生成一個payload,類似u'name=PAYLOAD_DELIMITER\__1)."."."\'."__PAYLOAD_DELIMITER'。其中PAYLOAD_DELIMITER\__1和__PAYLOAD_DELIMITER是隨機字符串。請求網頁后,調用parseFilePaths進行解析,查看是否爆出絕對路徑,而wasLastResponseDBMSError是判斷response中是否包含了數據庫的報錯信息。

                    #!python
                    value = "%s%s%s" % (randomStr(), DUMMY_XSS_CHECK_APPENDIX, randomStr())
                    payload = "%s%s%s" % (prefix, "'%s" % value, suffix)
                    payload = agent.payload(place, parameter, newValue=payload)
                    page, _ = Request.queryPage(payload, place, content=True, raise404=False)
                    
                    paramType = conf.method if conf.method not in (None, HTTPMETHOD.GET, HTTPMETHOD.POST) else place
                    
                    if value in (page or ""):       
                        infoMsg = "heuristic (XSS) test shows that %s parameter " % paramType
                        infoMsg += "'%s' might be vulnerable to XSS attacks" % parameter
                        logger.info(infoMsg)
                    
                    kb.heuristicMode = False
                    

                    上面的代碼是從888行開始,DUMMY_XSS_CHECK_APPENDIX = "<'\">",如果輸入的字符串在頁面中返回了,會提示可能存在XSS漏洞。

                    enter image description here

                    接下來,我們回到start函數中,繼續看下面的代碼。

                    #!python
                    if testSqlInj:
                        ......
                        injection = checkSqlInjection(place, parameter, value)
                    

                    在502行判斷testSqlInj,如果為true,就代表之前沒有檢測過,然后就會到checkSqlInjection,checkSqlInjection()才是真正開始測試的函數,傳入的參數是注入方法如GET,參數名,參數值。我們跟進。

                    3.2.3 checkSqlInjection

                    checkSqlInjection()在checks.py中,91行開始

                    #!python
                    paramType = conf.method if conf.method not in (None, HTTPMETHOD.GET, HTTPMETHOD.POST) else place
                    tests = getSortedInjectionTests()
                    

                    paramType是注入的類型,如GET。tests是要測試的列表,如下圖所示,包含了每個測試項的名稱,這些數據都是和/sqlmap/xml/payloads/目錄下每個xml相對應的。

                    enter image description here

                    #!python
                    if conf.dbms is None:
                        if not injection.dbms and PAYLOAD.TECHNIQUE.BOOLEAN in injection.data:
                            if not Backend.getIdentifiedDbms() and kb.heuristicDbms is False:
                                kb.heuristicDbms = heuristicCheckDbms(injection)
                        if kb.reduceTests is None and not conf.testFilter and (intersect(Backend.getErrorParsedDBMSes(), \
                           SUPPORTED_DBMS, True) or kb.heuristicDbms or injection.dbms):
                            msg = "it looks like the back-end DBMS is '%s'. " % (Format.getErrorParsedDBMSes() or kb.heuristicDbms or injection.dbms)
                            msg += "Do you want to skip test payloads specific for other DBMSes? [Y/n]"
                            kb.reduceTests = (Backend.getErrorParsedDBMSes() or [kb.heuristicDbms]) if readInput(msg, default='Y').upper() == 'Y' else []
                    if kb.extendTests is None and not conf.testFilter and (conf.level < 5 or conf.risk < 3) \
                       and (intersect(Backend.getErrorParsedDBMSes(), SUPPORTED_DBMS, True) or \
                       kb.heuristicDbms or injection.dbms):
                        msg = "for the remaining tests, do you want to include all tests "
                        msg += "for '%s' extending provided " % (Format.getErrorParsedDBMSes() or kb.heuristicDbms or injection.dbms)
                        msg += "level (%d)" % conf.level if conf.level < 5 else ""
                        msg += " and " if conf.level < 5 and conf.risk < 3 else ""
                        msg += "risk (%d)" % conf.risk if conf.risk < 3 else ""
                        msg += " values? [Y/n]" if conf.level < 5 and conf.risk < 3 else " value? [Y/n]"
                        kb.extendTests = (Backend.getErrorParsedDBMSes() or [kb.heuristicDbms]) if readInput(msg, default='Y').upper() == 'Y' else []
                    

                    101行開始,這段代碼主要是判斷DBMS類型,首先,如果用戶沒有手工指定dbms,則會根據頁面報錯或者bool類型的測試,找出DBMS類型,找出后,會提示是否跳過測試其他的DBMS。然后,對于測試出來的DBMS,是否用所有的payload來測試。

                    enter image description here

                    140行if stype == PAYLOAD.TECHNIQUE.UNION:會判斷是不是union注入,這個stype就是payload文件夾下面xml文件中的stype,如果是union,就會進入,然后配置列的數量等,今天先介紹流程,union注入以后會介紹。

                    #!python
                    if conf.tech and isinstance(conf.tech, list) and stype not in conf.tech:
                                    debugMsg = "skipping test '%s' because the user " % title
                                    debugMsg += "specified to test only for "
                                    debugMsg += "%s techniques" % " & ".join(map(lambda x: PAYLOAD.SQLINJECTION[x], conf.tech))
                                    logger.debug(debugMsg)
                                    continue
                    

                    177行,就是用戶提供的--technique,共有六個選項BEUSTQ,但是現在很多文檔,包括SQLMAP的官方文檔都只給了BEUST的解釋說明,少個inline_query,相當于查詢語句中再加入一個查詢語句。

                    B: Boolean-based blind SQL injection(布爾型注入)
                    E: Error-based SQL injection(報錯型注入)
                    U: UNION query SQL injection(可聯合查詢注入)
                    S: Stacked queries SQL injection(可多語句查詢注入)
                    T: Time-based blind SQL injection(基于時間延遲注入)
                    Q: inline_query(內聯查詢)
                    

                    接下來,就是生成payload的過程。288行:

                    #!python
                    fstPayload = agent.cleanupPayload(test.request.payload, origValue=value if place not in (PLACE.URI, PLACE.CUSTOM_POST, PLACE.CUSTOM_HEADER) else None)
                    

                    test.request.payload為'AND [RANDNUM]=[RANDNUM]'(相應payload.xml中的request值)。根據此代碼,生成一個隨機字符串,如fstPayload=u'AND 2876=2876'。
                    302行:

                    #!python
                    for boundary in boundaries:
                         injectable = False
                         if boundary.level > conf.level and not (kb.extendTests and intersect(payloadDbms, kb.extendTests, True)):
                                        continue
                    

                    循環遍歷boundaries.xml中的boundary節點,如果boundary的level大于用戶提供的level,則跳過,不檢測。
                    307行:

                    #!python
                    clauseMatch = False
                    for clauseTest in test.clause:     
                         if clauseTest in boundary.clause:   
                             clauseMatch = True
                             break
                    if test.clause != [0] and boundary.clause != [0] and not clauseMatch:
                         continue
                    whereMatch = False
                    for where in test.where:
                         if where in boundary.where:
                             whereMatch = True
                             break
                    if not whereMatch:
                         continue
                    

                    首先,循環遍歷test.clause(payload中的clause值),如果clauseTest在boundary的clause中,則設置clauseMatch = True,代表此條boundary可以使用。 接下來循環匹配where(payload中的where值),如果存在這樣的where,設置whereMatch = True。如果clause和where中的一個沒有匹配成功,都會結束循環,進入下一個payload的測試。

                    #!python
                    prefix = boundary.prefix if boundary.prefix else ""
                    suffix = boundary.suffix if boundary.suffix else ""
                    ptype = boundary.ptype
                    prefix = conf.prefix if conf.prefix is not None else prefix
                    suffix = conf.suffix if conf.suffix is not None else suffix
                    comment = None if conf.suffix is not None else comment
                    

                    上面是設置payload的前綴和后綴,如果用戶設置了,則使用用戶設置的,如果沒有,則使用boundary中的。
                    352行:

                    #!python
                    for where in test.where:
                        if where == PAYLOAD.WHERE.ORIGINAL or conf.prefix:
                            ......
                        elif where == PAYLOAD.WHERE.NEGATIVE:
                            ......
                        elif where == PAYLOAD.WHERE.REPLACE:
                            ......
                    

                    這里的where是payload中的where值,共有三個值,where字段我理解的意思是,以什么樣的方式將我們的payload添加進去。

                    1:表示將我們的payload直接添加在值得后面[此處指的應該是檢測的參數的值] 如我們寫的參數是id=1,設置值為1的話,會出現1后面跟payload

                    2:表示將檢測的參數的值更換為一個整數,然后將payload添加在這個整數的后面。 如我們寫的參數是id=1,設置值為2的話,會出現[數字]后面跟payload

                    3:表示將檢測的參數的值直接更換成我們的payload。 如我們寫的參數是id=1,設置值為3的話,會出現值1直接被替換成了我們的payload。
                    最終在389行:

                    #!python
                    boundPayload = agent.prefixQuery(fstPayload, prefix, where, clause)
                    boundPayload = agent.suffixQuery(boundPayload, comment, suffix, where)
                    reqPayload = agent.payload(place, parameter, newValue=boundPayload, where=where)
                    

                    組合前綴、后綴、payload等,生成請求的reqPayload。
                    這其中有個cleanupPayload()函數,其實就是將一些值進行隨機化。如下圖,例如kb.chars.start,kb.chars.stop,這兩個變量是在基于錯誤的注入時,隨機產生的字符串。

                    enter image description here

                    在398行:

                    #!python
                    for method, check in test.response.items():
                        check = agent.cleanupPayload(check, origValue=value if place not in (PLACE.
                    URI, PLACE.CUSTOM_POST, PLACE.CUSTOM_HEADER) else None)      
                        if method == PAYLOAD.METHOD.COMPARISON:     
                            def genCmpPayload():
                                sndPayload = agent.cleanupPayload(test.response.comparison, 
                    origValue=value if place not in (PLACE.URI, PLACE.CUSTOM_POST, 
                    PLACE.CUSTOM_HEADER) else None)
                                boundPayload = agent.prefixQuery(sndPayload, prefix, where, clause)
                                boundPayload = agent.suffixQuery(boundPayload, comment, suffix, 
                    where)
                                cmpPayload = agent.payload(place, parameter, 
                    newValue=boundPayload, where=where)
                                return cmpPayload
                            kb.matchRatio = None
                            kb.negativeLogic = (where == PAYLOAD.WHERE.NEGATIVE)
                            Request.queryPage(genCmpPayload(), place, raise404=False)
                            falsePage = threadData.lastComparisonPage or ""     
                            trueResult = Request.queryPage(reqPayload, place, raise404=False)
                            truePage = threadData.lastComparisonPage or ""      
                            if trueResult:
                                falseResult = Request.queryPage(genCmpPayload(), place, 
                    raise404=False)
                                if not falseResult:
                                    infoMsg = "%s parameter '%s' seems to be '%s' injectable " % (
                    paramType, parameter, title)
                                    logger.info(infoMsg)
                                    injectable = True
                            if not injectable and not any((conf.string, conf.notString, conf.
                    regexp)) and kb.pageStable:
                                trueSet = set(extractTextTagContent(truePage))
                                falseSet = set(extractTextTagContent(falsePage))
                                candidates = filter(None, (_.strip() if _.strip() in (kb.
                    pageTemplate or "") and _.strip() not in falsePage and _.strip() 
                    not in threadData.lastComparisonHeaders else None for _ in (
                    trueSet - falseSet)))
                                if candidates:
                                    conf.string = candidates[0]
                                    infoMsg = "%s parameter '%s' seems to be '%s' injectable (with 
                    --string=\"%s\")" % (paramType, parameter, title, repr(conf.
                    string).lstrip('u').strip("'"))
                                    logger.info(infoMsg)
                                    injectable = True
                        elif method == PAYLOAD.METHOD.GREP:
                            try:
                                page, headers = Request.queryPage(reqPayload, place, content=True, 
                    raise404=False)
                                output = extractRegexResult(check, page, re.DOTALL | re.
                    IGNORECASE) \
                                        or extractRegexResult(check, listToStrValue( \
                                        [headers[key] for key in headers.keys() if key.lower() != 
                    URI_HTTP_HEADER.lower()] \
                                        if headers else None), re.DOTALL | re.IGNORECASE) \
                                        or extractRegexResult(check, threadData.lastRedirectMsg[1] 
                    \
                                        if threadData.lastRedirectMsg and threadData.
                    lastRedirectMsg[0] == \
                                        threadData.lastRequestUID else None, re.DOTALL | re.
                    IGNORECASE)
                                if output:
                                    result = output == "1"
                                    if result:
                                        infoMsg = "%s parameter '%s' is '%s' injectable " % (
                    paramType, parameter, title)
                                        logger.info(infoMsg)
                                        injectable = True
                            except SqlmapConnectionException, msg:
                                debugMsg = "problem occurred most likely because the "
                                debugMsg += "server hasn't recovered as expected from the "
                                debugMsg += "error-based payload used ('%s')" % msg
                                logger.debug(debugMsg)
                        elif method == PAYLOAD.METHOD.TIME:
                            trueResult = Request.queryPage(reqPayload, place, 
                    timeBasedCompare=True, raise404=False)
                            if trueResult:
                                # Confirm test's results
                                trueResult = Request.queryPage(reqPayload, place, 
                    timeBasedCompare=True, raise404=False)
                                if trueResult:
                                    infoMsg = "%s parameter '%s' seems to be '%s' injectable " % (
                    paramType, parameter, title)
                                    logger.info(infoMsg)
                                    injectable = True
                        elif method == PAYLOAD.METHOD.UNION:
                            configUnion(test.request.char, test.request.columns)
                            if not Backend.getIdentifiedDbms():
                                if kb.heuristicDbms is None:
                                    warnMsg = "using unescaped version of the test "
                                    warnMsg += "because of zero knowledge of the "
                                    warnMsg += "back-end DBMS. You can try to "
                                    warnMsg += "explicitly set it using option '--dbms'"
                                    singleTimeWarnMessage(warnMsg)
                                else:
                                    Backend.forceDbms(kb.heuristicDbms)
                            if unionExtended:
                                infoMsg = "automatically extending ranges for UNION "
                                infoMsg += "query injection technique tests as "
                                infoMsg += "there is at least one other (potential) "
                                infoMsg += "technique found"
                                singleTimeLogMessage(infoMsg)
                            reqPayload, vector = unionTest(comment, place, parameter, value, 
                    prefix, suffix)
                            if isinstance(reqPayload, basestring):
                                infoMsg = "%s parameter '%s' is '%s' injectable" % (paramType, 
                    parameter, title)
                                logger.info(infoMsg)
                                injectable = True
                                # Overwrite 'where' because it can be set
                                # by unionTest() directly
                                where = vector[6]
                        kb.previousMethod = method
                    

                    上面這部分代碼非常多,通過for循環遍歷payload中的標簽,遍歷的結果類似于

                    enter image description here

                    所以,上面的代碼可以分為:

                    1.method為PAYLOAD.METHOD.COMPARISON:bool類型盲注 2.method為PAYLOAD.METHOD.GREP:基于錯誤的sql注入 3.mehtod為PAYLOAD.METHOD.TIME:基于時間的盲注 4.method為PAYLOAD.METHOD.UNION:union聯合查詢

                    請注意,上面這四種方法,和之前說的六種注入方法不是一個概念,這里的是payload中的response代碼,而注入用的是request代碼。通過比較request的結果和response的結果,確定是否可以注入。以后的文章會介紹怎么比較的。。
                    checkSqlInjectiond的關鍵部分就到這里了,后面就是把注入的數據保存起來。馬上會介紹讀取的時候。

                    3.2.4 Payload生成條件

                    前面具體介紹了Payload的生成方法,這里再總結一下條件:

                    1.sqlmap會實現讀取payloads文件夾下xml文件中的每個test元素,然后循環遍歷。

                    2.此時還會遍歷boundaries.xml文件。

                    3.當且僅當某個boundary元素的where節點的值包含test元素where節點的值,clause節點的值包含test元素的clause節點的值,該boundary才能和當前的test匹配,從而進一步生成payload。

                    4.where字段有三個值1:表示將我們的payload直接添加在值得后面[此處指的應該是檢測的參數的值] 如我們寫的參數是id=1,設置值為1的話,會出現1后面跟payload 2:表示將檢測的參數的值更換為一個整數,然后將payload添加在這個整數的后面。 如我們寫的參數是id=1,設置值為2的話,會出現[數字]后面跟payload 3:表示將檢測的參數的值直接更換成我們的payload。 如我們寫的參數是id=1,設置值為3的話,會出現值1直接被替換成了我們的payload

                    5.最終的payload = url參數 + boundary.prefix+test.payload+boundary.suffix

                    3.2.5 Action

                    在start()的617行是action()函數,位于Action.py中,此函數是判斷用戶提供的參數,然后提供相應的函數。

                    #!python
                    if conf.getDbs:
                        conf.dumper.dbs(conf.dbmsHandler.getDbs())
                    if conf.getTables:
                        conf.dumper.dbTables(conf.dbmsHandler.getTables())
                    if conf.commonTables:
                        conf.dumper.dbTables(tableExists(paths.COMMON_TABLES))
                    

                    3.2.6 HashDB

                    sqlmap注入的結果會保存在輸出目錄的session.sqlite文件匯總,此文件是sqlite數據庫,可以使用SQLiteManager打開。
                    回到controller.py中的start函數。第602行

                    #!python
                    _saveToResultsFile()
                    _saveToHashDB()     
                    _showInjections()   
                    _selectInjection()  
                    

                    這四個函數的作用就是保存結果保存結果、保存session、顯示注入結果,包括類型,payload等。
                    前面介紹過會判斷testSqlInj的值,如果為True,代表沒有測試過,會進入checkSqlInjection()函數,如果測試過,那么testSqlInj為false,就會跳過checkSqlInjection()。
                    比如我們選擇--current-db時,通過action()進入到conf.dumper.currentDb(conf.dbmsHandler.getCurrentDb())。進入到databases.py的getCurrentDb中。

                    #!python
                    query = queries[Backend.getIdentifiedDbms()].current_db.query
                    

                    這是獲取相應的命令,比如mysql的命令是database().一直跟蹤函數到use.py的346行

                    #!python
                    if not value and not abortedFlag:
                        output = _oneShotUnionUse(expression, unpack)
                        value = parseUnionPage(output)
                    

                    _onehotUninoUse就是讀取session文件,獲取已經注入過的數據,如果session中沒有,代表沒有請求過,則重新請求獲取數據。output此時是獲取的網頁的源碼。

                    #!python
                    retVal = hashDBRetrieve("%s%s" % (conf.hexConvert, expression), checkConf=True)
                    

                    _onehotUninoUse的第一行,就是從session中獲取數據,跟蹤進hashdb.py的regrieve函數

                    #!python
                    def hashKey(key):
                        key = key.encode(UNICODE_ENCODING) if isinstance(key, unicode) else repr(key)
                        retVal = int(hashlib.md5(key).hexdigest()[:12], 16)     #注釋:hash的算法,對應數據庫中的id。md5后,轉換為10進制,就是session中的id
                        return retVal
                    def retrieve(self, key, unserialize=False):
                        retVal = None
                        if key and (self._write_cache or os.path.isfile(self.filepath)):
                            hash_ = HashDB.hashKey(key)
                            retVal = self._write_cache.get(hash_)
                            if not retVal:      
                                while True:
                                    try:
                                        for row in self.cursor.execute("SELECT value FROM storage WHERE id=?", (hash_,)):
                                            retVal = row[0]
                                    except sqlite3.OperationalError, ex:
                                        if not "locked" in ex.message:
                                            raise
                                    except sqlite3.DatabaseError, ex:
                                        errMsg = "error occurred while accessing session file '%s' ('%s'). " % (self.filepath, ex)
                                        errMsg += "If the problem persists please rerun with `--flush-session`"
                                        raise SqlmapDataException, errMsg
                                    else:
                                        break
                        return retVal if not unserialize else unserializeObject(retVal)
                    

                    通過HashDB.hashKey()計算id,然后到session.sqlite中找記錄,那么key是怎么生成的呢?
                    在common.py中有個hashDBRetrieve(),

                    #!python
                    def hashDBRetrieve(key, unserialize=False, checkConf=False):
                        _ = "%s%s%s" % (conf.url or "%s%s" % (conf.hostname, conf.port), key, HASHDB_MILESTONE_VALUE)
                        retVal = conf.hashDB.retrieve(_, unserialize) if kb.resumeValues and not (checkConf and any((conf.flushSession, conf.freshQueries))) else None
                        if not kb.inferenceMode and not kb.fileReadMode and any(_ in (retVal or "") for _ in (PARTIAL_VALUE_MARKER, PARTIAL_HEX_VALUE_MARKER)):
                            retVal = None
                        return retVal
                    

                    此函數用于生成hash的key,生成方法為url+'None'+命令+HASHDB_MILESTONE_VALUE,比如u'http://127.0.0.1:80/biweb/archives/detail.phpNoneDATABASE()JHjrBugdDA'。此key經過int(hashlib.md5(key).hexdigest()[:12], 16),就是對應session中的id

                    enter image description here

                    最終在session.sqlite中根據id,就能夠找到記錄。

                    enter image description here

                    如上圖,獲取到的記錄其實就是一個網頁的源代碼,另外可以看到current-db的前后有幾個字符串,這個字符串就是kb.chars.start和kb.chars.stop
                    回到_oneShotUnionUse中,如果session中沒有記錄,則會重新進行請求,獲取數據

                    #!python
                    vector = kb.injection.data[PAYLOAD.TECHNIQUE.UNION].vector
                            kb.unionDuplicates = vector[7]
                            kb.forcePartialUnion = vector[8]
                            query = agent.forgeUnionQuery(injExpression, vector[0], vector[1], vector[2], vector[3], vector[4], vector[5], vector[6], None, limited)    
                            where = PAYLOAD.WHERE.NEGATIVE if conf.limitStart or conf.limitStop else vector[6]
                            payload = agent.payload(newValue=query, where=where)
                    

                    最終的值通過解析session中的記錄value = parseUnionPage(output),找到kb.chars.start和kb.chars.stop中間的值,就是結果。

                    0x04 結束


                    還有很多東西沒有寫出來,希望后面的幾篇文章能夠寫好。花了好久的時間,調試、碼字,不知道又沒有人能看到最后。。

                      <pre id="vvttv"><mark id="vvttv"><progress id="vvttv"></progress></mark></pre>
                      <pre id="vvttv"></pre>

                        <p id="vvttv"></p>

                            <p id="vvttv"></p>

                                  <p id="vvttv"></p>

                                  <pre id="vvttv"><cite id="vvttv"><progress id="vvttv"></progress></cite></pre>

                                    <output id="vvttv"><dfn id="vvttv"><th id="vvttv"></th></dfn></output>

                                      <p id="vvttv"></p>

                                      这里只有精品视频