Skip to content

Commit 5fa2da5

Browse files
committed
Adding support for --xxe
1 parent 16c8909 commit 5fa2da5

14 files changed

Lines changed: 1413 additions & 16 deletions

File tree

data/txt/sha256sums.txt

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,8 @@ df768bcb9838dc6c46dab9b4a877056cb4742bd6cfaaf438c4a3712c5cc0d264 extra/shutils/
162162
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 extra/vulnserver/__init__.py
163163
9af5fdfa8b2425d404d86ab08d3644caa95bcf77605551f5da482a59d1e54a22 extra/vulnserver/vulnserver.py
164164
a2bf70d7f87c3a4e0675c0bad54119a4e04efa6ea2730a8338d5aebcd995630e lib/controller/action.py
165-
736715a73941a06e5d3d349dd01a1f1b171f54eb4c374c6752b2cc44b0977ffe lib/controller/checks.py
166-
2086100cd7a78a4e8c12d72bd4f5b414ec6b3f49926e83285494534140e60ce7 lib/controller/controller.py
165+
0d1072ac052b65fca6da9975238b6f8816bc78603631b68ada4c7aea97f060e4 lib/controller/checks.py
166+
00d56cc59757cc3f3073ac20735ac9954ff06242b9433a96bd4186c090094db3 lib/controller/controller.py
167167
d69e84f1648cdb907f5d2dd454f03874a4613752b07867510145d51d84b3c56f lib/controller/handler.py
168168
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/controller/__init__.py
169169
48ffe93d61734e16c3b20153b51595853d9ac1fbcf0b537e0e61e957b0c0bfa6 lib/core/agent.py
@@ -181,15 +181,15 @@ c2db614a3ce7dda889152bea8bd6d709e5d8c2b556741fdbfe44469f27ce266b lib/core/enums
181181
5387168e5dfedd94ae22af7bb255f27d6baaca50b24179c6b98f4f325f5cc7b4 lib/core/exception.py
182182
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/core/__init__.py
183183
914a13ee21fd610a6153a37cbe50830fcbd1324c7ebc1e7fc206d5e598b0f7ad lib/core/log.py
184-
47c9828bdfa606a02f07925539d7af55c5eaf1fda61d05ecc40f73d77df036f9 lib/core/optiondict.py
185-
3ac60716cf1c619b80038acb8b213c728cc607e7c5a387911e01635a23fbc92b lib/core/option.py
184+
23852bdfadfb4bd5663302a63bdcc7227c0314fbdea884167d58ca21cda9fb09 lib/core/optiondict.py
185+
0caac9b4af2cc50321a4d8126d92481ad0b092af2075e7efa19bccef529986fb lib/core/option.py
186186
21b2b1745107c211fc7593923a3da7a808d40763c00091c28de5f7c129bcf3bc lib/core/patch.py
187187
49c0fa7e3814dfda610d665ee02b12df299b28bc0b6773815b4395514ddf8dec lib/core/profiling.py
188188
0c36a65b6237732eb001d333f80f0c58c088ff01ae80cf07e4dcc6da2a806364 lib/core/readlineng.py
189189
9bf174058f15d14e24e94f9aaf42df045119d3617c6c54bd2f3af79b462f331d lib/core/replication.py
190190
0b8c38a01bb01f843d94a6c5f2075ee47520d0c4aa799cecea9c3e2c5a4a23a6 lib/core/revision.py
191191
888daba83fd4a34e9503fe21f01fef4cc730e5cde871b1d40e15d4cbc847d56c lib/core/session.py
192-
6f4a6f82360addb01fb9581a67f67df30a2d44606b631bf3e1dc026e46f83e55 lib/core/settings.py
192+
d974c44979d7699feda3eafeb1baee9618cb6dbe27b144a6d36bec95527c5cee lib/core/settings.py
193193
c7804223319e18eb0b8e2cbf0a8b6896d1cefb7b0b1a2e9f1cf826a8a3b56750 lib/core/shell.py
194194
a2e98a94b231432736d6b304fc75525c8b5fdb4768c418387c5b4c1a610dad64 lib/core/subprocessng.py
195195
15d36cdac9389d0a54a6c33fbb89f32bb65e303f50de573773dcb6d4618bca64 lib/core/target.py
@@ -200,7 +200,7 @@ b9aacb840310173202f79c2ba125b0243003ee6b44c92eca50424f2bdfc83c02 lib/core/unesc
200200
2400e465fa4d13e4c32795910878c71ff212e4361b46428d57ce43983f5e997c lib/core/wordlist.py
201201
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/__init__.py
202202
54bfd31ebded3ffa5848df1c644f196eb704116517c7a3d860b5d081e984d821 lib/parse/banner.py
203-
fef119c6f3f2fe6a092112fd832d645c58e4c3c2af0bd97ace4487372c1e3574 lib/parse/cmdline.py
203+
6d2b663807178b4eed0060ed22cde5a94d1b63b7f1ce54e401f709acfd2344c0 lib/parse/cmdline.py
204204
925a068efa1885fa40671414a887c088f2aafbe8cb76f01286e6bde3f624dac1 lib/parse/configfile.py
205205
c5b258be7485089fac9d9cd179960e774fbd85e62836dc67cce76cc028bb6aeb lib/parse/handler.py
206206
5c9a9caee948843d5537745640cc7b98d70a0412cc0949f59d4ebe8b2907c06c lib/parse/headers.py
@@ -215,17 +215,19 @@ bc61bc944b81a7670884f82231033a6ac703324b34b071c9834886a92e249d0e lib/request/ch
215215
4fd1957e31b14e7670b09d85a634fa6772a1cd90babe149f39a1c945fe306f0a lib/request/comparison.py
216216
4a3b997a83b1724e8bd025be95ec5d84c6bf41d533ba097fcab1eab763352111 lib/request/connect.py
217217
8e06682280fce062eef6174351bfebcb6040e19976acff9dc7b3699779783498 lib/request/direct.py
218-
a6b37b436838caeb197fea858d0a39fadbff4736256e741b5fcec1f28fcf1ce0 lib/request/dns.py
218+
b1f07e0571f249eedf294b7827c530b0de8c0524d445b33fdb2d0a639c0f123a lib/request/dns.py
219219
7344978ac1c52060716b7837c88a62768c6a445eafe189ea3232b8a498fdd038 lib/request/http2.py
220220
92c81cc31ff4a396723242058fb2152c9e9745f8412d01ea74480b048a53af6c lib/request/httpshandler.py
221221
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/request/__init__.py
222222
7a0ac2522213e756348fd871a7af74cc963bdc82f9d7ade57be5de42b5bf7cab lib/request/inject.py
223+
fa51d6c8855049ac18b8c08dfea87df3ce0ebcc094d62322e9f615284bca54af lib/request/interactsh.py
223224
ff15723c82e343eb95f4599d251165d478ca720afc8f5daaed3da44ea923df44 lib/request/keepalive.py
224225
ada4d305d6ce441f79e52ec3f2fc23869ee2fa87c017723e8f3ed0dfa61cdab4 lib/request/methodrequest.py
225226
43a7fdf64e7ba63c6b2d641c9f999a63c12ac23b43b64fedfce4e05b863de568 lib/request/pkihandler.py
226227
b90feeb16e89a844427df42373b0139eb6f6cf3c48ccec32b3e3a3f540c2451e lib/request/rangehandler.py
227228
fa347e74361904d052e4d5c958ebbdf080e4f7003176824a44786108b4d7afc6 lib/request/redirecthandler.py
228229
1bf93c2c251f9c422ecf52d9cae0cd0ff4ea2e24091ee6d019c7a4f69de8e5eb lib/request/templates.py
230+
58da8988a650c19e080980e545216158ba267065374c6812dabe0b22c1407bd2 lib/request/webhooksite.py
229231
01600295b17c00d4a5ada4c77aa688cfe36c89934da04c031be7da8040a3b457 lib/takeover/abstraction.py
230232
d3c93562d78ebdaf9e22c0ea2e4a62adb12f0ce9e9d9631c1ea000b1a07d04ab lib/takeover/icmpsh.py
231233
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/takeover/__init__.py
@@ -255,6 +257,8 @@ f6678ac1342f8d234ed32ae69be5ac5d7837393e9348929ec029c9764c030e82 lib/techniques
255257
c68f8259e0a89a556d049f227041849df584313bd1b5349b02f74a47778c901c lib/techniques/union/use.py
256258
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/techniques/xpath/__init__.py
257259
c61816c9dba9f6cc2223aed1a923f95130979e5f0a88ec254ee667d955ed2734 lib/techniques/xpath/inject.py
260+
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/techniques/xxe/__init__.py
261+
9a74178421ea0d98f7b27062e97eb55a12236deb893c2ef5f26fb6e734001f32 lib/techniques/xxe/inject.py
258262
2403eda0e87835a2b402cbe6927a4d2737c4e87f3d4ef9b75e7685f3d2a9dc1e lib/utils/api.py
259263
442555ab85277aff7c9e0cf465ea5b0d28395c326f68363449b2d3941f4b6de2 lib/utils/brute.py
260264
da5bcbcda3f667582adf5db8c1b5d511b469ac61b55d387cec66de35720ed718 lib/utils/crawler.py
@@ -609,7 +613,7 @@ fa85881aa8d082a65aeacb2b03fcb5d2abb1daa9a02ee24ff048d54fbc904b90 tests/test_dia
609613
41bb0981cb7372753dbaa328c8be3678d328b736e6b97f7bd2573b465753af01 tests/test_dialect.py
610614
993a2d4d87c4fbaf261663b069629acc95ee4405aa0c42cf5a8f39649fdb0fff tests/test_dicts.py
611615
62a4386524d0ef269cba3bd6dcadc5a2a11c0d2bdd198773b79bcd8589324328 tests/test_dns_engine.py
612-
ec58ba0849d90d2bb7580fe2b8b96cd8299ddfc25f14dc27d9de9d41f152c78a tests/test_dns_server.py
616+
a9db98cbb4d16c42118fb6f612edd5bfedc77298e38d06d50e7ecc2faaa7fdc1 tests/test_dns_server.py
613617
3dc788fd3adba8b6f766281e0a50025b1ee9150d80ab9a738c6c43f2eaf805b3 tests/test_dump_format.py
614618
118d1987861ed0df978474329adce8c23009b3964210c13fbaf667e0019bbd15 tests/test_dump_jsonl.py
615619
2bbe4b01f79992cfa8884651fc0a28dbd0e3abb0cbea9eb7eadf1f98ca3c3420 tests/test_encoding.py
@@ -666,6 +670,7 @@ b03689c4dcca0e88a62a88784c61418f963c031d338a357dcc223560c8f9bd22 tests/test_use
666670
93ef9944effc62d4f744c57bd643137c90fd92205c6a6cbe891e0e99efb80a7f tests/test_wafbypass.py
667671
81bb6d7449f224fa337734ae361c1a340bf9a51768a854d6a1a6e718ed1263ca tests/test_wordlist.py
668672
9d6dd551b751ab38200ab190c744ec0a9afa798b37f83b0078a4325ab3f80aec tests/test_xpath.py
673+
140aa78a94fb97e364cead82149f5a2c33d576b721f39ae52a6352072d770793 tests/test_xxe.py
669674
55eaefc664bd8598329d535370612351ec8443c52465f0a37172ea46a97c458a thirdparty/ansistrm/ansistrm.py
670675
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 thirdparty/ansistrm/__init__.py
671676
f597b49ef445bfbfb8f98d1f1a08dcfe4810de5769c0abfab7cdce4eebbfcae7 thirdparty/beautifulsoup/beautifulsoup.py

lib/controller/checks.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
from lib.core.enums import DBMS
5858
from lib.core.enums import HASHDB_KEYS
5959
from lib.core.enums import HEURISTIC_TEST
60+
from lib.core.enums import POST_HINT
6061
from lib.core.enums import HTTP_HEADER
6162
from lib.core.enums import HTTPMETHOD
6263
from lib.core.enums import NOTE
@@ -86,6 +87,7 @@
8687
from lib.core.settings import LDAP_ERROR_REGEX
8788
from lib.core.settings import SSTI_ERROR_REGEX
8889
from lib.core.settings import XPATH_ERROR_REGEX
90+
from lib.core.settings import XXE_ERROR_REGEX
8991
from lib.core.settings import IPS_WAF_CHECK_PAYLOAD
9092
from lib.core.settings import IPS_WAF_CHECK_RATIO
9193
from lib.core.settings import IPS_WAF_CHECK_TIMEOUT
@@ -1214,6 +1216,13 @@ def _(page):
12141216
if conf.beep:
12151217
beep()
12161218

1219+
if not conf.xxe and kb.postHint in (POST_HINT.XML, POST_HINT.SOAP) and re.search(XXE_ERROR_REGEX, page or ""):
1220+
infoMsg = "heuristic (XXE) test shows that the XML request body might be vulnerable to XML External Entity injection (rerun with switch '--xxe')"
1221+
logger.info(infoMsg)
1222+
1223+
if conf.beep:
1224+
beep()
1225+
12171226
kb.disableHtmlDecoding = False
12181227
kb.heuristicMode = False
12191228

lib/controller/controller.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -529,8 +529,8 @@ def start():
529529

530530
checkWaf()
531531

532-
if any((conf.graphql, conf.nosql, conf.ldap, conf.xpath, conf.ssti)) and (conf.reportJson or conf.resultsFile):
533-
singleTimeWarnMessage("'--report-json'/'--results-file' do not (yet) capture non-SQL technique (--graphql/--nosql/--ldap/--xpath/--ssti) findings; these are reported on the console only")
532+
if any((conf.graphql, conf.nosql, conf.ldap, conf.xpath, conf.ssti, conf.xxe)) and (conf.reportJson or conf.resultsFile):
533+
singleTimeWarnMessage("'--report-json'/'--results-file' do not (yet) capture non-SQL technique (--graphql/--nosql/--ldap/--xpath/--ssti/--xxe) findings; these are reported on the console only")
534534

535535
if conf.graphql:
536536
from lib.techniques.graphql.inject import graphqlScan
@@ -557,6 +557,11 @@ def start():
557557
sstiScan()
558558
continue
559559

560+
if conf.xxe:
561+
from lib.techniques.xxe.inject import xxeScan
562+
xxeScan()
563+
continue
564+
560565
if conf.nullConnection:
561566
checkNullConnection()
562567

lib/core/option.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@
144144
from lib.request.chunkedhandler import ChunkedHandler
145145
from lib.request.connect import Connect as Request
146146
from lib.request.dns import DNSServer
147+
from lib.request.dns import InteractshDNSServer
147148
from lib.request.httpshandler import HTTPSHandler
148149
from lib.request.keepalive import HTTPKeepAliveHandler
149150
from lib.request.keepalive import HTTPSKeepAliveHandler
@@ -935,10 +936,10 @@ def _setTamperingFunctions():
935936
logger.warning(warnMsg)
936937

937938
# tamper scripts rewrite SQL injection payloads; the self-contained non-SQL engines
938-
# (--graphql/--nosql/--ldap/--xpath/--ssti) do not run payloads through the tampering hook, so
939+
# (--graphql/--nosql/--ldap/--xpath/--ssti/--xxe) do not run payloads through the tampering hook, so
939940
# warn instead of silently ignoring the user's '--tamper'
940-
if kb.tamperFunctions and any((conf.graphql, conf.nosql, conf.ldap, conf.xpath, conf.ssti)):
941-
engine = next(_ for _ in ("graphql", "nosql", "ldap", "xpath", "ssti") if conf.get(_))
941+
if kb.tamperFunctions and any((conf.graphql, conf.nosql, conf.ldap, conf.xpath, conf.ssti, conf.xxe)):
942+
engine = next(_ for _ in ("graphql", "nosql", "ldap", "xpath", "ssti", "xxe") if conf.get(_))
942943
warnMsg = "tamper scripts are applied to SQL injection payloads only and "
943944
warnMsg += "will be ignored by the '--%s' engine" % engine
944945
logger.warning(warnMsg)
@@ -2581,6 +2582,26 @@ def _setDNSServer():
25812582
if not conf.dnsDomain:
25822583
return
25832584

2585+
from lib.core.settings import OOB_INTERACTSH_SERVERS
2586+
2587+
_requested = conf.dnsDomain.strip().lower()
2588+
if _requested in ("interactsh", "oast", "oob") or _requested in OOB_INTERACTSH_SERVERS:
2589+
infoMsg = "setting up interactsh-backed DNS exfiltration collector"
2590+
logger.info(infoMsg)
2591+
2592+
try:
2593+
conf.dnsServer = InteractshDNSServer(server=_requested if _requested in OOB_INTERACTSH_SERVERS else None)
2594+
conf.dnsServer.run()
2595+
conf.dnsDomain = conf.dnsServer.domain
2596+
except socket.error as ex:
2597+
errMsg = "there was an error while setting up "
2598+
errMsg += "the interactsh DNS collector ('%s')" % getSafeExString(ex)
2599+
raise SqlmapGenericException(errMsg)
2600+
2601+
infoMsg = "using interactsh DNS collector (exfiltration domain '%s')" % conf.dnsDomain
2602+
logger.info(infoMsg)
2603+
return
2604+
25842605
infoMsg = "setting up DNS server instance"
25852606
logger.info(infoMsg)
25862607

lib/core/optiondict.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,9 @@
125125
"ldap": "boolean",
126126
"xpath": "boolean",
127127
"ssti": "boolean",
128+
"xxe": "boolean",
129+
"oobServer": "string",
130+
"oobToken": "string",
128131
"timeSec": "integer",
129132
"uCols": "string",
130133
"uChar": "string",

lib/core/settings.py

Lines changed: 68 additions & 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.23"
23+
VERSION = "1.10.7.24"
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)
@@ -1071,6 +1071,73 @@
10711071

10721072
SSTI_ERROR_REGEX = r"(?i)(?:%s)" % '|'.join(regex for _, regex in SSTI_ERROR_SIGNATURES)
10731073

1074+
# XXE parser error signatures for detection and fingerprinting. Each tuple is
1075+
# (parser_family, regex_fragment). A match means the XML surface reached a real
1076+
# parser and the DOCTYPE/entity was processed (or rejected with a diagnostic) -
1077+
# useful both as an error-based oracle and to fingerprint the back-end parser.
1078+
XXE_ERROR_SIGNATURES = (
1079+
("libxml2 (PHP/lxml)", r"(?:failed to load (?:external entity|\")|xmlParseEntityRef|Entity '[^']*' not defined|EntityRef: expecting|Detected an entity reference loop|String not started expecting|StartTag: invalid element name|Start tag expected|Extra content at the end of the document|Premature end of data|error parsing DTD|internal error: Huge input lookup)"),
1080+
("PHP simplexml/DOM", r"(?:simplexml_load_string\(\)|DOMDocument::load(?:XML)?\(\)|SimpleXMLElement::__construct\(\))"),
1081+
("Java (Xerces/JAXP)", r"(?:org\.xml\.sax\.SAXParseException|com\.sun\.org\.apache\.xerces|javax\.xml\.stream\.XMLStreamException|The (?:entity|element type) \"[^\"]*\" was referenced|DOCTYPE is disallowed when the feature|External (?:DTD|parsed entities|Entity): failed|must be declared|had to be read but the maximum)"),
1082+
(".NET System.Xml", r"(?:System\.Xml\.XmlException|For security reasons DTD is prohibited|Reference to undeclared entity|An error occurred while parsing EntityName|XmlTextReaderImpl)"),
1083+
("Python expat", r"(?:xml\.parsers\.expat\.ExpatError|undefined entity|not well-formed \(invalid token\)|ExpatError)"),
1084+
("Ruby Nokogiri/REXML", r"(?:Nokogiri::XML::SyntaxError|REXML::ParseException|Entity .* not defined)"),
1085+
("Go encoding/xml", r"XML syntax error on line \d+"),
1086+
("Generic XML", r"(?:XML (?:parsing|parse|syntax) error|malformed XML|unexpected (?:end of|<) )"),
1087+
)
1088+
1089+
XXE_ERROR_REGEX = r"(?i)(?:%s)" % '|'.join(regex for _, regex in XXE_ERROR_SIGNATURES)
1090+
1091+
# Signatures indicating a hardened / XXE-safe parser posture (DTDs or external
1092+
# entities explicitly refused). Reported as "reachable but protected" - never a hit.
1093+
XXE_HARDENED_REGEX = r"(?i)(?:DOCTYPE is disallowed|DTD is prohibited|(?:external )?(?:DTD|entit(?:y|ies)) (?:are|is) (?:not (?:supported|allowed)|disabled|prohibited|forbidden)|loading of external|network access is not allowed|FEATURE_SECURE_PROCESSING|access to external)"
1094+
1095+
# Benign, low-entropy files used only to demonstrate file-read impact once XXE is
1096+
# confirmed. Deliberately NOT /etc/passwd (WAF honeypots key on "root:x:0:0") - a
1097+
# short host-identity file is enough to prove the read without tripping decoys.
1098+
# Out-of-band (interactsh) collector for blind XXE confirmation. Public default
1099+
# pool (best-effort, may rotate/be blocklisted by WAFs); override with --oob-server
1100+
# to point at a self-hosted interactsh-server. Correlation-id + nonce lengths match
1101+
# the interactsh defaults (subdomain = <20-char id><13-char nonce>.<server>).
1102+
OOB_INTERACTSH_SERVERS = ("oast.fun", "oast.pro", "oast.live", "oast.site", "oast.online", "oast.me")
1103+
# Public content-hosting + request-logging endpoint for blind-XXE OOB exfiltration
1104+
# (hosts the malicious external DTD and captures the file-bearing callback). Unlike
1105+
# interactsh it can serve arbitrary content; HTTP-only. Default exfil target is benign.
1106+
OOB_EXFIL_ENDPOINT = "https://webhook.site"
1107+
OOB_EXFIL_DEFAULT_FILE = "/etc/hostname"
1108+
OOB_CORRELATION_ID_LENGTH = 20
1109+
OOB_NONCE_LENGTH = 13
1110+
OOB_POLL_ATTEMPTS = 5
1111+
OOB_POLL_DELAY = 2
1112+
1113+
# Time-based blind tier: an external entity aimed at this non-routable RFC5737
1114+
# TEST-NET-1 host makes a fetching parser stall on the connection, so a large,
1115+
# reproducible response delay betrays otherwise-blind XXE with NO collector needed.
1116+
# The delay must exceed a DTD-processing control baseline by this many seconds.
1117+
XXE_BLACKHOLE_HOST = "192.0.2.1"
1118+
XXE_TIME_THRESHOLD = 5
1119+
1120+
XXE_IMPACT_FILES = (
1121+
("file:///etc/os-release", r"(?i)^(?:NAME|ID|VERSION)="), # high-signal, tried first
1122+
("file:///c:/windows/win.ini", r"(?i)\[(?:fonts|extensions|mci extensions|files)\]"),
1123+
("file:///etc/hostname", r"^[\w.-]{1,255}$"), # loosest pattern, tried last
1124+
)
1125+
1126+
# GoSecure dtd-finder local-DTD repurposing table for no-egress error-based XXE:
1127+
# an on-disk DTD is loaded, one of its parameter entities is redefined to smuggle
1128+
# an error/exfil primitive, so no outbound network is needed. (path, entity_name).
1129+
# Windows paths are community-sourced and remain UNVERIFIED vendor-side.
1130+
XXE_LOCAL_DTDS = (
1131+
("file:///usr/share/yelp/dtd/docbookx.dtd", "ISOamso"), # GNOME yelp - reliably repurposable
1132+
("file:///usr/share/xml/docbook/schema/dtd/4.5/docbookx.dtd", "ISOamso"), # docbook package
1133+
("file:///opt/IBM/WebSphere/AppServer/properties/sip-app_1_0.dtd", "connection"),
1134+
("file:///usr/share/xml/fontconfig/fonts.dtd", "constant"), # widespread but gadget is version-fragile
1135+
("file:///C:/Windows/System32/wbem/cim20.dtd", "SuperClass"), # Windows paths community-sourced, UNVERIFIED
1136+
("file:///C:/Windows/System32/wbem/wmi20.dtd", "extension"),
1137+
("file:///C:/Windows/System32/xwizards/xwizard.dtd", "ELEMENT"),
1138+
("jar:file:///usr/share/java/lotus-domino.jar!/schema/domino.dtd", "abbr"),
1139+
)
1140+
10741141
# Upper bound for SSTI value extraction (reserved for future use)
10751142
SSTI_MAX_LENGTH = 256
10761143

lib/parse/cmdline.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ def cmdLineParser(argv=None):
440440
help="Column values to use for UNION query SQL injection")
441441

442442
techniques.add_argument("--dns-domain", dest="dnsDomain",
443-
help="Domain name used for DNS exfiltration attack")
443+
help="Domain name used for DNS exfiltration attack (or 'interactsh' for zero-setup OOB)")
444444

445445
techniques.add_argument("--second-url", dest="secondUrl",
446446
help="Resulting page URL searched for second-order response")
@@ -790,6 +790,15 @@ def cmdLineParser(argv=None):
790790
nonsql.add_argument("--ssti", dest="ssti", action="store_true",
791791
help="Test for server-side template injection")
792792

793+
nonsql.add_argument("--xxe", dest="xxe", action="store_true",
794+
help="Test for XML External Entity (XXE) injection")
795+
796+
nonsql.add_argument("--oob-server", dest="oobServer",
797+
help="Out-of-band server for blind '--xxe' (default: public interactsh; 'none' to disable OOB)")
798+
799+
nonsql.add_argument("--oob-token", dest="oobToken",
800+
help="Authentication token for a self-hosted '--oob-server'")
801+
793802
# Miscellaneous options
794803
miscellaneous = parser.add_argument_group("Miscellaneous", "These options do not fit into any other category")
795804

0 commit comments

Comments
 (0)