SQLMAP的前世今生Part2 資料庫指紋識別

wyzsk發表於2020-08-19
作者: 獵豹科學院 · 2015/11/24 19:03

0x00 前言


談到SQL隱碼攻擊,那麼第一時間就會想到神器SQLMAP,SQLMap是一款用來檢測與利用的SQL隱碼攻擊開源工具。那麼SQLMap在掃描SQL的邏輯到底是怎樣實現的呢,接下來就探討下SQLMap的掃描邏輯,透過了解SQLMap的掃描邏輯打造一款屬於自己的SQL掃描工具。

0x01 SQLMAP的準備工作


SQLMAP在進行掃描之前會有一些其他的功能去確定當前的目標的一些有用的資訊,如防火牆的檢測,當檢測到有防火牆之後,進行SQL檢測時的判斷依據也會有所調整,如bool型別的盲注的時候,而其中heuristicCheckSqlInjection這一函式既會影響到接下來所要使用什麼樣的Payload進行測試,heuristicCheckSqlInjection翻譯過來的意思是啟發式SQL隱碼攻擊測試,那麼到底什麼是啟發式,具體作用到底是什麼呢,在我們經常使用SQLMAP的時候,有可能會出現以下的提示。

p1

上面提示我們當前的目標資料庫版本好像是Oracle,而這上面的提示的依據就是根據這一個啟發式SQL隱碼攻擊測試也就是本文要介紹的heuristicCheckSqlInjection來決定的。SQLMAP中有許多的Payload,足以有幾百條,那麼如果全部Payload都測試一遍的話,無疑是一件很浪費時間的事情,除非Payload中的risk,clause,where欄位中加以過濾,還會以這一個根據資料庫的指紋來選擇所要測試的Payload。

heuristicCheckSqlInjection的主要作用可以分為以下幾點:

  1. 資料庫版本的識別。
  2. 絕對路徑獲取。
  3. XSS的測試

0x02 資料庫版本的識別


#!python
# Alphabet used for heuristic checks
HEURISTIC_CHECK_ALPHABET = ('"', '\'', ')', '(', ',', '.')
...
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)
...

首先會從HEURISTIC_CHECK_ALPHABET中隨機抽取10個字元出現構造Payload,當然裡面的都不是些普通的字元,而且些特殊字元,當我們進行SQL隱碼攻擊測試的時候會很習慣的在引數後面加個分號啊什麼的,又或者是其他一些特殊的字元,出現運氣好的話有可能會暴出資料的相關錯誤資訊,而那個時候我們就可以根據所暴出的相關錯誤資訊去猜測當前目標的資料庫是什麼。

實際找個網站測試,打下碼,保護下。

http://***.***.***/datalist/default.aspx/article?category_id=1051

那麼經過while '\'' not in randStr:後生成了隨機的字元,然後就是發包檢測返回的資料了。

如下圖:

p2

其實熟悉SQL隱碼攻擊的人也知道這是一個Oracle的一個錯誤資訊,那麼接下來看看SQLMAP到底是怎樣去判斷的。

位於./lib/request/connect.py中的getPage函式,大約在598行。

#!python
def getPage(**kwargs):
    ...
    processResponse(page, responseHeaders)
    ...

其中processResponse會呼叫到./lib/parse/html.py中的htmlParser函式,這一個函式就是根據不同的資料庫指紋去識別當前的資料庫究竟是什麼。

#!python
def htmlParser(page):
    """
    This function calls a class that parses the input HTML page to
    fingerprint the back-end database management system
    """
    xmlfile = paths.ERRORS_XML
    handler = HTMLHandler(page)
    parseXmlFile(xmlfile, handler)
    if handler.dbms and handler.dbms not in kb.htmlFp:
        kb.lastParserStatus = handler.dbms
        kb.htmlFp.append(handler.dbms)
    else:
        kb.lastParserStatus = None
    # generic SQL warning/error messages
    if re.search(r"SQL (warning|error|syntax)", page, re.I):
        handler._markAsErrorPage()
    return handler.dbms

最終實現的的其實是HTMLHandler這個類,而paths.ERRORS_XML這一變數的就是SQLMAP用來識別的指紋配置檔案路徑,位置在於./xml/errors.xml中。

#!html
<!-- Oracle -->
<dbms value="Oracle">
    <error regexp="\bORA-[0-9][0-9][0-9][0-9]"/>
    <error regexp="Oracle error"/>
    <error regexp="Oracle.*Driver"/>
    <error regexp="Warning.*\Woci_.*"/>
    <error regexp="Warning.*\Wora_.*"/>
</dbms>

這一配置檔案的比較簡單,其實也就是一些對應資料庫的正則。SQLMAP在解析errors.xml的時候,然後根據regexp中的正則去匹配當前的頁面資訊然後去確定當前的資料庫。

#!python
class HTMLHandler(ContentHandler):
    """
    This class defines methods to parse the input HTML page to
    fingerprint the back-end database management system
    """
    def __init__(self, page):
        ContentHandler.__init__(self)
        self._dbms = None
        self._page = page
        self.dbms = None
    def _markAsErrorPage(self):
        threadData = getCurrentThreadData()
        threadData.lastErrorPage = (threadData.lastRequestUID, self._page)
    def startElement(self, name, attrs):
        if name == "dbms":
            self._dbms = attrs.get("value")
        elif name == "error":
            if re.search(attrs.get("regexp"), self._page, re.I):
                self.dbms = self._dbms
                self._markAsErrorPage()

可以發現當前返回的頁面資訊命中了<error regexp="\bORA-[0-9][0-9][0-9][0-9]"/>這一條正規

p3

到此SQLMap就可以確定資料的版本了,從而選擇對應的測試Payload,減少SQLMAP的掃描時間。

0x03 絕對路徑獲取與XSS檢測


相比指紋識別,獲取絕對路徑的功能模組相對簡單,利用正則匹配尋找出絕對路徑。

#!python
def parseFilePaths(page):
    """
    Detects (possible) absolute system paths inside the provided page content
    """
    if page:
        for regex in (r" in <b>(?P<result>.*?)</b> on line", r"(?:>|\s)(?P<result>[A-Za-z]:[\\/][\w.\\/]*)", r"(?:>|\s)(?P<result>/\w[/\w.]+)"):
            for match in re.finditer(regex, page):
                absFilePath = match.group("result").strip()
                page = page.replace(absFilePath, "")
                if isWindowsDriveLetterPath(absFilePath):
                    absFilePath = posixToNtSlashes(absFilePath)
                if absFilePath not in kb.absFilePaths:
                    kb.absFilePaths.add(absFilePath)

而XSS的檢測程式碼位於889行中:

#!python
# String used for dummy XSS check of a tested parameter value
DUMMY_XSS_CHECK_APPENDIX = "<'\">"
    ...
    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)
    ...

最後根據輸入的字元是否留著頁面上,如果存在就提示有可能擁有XSS漏洞。

0x04 總結


至此heuristicCheckSqlInjection的功能也介紹的差不多了,透過具體瞭解SQLMAP的一些掃描規則又或者是思路,可以讓我們根據具體的情況去配置SQLMAP又或者編寫自己的SQL Fuzz系統,其中可以透過編輯errors.xml這一指資料紋配置來增強SQLMAP的嗅探能力,從而打造更強大的神器了。

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章