Skip to content

Commit 103a0e6

Browse files
committed
More refactoring for --xxe
1 parent 3cf29a5 commit 103a0e6

3 files changed

Lines changed: 34 additions & 17 deletions

File tree

data/txt/sha256sums.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ c2db614a3ce7dda889152bea8bd6d709e5d8c2b556741fdbfe44469f27ce266b lib/core/enums
189189
9bf174058f15d14e24e94f9aaf42df045119d3617c6c54bd2f3af79b462f331d lib/core/replication.py
190190
0b8c38a01bb01f843d94a6c5f2075ee47520d0c4aa799cecea9c3e2c5a4a23a6 lib/core/revision.py
191191
888daba83fd4a34e9503fe21f01fef4cc730e5cde871b1d40e15d4cbc847d56c lib/core/session.py
192-
c8b5b430219d8bdd7e0139c2fe10a8175c55dc4ef2c1baa84fa24c4d6d8d4229 lib/core/settings.py
192+
d9b2dc6104456fa679f827d16baeb1ed7ca377a961d163d12cd2b7eba09f24c6 lib/core/settings.py
193193
c7804223319e18eb0b8e2cbf0a8b6896d1cefb7b0b1a2e9f1cf826a8a3b56750 lib/core/shell.py
194194
a2e98a94b231432736d6b304fc75525c8b5fdb4768c418387c5b4c1a610dad64 lib/core/subprocessng.py
195195
15d36cdac9389d0a54a6c33fbb89f32bb65e303f50de573773dcb6d4618bca64 lib/core/target.py
@@ -258,7 +258,7 @@ c68f8259e0a89a556d049f227041849df584313bd1b5349b02f74a47778c901c lib/techniques
258258
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/techniques/xpath/__init__.py
259259
c61816c9dba9f6cc2223aed1a923f95130979e5f0a88ec254ee667d955ed2734 lib/techniques/xpath/inject.py
260260
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/techniques/xxe/__init__.py
261-
d9a776f37578e4c3b0498689eaff448904048b41d8ce9e758d2404a912c44ae8 lib/techniques/xxe/inject.py
261+
e542cbcb1e2798f2d756d1f79940f61f7cebef661657f8ca1dba83c0696e95eb lib/techniques/xxe/inject.py
262262
2403eda0e87835a2b402cbe6927a4d2737c4e87f3d4ef9b75e7685f3d2a9dc1e lib/utils/api.py
263263
442555ab85277aff7c9e0cf465ea5b0d28395c326f68363449b2d3941f4b6de2 lib/utils/brute.py
264264
da5bcbcda3f667582adf5db8c1b5d511b469ac61b55d387cec66de35720ed718 lib/utils/crawler.py

lib/core/settings.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from thirdparty import six
2121

2222
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
23-
VERSION = "1.10.7.25"
23+
VERSION = "1.10.7.26"
2424
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
2525
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
2626
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)

lib/techniques/xxe/inject.py

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -656,20 +656,23 @@ def xxeScan():
656656
logger.info("testing XXE injection on the XML request body (root element: '%s')" % rootName)
657657

658658
baseline = _send(xml)
659-
found = False
659+
found = False # an actual impact/oracle (file read, error-based, XInclude, blind)
660+
expansionSeen = False # reflected DTD/internal-entity processing (weaker; must not stop the search)
660661

661662
# T2: in-band reflected DTD/internal-entity expansion. This proves the parser
662-
# processes entities; it is NOT yet external-entity file-read impact - so the
663-
# finding is worded conservatively and escalated only if an actual read follows.
663+
# processes entities but is NOT yet file-read impact, so it deliberately does NOT
664+
# set `found` - the in-band read (or, if that fails, the error/XInclude tiers) still
665+
# run to try to upgrade a mere "expansion confirmed" into actual file-read impact.
664666
payload, page = _tryInternal(xml, rootName, baseline)
665667
if payload:
666-
found = True
668+
expansionSeen = True
667669
logger.info("the XML body processes DTD/internal entities (in-band reflection confirmed)")
668670
_report("In-band DTD/internal entity expansion", payload)
669671

670672
if conf.get("fileRead"):
671673
content = _tryInbandFileRead(xml, rootName, conf.fileRead)
672674
if content:
675+
found = True
673676
logger.info("in-band XXE file-read impact confirmed for '%s'" % conf.fileRead)
674677
_report("In-band file read ('%s')" % conf.fileRead, "<in-band reflected read of '%s'>" % conf.fileRead)
675678
_dumpFileRead(conf.fileRead, content)
@@ -680,21 +683,24 @@ def xxeScan():
680683
snippet = _tryPhpFilter(xml, rootName, baseline)
681684
systemId = "php://filter" if snippet else None
682685
if systemId:
686+
found = True
683687
logger.info("in-band XXE file-read impact confirmed (external entity, e.g. '%s')" % systemId)
684688
_report("In-band file-read impact (external entity '%s')" % systemId, "<external-entity read of a benign file for impact>")
685689

686-
# T3: error-based (works where entities are not reflected but errors leak)
690+
# T3: error-based (works where entities are not reflected but errors leak). A
691+
# redundant detection channel once in-band reflection was already seen, so it is
692+
# skipped then - the file-read *impact* tiers below still run to try to upgrade.
687693
errorChannel = False
688-
if not found:
694+
if not found and not expansionSeen:
689695
payload, page = _tryError(xml, rootName)
690696
if payload:
691697
found = errorChannel = True
692698
backend = _fingerprint(page) or "Generic XML"
693699
logger.info("the XML body is vulnerable to XXE injection (error-based, back-end parser: '%s')" % backend)
694700
_report("Error-based (parameter entity, back-end: '%s')" % backend, payload)
695701

696-
# T3b: no-egress error-based via local-DTD repurposing
697-
if not found:
702+
# T3b: no-egress error-based via local-DTD repurposing (detection; skip once reflected)
703+
if not found and not expansionSeen:
698704
payload, page = _tryLocalDtd(xml, rootName)
699705
if payload:
700706
found = errorChannel = True
@@ -721,27 +727,32 @@ def xxeScan():
721727
logger.info("the XML body is vulnerable to XInclude file read ('%s'): '%s'" % (systemId, snippet))
722728
_report("XInclude file read ('%s')" % systemId, payload)
723729

724-
# T5: WAF-evasion fallbacks (UTF-16 re-encoding, PUBLIC-for-SYSTEM)
725-
if not found:
730+
# T5: WAF-evasion fallbacks (UTF-16 re-encoding, PUBLIC-for-SYSTEM). The UTF-16
731+
# variant re-detects internal-entity reflection, so it is redundant (and mislabels
732+
# as 'evasion') once reflection was already seen - skip it then.
733+
if not found and not expansionSeen:
726734
title, payload = _tryEvasions(xml, rootName, baseline)
727735
if title:
728736
found = True
729737
logger.info("the XML body is vulnerable to XXE injection (%s)" % title.lower())
730738
_report(title, payload)
731739

732-
# T6: time-based blind (no collector, no third party) - external entity to a non-routable host
733-
if not found:
740+
# T6: time-based blind (no collector, no third party) - external entity to a non-routable host.
741+
# Skipped once in-band reflection worked: the target is demonstrably not blind, so the (slow)
742+
# blind tiers add nothing and would needlessly stall.
743+
if not found and not expansionSeen:
734744
logger.debug("attempting time-based blind XXE (external entity to a non-routable host); this can be slow")
735745
payload = _tryTimeBlind(xml, rootName)
736746
if payload:
737747
found = True
738748
logger.info("the XML body is vulnerable to XXE injection (time-based blind, external entity resolution reaches out-of-band)")
739749
_report("Time-based blind (external entity to non-routable host)", payload)
740750

741-
# T7: out-of-band tiers - THIRD PARTY, so only on explicit consent (default NO).
751+
# T7: out-of-band tiers - THIRD PARTY, so only on explicit consent (default NO). Also blind-only
752+
# (skipped when in-band reflection already worked, so a non-blind target never triggers the prompt).
742753
# Low-impact callback confirmation is the default; actual file exfiltration is
743754
# attempted only when the user explicitly asked for a file via '--file-read'.
744-
if not found and _oobConsent():
755+
if not found and not expansionSeen and _oobConsent():
745756
if conf.get("fileRead"):
746757
exfil = _tryOobExfil(xml, rootName)
747758
if exfil and (exfil["content"] or exfil["detected"]):
@@ -762,6 +773,12 @@ def xxeScan():
762773
_report("Out-of-band blind (collector callback: %s)" % protocol, payload)
763774

764775
if not found:
776+
if expansionSeen:
777+
# in-band entity processing is real, but no external-entity/blind oracle was reachable
778+
# (typically external entities disabled) - report honestly rather than overstate impact
779+
logger.info("DTD/internal entity processing is enabled, but no external-entity file-read or blind XXE oracle was established")
780+
logger.info("XXE scan complete")
781+
return
765782
# Reachable-but-not-exploitable diagnostics: distinguish a hardened parser
766783
# from a merely non-reflecting one so the user knows why it did not fire.
767784
probe = _send(_buildDoctype(xml, rootName, '<!ENTITY %% p SYSTEM "file:///%s">%%p;' % SENTINEL))

0 commit comments

Comments
 (0)