mirror of
				https://github.com/sqlmapproject/sqlmap.git
				synced 2025-10-31 16:07:55 +03:00 
			
		
		
		
	Major bug fix to make it work properly with MSSQL custom limited (SELECT
TOP ...) queries with both inferential blind and Full UNION query injection
This commit is contained in:
		
							parent
							
								
									2cc3bb2f6a
								
							
						
					
					
						commit
						9c42a883be
					
				|  | @ -285,7 +285,7 @@ class Agent: | ||||||
|         if query.startswith("SELECT ") and "(SELECT " in query: |         if query.startswith("SELECT ") and "(SELECT " in query: | ||||||
|             fieldsSelectFrom = None |             fieldsSelectFrom = None | ||||||
| 
 | 
 | ||||||
|         return fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsToCastList, fieldsToCastStr |         return fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsSelectTop, fieldsToCastList, fieldsToCastStr | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     def concatQuery(self, query): |     def concatQuery(self, query): | ||||||
|  | @ -317,7 +317,7 @@ class Agent: | ||||||
|         concatQuery = "" |         concatQuery = "" | ||||||
|         query       = query.replace(", ", ",") |         query       = query.replace(", ", ",") | ||||||
| 
 | 
 | ||||||
|         fieldsSelectFrom, fieldsSelect, fieldsNoSelect, _, fieldsToCastStr = self.getFields(query) |         fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsSelectTop, _, fieldsToCastStr = self.getFields(query) | ||||||
|         castedFields = self.nullCastConcatFields(fieldsToCastStr) |         castedFields = self.nullCastConcatFields(fieldsToCastStr) | ||||||
|         concatQuery  = query.replace(fieldsToCastStr, castedFields, 1) |         concatQuery  = query.replace(fieldsToCastStr, castedFields, 1) | ||||||
| 
 | 
 | ||||||
|  | @ -348,7 +348,11 @@ class Agent: | ||||||
|                     concatQuery += " FROM DUAL" |                     concatQuery += " FROM DUAL" | ||||||
| 
 | 
 | ||||||
|         elif kb.dbms == "Microsoft SQL Server": |         elif kb.dbms == "Microsoft SQL Server": | ||||||
|             if fieldsSelectFrom: |             if fieldsSelectTop: | ||||||
|  |                 topNum = re.search("\ASELECT\s+TOP\s+([\d]+)\s+", concatQuery, re.I).group(1) | ||||||
|  |                 concatQuery = concatQuery.replace("SELECT TOP %s " % topNum, "TOP %s '%s'+" % (topNum, temp.start), 1) | ||||||
|  |                 concatQuery = concatQuery.replace(" FROM ", "+'%s' FROM " % temp.stop, 1) | ||||||
|  |             elif fieldsSelectFrom: | ||||||
|                 concatQuery = concatQuery.replace("SELECT ", "'%s'+" % temp.start, 1) |                 concatQuery = concatQuery.replace("SELECT ", "'%s'+" % temp.start, 1) | ||||||
|                 concatQuery = concatQuery.replace(" FROM ", "+'%s' FROM " % temp.stop, 1) |                 concatQuery = concatQuery.replace(" FROM ", "+'%s' FROM " % temp.stop, 1) | ||||||
|             elif fieldsSelect: |             elif fieldsSelect: | ||||||
|  | @ -393,6 +397,11 @@ class Agent: | ||||||
| 
 | 
 | ||||||
|         inbandQuery = self.prefixQuery(" UNION ALL SELECT ") |         inbandQuery = self.prefixQuery(" UNION ALL SELECT ") | ||||||
| 
 | 
 | ||||||
|  |         if query.startswith("TOP"): | ||||||
|  |             topNum       = re.search("\ATOP\s+([\d]+)\s+", query, re.I).group(1) | ||||||
|  |             query        = query[len("TOP %s " % topNum):] | ||||||
|  |             inbandQuery += "TOP %s " % topNum | ||||||
|  | 
 | ||||||
|         if not exprPosition: |         if not exprPosition: | ||||||
|             exprPosition = kb.unionPosition |             exprPosition = kb.unionPosition | ||||||
| 
 | 
 | ||||||
|  | @ -472,10 +481,17 @@ class Agent: | ||||||
|             if " ORDER BY " in limitedQuery: |             if " ORDER BY " in limitedQuery: | ||||||
|                 limitedQuery = limitedQuery[:limitedQuery.index(" ORDER BY ")] |                 limitedQuery = limitedQuery[:limitedQuery.index(" ORDER BY ")] | ||||||
| 
 | 
 | ||||||
|             limitedQuery  = limitedQuery.replace("SELECT ", (limitStr % 1), 1) |             if not limitedQuery.startswith("SELECT TOP "): | ||||||
|             limitedQuery  = "%s WHERE %s " % (limitedQuery, field) |                 limitedQuery  = limitedQuery.replace("SELECT ", (limitStr % 1), 1) | ||||||
|             limitedQuery += "NOT IN (%s" % (limitStr % num) |                 limitedQuery  = "%s WHERE %s " % (limitedQuery, field) | ||||||
|             limitedQuery += "%s %s)" % (field, fromFrom) |                 limitedQuery += "NOT IN (%s" % (limitStr % num) | ||||||
|  |                 limitedQuery += "%s %s)" % (field, fromFrom) | ||||||
|  |             else: | ||||||
|  |                 topNums         = re.search("\ASELECT\s+TOP\s+([\d]+)\s+.+?\s+FROM\s+.+?\s+WHERE\s+.+?\s+NOT\s+IN\s+\(SELECT\s+TOP\s+([\d]+)\s+", limitedQuery, re.I).groups() | ||||||
|  |                 quantityTopNums = topNums[0] | ||||||
|  |                 limitedQuery    = limitedQuery.replace("SELECT TOP %s" % quantityTopNums, "SELECT TOP 1", 1) | ||||||
|  |                 startTopNums    = topNums[1] | ||||||
|  |                 limitedQuery    = limitedQuery.replace(" (SELECT TOP %s" % startTopNums, " (SELECT TOP %d" % num) | ||||||
| 
 | 
 | ||||||
|         return limitedQuery |         return limitedQuery | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -30,7 +30,7 @@ import sys | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # sqlmap version and site | # sqlmap version and site | ||||||
| VERSION            = "0.6.4-rc3" | VERSION            = "0.6.4-rc4" | ||||||
| VERSION_STRING     = "sqlmap/%s" % VERSION | VERSION_STRING     = "sqlmap/%s" % VERSION | ||||||
| SITE               = "http://sqlmap.sourceforge.net" | SITE               = "http://sqlmap.sourceforge.net" | ||||||
| 
 | 
 | ||||||
|  | @ -73,6 +73,7 @@ MATCH_RATIO       = 0.9 | ||||||
| SQL_STATEMENTS    = { | SQL_STATEMENTS    = { | ||||||
|                       "SQL SELECT statement":  ( |                       "SQL SELECT statement":  ( | ||||||
|                              "select ", |                              "select ", | ||||||
|  |                              "select top ", | ||||||
|                              " from ", |                              " from ", | ||||||
|                              " from dual", |                              " from dual", | ||||||
|                              " where ", |                              " where ", | ||||||
|  |  | ||||||
|  | @ -81,7 +81,7 @@ def __goInferenceFields(expression, expressionFields, expressionFieldsList, payl | ||||||
|             continue |             continue | ||||||
| 
 | 
 | ||||||
|         if isinstance(num, int): |         if isinstance(num, int): | ||||||
|             origExpr = expression |             origExpr   = expression | ||||||
|             expression = agent.limitQuery(num, expression, field) |             expression = agent.limitQuery(num, expression, field) | ||||||
| 
 | 
 | ||||||
|         if "ROWNUM" in expressionFieldsList: |         if "ROWNUM" in expressionFieldsList: | ||||||
|  | @ -89,7 +89,7 @@ def __goInferenceFields(expression, expressionFields, expressionFieldsList, payl | ||||||
|         else: |         else: | ||||||
|             expressionReplaced = expression |             expressionReplaced = expression | ||||||
| 
 | 
 | ||||||
|         output             = resume(expressionReplaced, payload) |         output = resume(expressionReplaced, payload) | ||||||
| 
 | 
 | ||||||
|         if not output or ( expected == "int" and not output.isdigit() ): |         if not output or ( expected == "int" and not output.isdigit() ): | ||||||
|             if output: |             if output: | ||||||
|  | @ -131,7 +131,7 @@ def __goInferenceProxy(expression, fromUser=False, expected=None): | ||||||
|         return output |         return output | ||||||
| 
 | 
 | ||||||
|     if kb.dbmsDetected: |     if kb.dbmsDetected: | ||||||
|         _, _, _, expressionFieldsList, expressionFields = agent.getFields(expression) |         _, _, _, _, expressionFieldsList, expressionFields = agent.getFields(expression) | ||||||
| 
 | 
 | ||||||
|         if len(expressionFieldsList) > 1: |         if len(expressionFieldsList) > 1: | ||||||
|             infoMsg  = "the SQL query provided has more than a field. " |             infoMsg  = "the SQL query provided has more than a field. " | ||||||
|  | @ -159,7 +159,17 @@ def __goInferenceProxy(expression, fromUser=False, expected=None): | ||||||
|                     stopLimit = limitRegExp.group(int(limitGroupStop)) |                     stopLimit = limitRegExp.group(int(limitGroupStop)) | ||||||
|                     limitCond = int(stopLimit) > 1 |                     limitCond = int(stopLimit) > 1 | ||||||
| 
 | 
 | ||||||
|                 elif kb.dbms in ( "Oracle", "Microsoft SQL Server" ): |                 elif kb.dbms == "Microsoft SQL Server": | ||||||
|  |                     limitGroupStart = queries[kb.dbms].limitgroupstart | ||||||
|  |                     limitGroupStop  = queries[kb.dbms].limitgroupstop | ||||||
|  | 
 | ||||||
|  |                     if limitGroupStart.isdigit(): | ||||||
|  |                         startLimit = int(limitRegExp.group(int(limitGroupStart))) | ||||||
|  | 
 | ||||||
|  |                     stopLimit = limitRegExp.group(int(limitGroupStop)) | ||||||
|  |                     limitCond = int(stopLimit) > 1 | ||||||
|  | 
 | ||||||
|  |                 elif kb.dbms == "Oracle": | ||||||
|                     limitCond = False |                     limitCond = False | ||||||
|             else: |             else: | ||||||
|                 limitCond = True |                 limitCond = True | ||||||
|  | @ -178,6 +188,9 @@ def __goInferenceProxy(expression, fromUser=False, expected=None): | ||||||
|                         untilLimitChar = expression.index(queries[kb.dbms].limitstring) |                         untilLimitChar = expression.index(queries[kb.dbms].limitstring) | ||||||
|                         expression = expression[:untilLimitChar] |                         expression = expression[:untilLimitChar] | ||||||
| 
 | 
 | ||||||
|  |                     elif kb.dbms == "Microsoft SQL Server": | ||||||
|  |                         stopLimit += startLimit | ||||||
|  | 
 | ||||||
|                 if not stopLimit or stopLimit <= 1: |                 if not stopLimit or stopLimit <= 1: | ||||||
|                     if kb.dbms == "Oracle" and expression.endswith("FROM DUAL"): |                     if kb.dbms == "Oracle" and expression.endswith("FROM DUAL"): | ||||||
|                         test = "n" |                         test = "n" | ||||||
|  |  | ||||||
|  | @ -54,12 +54,12 @@ def bisection(payload, expression, length=None): | ||||||
|     finalValue      = "" |     finalValue      = "" | ||||||
| 
 | 
 | ||||||
|     if kb.dbmsDetected: |     if kb.dbmsDetected: | ||||||
|         _, _, _, _, fieldToCastStr = agent.getFields(expression) |         _, _, _, _, _, fieldToCastStr = agent.getFields(expression) | ||||||
|         nulledCastedField          = agent.nullAndCastField(fieldToCastStr) |         nulledCastedField             = agent.nullAndCastField(fieldToCastStr) | ||||||
|         expressionReplaced         = expression.replace(fieldToCastStr, nulledCastedField, 1) |         expressionReplaced            = expression.replace(fieldToCastStr, nulledCastedField, 1) | ||||||
|         expressionUnescaped        = unescaper.unescape(expressionReplaced) |         expressionUnescaped           = unescaper.unescape(expressionReplaced) | ||||||
|     else: |     else: | ||||||
|         expressionUnescaped        = unescaper.unescape(expression) |         expressionUnescaped           = unescaper.unescape(expression) | ||||||
| 
 | 
 | ||||||
|     infoMsg = "query: %s" % expressionUnescaped |     infoMsg = "query: %s" % expressionUnescaped | ||||||
|     logger.info(infoMsg) |     logger.info(infoMsg) | ||||||
|  |  | ||||||
|  | @ -159,7 +159,7 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False): | ||||||
|                 conf.paramNegative = True |                 conf.paramNegative = True | ||||||
| 
 | 
 | ||||||
|     if conf.paramNegative == True and direct == False: |     if conf.paramNegative == True and direct == False: | ||||||
|         _, _, _, expressionFieldsList, expressionFields = agent.getFields(origExpr) |         _, _, _, _, expressionFieldsList, expressionFields = agent.getFields(origExpr) | ||||||
| 
 | 
 | ||||||
|         if len(expressionFieldsList) > 1: |         if len(expressionFieldsList) > 1: | ||||||
|             infoMsg  = "the SQL query provided has more than a field. " |             infoMsg  = "the SQL query provided has more than a field. " | ||||||
|  | @ -187,7 +187,17 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False): | ||||||
|                     stopLimit = limitRegExp.group(int(limitGroupStop)) |                     stopLimit = limitRegExp.group(int(limitGroupStop)) | ||||||
|                     limitCond = int(stopLimit) > 1 |                     limitCond = int(stopLimit) > 1 | ||||||
| 
 | 
 | ||||||
|                 elif kb.dbms in ( "Oracle", "Microsoft SQL Server" ): |                 elif kb.dbms == "Microsoft SQL Server": | ||||||
|  |                     limitGroupStart = queries[kb.dbms].limitgroupstart | ||||||
|  |                     limitGroupStop  = queries[kb.dbms].limitgroupstop | ||||||
|  | 
 | ||||||
|  |                     if limitGroupStart.isdigit(): | ||||||
|  |                         startLimit = int(limitRegExp.group(int(limitGroupStart))) | ||||||
|  | 
 | ||||||
|  |                     stopLimit = limitRegExp.group(int(limitGroupStop)) | ||||||
|  |                     limitCond = int(stopLimit) > 1 | ||||||
|  | 
 | ||||||
|  |                 elif kb.dbms == "Oracle": | ||||||
|                     limitCond = False |                     limitCond = False | ||||||
|             else: |             else: | ||||||
|                 limitCond = True |                 limitCond = True | ||||||
|  | @ -287,7 +297,7 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False): | ||||||
| 
 | 
 | ||||||
|     else: |     else: | ||||||
|         # Forge the inband SQL injection request |         # Forge the inband SQL injection request | ||||||
|         query = agent.forgeInbandQuery(expression) |         query   = agent.forgeInbandQuery(expression) | ||||||
|         payload = agent.payload(newValue=query) |         payload = agent.payload(newValue=query) | ||||||
| 
 | 
 | ||||||
|         infoMsg = "query: %s" % query |         infoMsg = "query: %s" % query | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user