@@ -1289,6 +1289,27 @@ def checkDynamicContent(firstPage, secondPage):
12891289 count += 1
12901290
12911291 if count > conf .retries :
1292+ # Last resort before the (lossy) '--text-only' fallback: if the page is byte-unstable
1293+ # but STRUCTURALLY stable - an identical, non-empty tag/class/id skeleton across
1294+ # requests - base the comparison on that value-free structure instead. Dynamic text
1295+ # (e.g. per-render result rows) then no longer masks an injection whose signal is
1296+ # structural (the HTML counterpart of the structure-aware JSON comparison). Content
1297+ # with no usable structure (empty skeleton, e.g. random/binary bodies) falls through
1298+ # to '--text-only' as before.
1299+ skeleton = extractStructuralTokens (firstPage )
1300+ if skeleton and skeleton == extractStructuralTokens (secondPage ):
1301+ kb .pageStructurallyStable = True
1302+
1303+ if kb .nullConnection :
1304+ debugMsg = "turning off NULL connection support because of structural page comparison"
1305+ logger .debug (debugMsg )
1306+ kb .nullConnection = None
1307+
1308+ infoMsg = "target URL content is not byte-stable but structurally stable; sqlmap "
1309+ infoMsg += "will base the page comparison on the page structure"
1310+ logger .info (infoMsg )
1311+ return
1312+
12921313 warnMsg = "target URL content appears to be too dynamic. "
12931314 warnMsg += "Switching to '--text-only' "
12941315 logger .warning (warnMsg )
@@ -1394,26 +1415,7 @@ def checkStability():
13941415 raise SqlmapNoneDataException (errMsg )
13951416
13961417 else :
1397- # Before engaging the (lossy) dynamic-content removal / '--text-only' escalation, check
1398- # whether the page is structurally stable (identical tag/class/id skeleton across the two
1399- # requests) despite differing text. If so, base the comparison on that value-free structure
1400- # so that dynamic content (e.g. per-render result rows) does not mask an injection. This is
1401- # the HTML counterpart of the structure-aware JSON comparison
1402- if firstPage and secondPage and extractStructuralTokens (firstPage ) == extractStructuralTokens (secondPage ):
1403- kb .pageStructurallyStable = True
1404-
1405- if kb .nullConnection :
1406- debugMsg = "turning off NULL connection "
1407- debugMsg += "support because of structural page comparison"
1408- logger .debug (debugMsg )
1409-
1410- kb .nullConnection = None
1411-
1412- infoMsg = "target URL content is not byte-stable but structurally stable; sqlmap "
1413- infoMsg += "will base the page comparison on the page structure"
1414- logger .info (infoMsg )
1415- else :
1416- checkDynamicContent (firstPage , secondPage )
1418+ checkDynamicContent (firstPage , secondPage )
14171419
14181420 return kb .pageStable
14191421
0 commit comments