Skip to content

Commit 8ff5d38

Browse files
committed
Adding switch --xpath
1 parent 4c86981 commit 8ff5d38

12 files changed

Lines changed: 1242 additions & 9 deletions

File tree

.github/workflows/tests.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,9 @@ jobs:
108108
python -m coverage report --fail-under=50
109109
110110
- name: Smoke test
111-
run: python sqlmap.py --smoke-test
111+
run: |
112+
python -m pip install -q lxml
113+
python sqlmap.py --smoke-test
112114
113115
- name: Vuln test
114116
run: python sqlmap.py --vuln-test

data/txt/sha256sums.txt

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,10 @@ ca86d61d3349ed2d94a6b164d4648cff9701199b5e32378c3f40fca0f517b128 extra/shutils/
160160
df768bcb9838dc6c46dab9b4a877056cb4742bd6cfaaf438c4a3712c5cc0d264 extra/shutils/recloak.sh
161161
1972990a67caf2d0231eacf60e211acf545d9d0beeb3c145a49ba33d5d491b3f extra/shutils/strip.sh
162162
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 extra/vulnserver/__init__.py
163-
32577fc21a6170266438b608ed81620e0b0a889aa8a05124bc7f0905cba772a6 extra/vulnserver/vulnserver.py
163+
a4d4ec8aaea6da7b20068209945cf46348bde74b4c90ddf630c3be820d16f73e extra/vulnserver/vulnserver.py
164164
a2bf70d7f87c3a4e0675c0bad54119a4e04efa6ea2730a8338d5aebcd995630e lib/controller/action.py
165-
c9a1661fc6719655e1e5b6dd72caab680766690c5f746b386093267329f7b3b8 lib/controller/checks.py
166-
256ba0c6967121dc25c95fe09d1165dd8d0530f26c7879e6036f649fb0a6de95 lib/controller/controller.py
165+
0397a941e27fa23ef375b6bd0a654132b05496d78737253a58524aab7e840789 lib/controller/checks.py
166+
e9fd898a38e4e1bfc975e44b41b344c190e58d845b8602a50a2bf05835ddc7c8 lib/controller/controller.py
167167
d69e84f1648cdb907f5d2dd454f03874a4613752b07867510145d51d84b3c56f lib/controller/handler.py
168168
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/controller/__init__.py
169169
9c5764c92ce536d1f0f96200359ee5ef1f37f9128769bf990cb77f1d1f8e17b1 lib/core/agent.py
@@ -181,26 +181,26 @@ f8de57606325456928e46ae2896f5f8bbec9ad18b1c644b492a566fa992216f6 lib/core/decor
181181
5387168e5dfedd94ae22af7bb255f27d6baaca50b24179c6b98f4f325f5cc7b4 lib/core/exception.py
182182
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/core/__init__.py
183183
914a13ee21fd610a6153a37cbe50830fcbd1324c7ebc1e7fc206d5e598b0f7ad lib/core/log.py
184-
1b03686e1aa916ccad3cd86b8e4e6ea4baca5e30e05bf86a56f8df8dd4f44ba6 lib/core/optiondict.py
184+
8b5d4d1f503ef7075820f7eca184c9e55386b7717c5cf93d195fa9e5332d9e34 lib/core/optiondict.py
185185
e033b20a0f7821797a10f4bf4235723f38c7db551c611fbb713faa621b123c4a 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-
e9aae7dacf83a4d7054862eeb0a96ed695731cd87f8b03836a8a41c7454d0f5f lib/core/settings.py
192+
77a4804887ae9dde7142ede91fcae1bd1d7369132f90d7bf095e8bad6f62e5a4 lib/core/settings.py
193193
c7804223319e18eb0b8e2cbf0a8b6896d1cefb7b0b1a2e9f1cf826a8a3b56750 lib/core/shell.py
194194
a2e98a94b231432736d6b304fc75525c8b5fdb4768c418387c5b4c1a610dad64 lib/core/subprocessng.py
195195
19f1e3c5e3ba703d28d510cd7a9ab8284d5fbe9df5ce7e77c86e5931571364b7 lib/core/target.py
196-
46b405d0e0e035b3f323deffc1f1d30505adf7c01144ea2ddf81c5dc6caaa20f lib/core/testing.py
196+
fbfb3fa79ac0566a985b8cdc3a2e4758bdf4ccf9d94428163bfe6432c72d696b lib/core/testing.py
197197
95656c44bab1771f4808030dd6a17eae5b129cb1234443f00b19695c7b712b86 lib/core/threads.py
198198
b9aacb840310173202f79c2ba125b0243003ee6b44c92eca50424f2bdfc83c02 lib/core/unescaper.py
199199
53e396902cb2546eaa09e77073fcba8be8827ee9ce055cfc899e81b0e6ad4d6d lib/core/update.py
200200
2400e465fa4d13e4c32795910878c71ff212e4361b46428d57ce43983f5e997c lib/core/wordlist.py
201201
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/__init__.py
202202
54bfd31ebded3ffa5848df1c644f196eb704116517c7a3d860b5d081e984d821 lib/parse/banner.py
203-
8351588876a7579fa96b3ab860ef2254487de34ea624c0a7696f2428c24ceb98 lib/parse/cmdline.py
203+
541b517c9cacba2b62122c1dc2be8f2808afdc32e715983edf29998433b531bb lib/parse/cmdline.py
204204
02d82e4069bd98c52755417f8b8e306d79945672656ac24f1a45e7a6eff4b158 lib/parse/configfile.py
205205
c5b258be7485089fac9d9cd179960e774fbd85e62836dc67cce76cc028bb6aeb lib/parse/handler.py
206206
5c9a9caee948843d5537745640cc7b98d70a0412cc0949f59d4ebe8b2907c06c lib/parse/headers.py
@@ -249,6 +249,8 @@ e2cd2b19f82393f9bbc8f374686cd851a4ccc264bb898ea54547ec479a05674c lib/techniques
249249
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/techniques/union/__init__.py
250250
ceec65f8cb7c3254c4671351c837418c76ac5bc55ccbc40779f67231b54d7085 lib/techniques/union/test.py
251251
c65766f71e285fc85cdf58e7448c4c1d015af2a9dbb44fa3b665a9f13362fbcc lib/techniques/union/use.py
252+
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/techniques/xpath/__init__.py
253+
ece1fca81148ccf3c5f13b6ad7fb64966cb1ebef245216eac5cb0dd2490989db lib/techniques/xpath/inject.py
252254
aeefb42ea0c68f72744bc1bfd7194ec1bc06480d8a7e23f4b8d3d23fbba2b014 lib/utils/api.py
253255
442555ab85277aff7c9e0cf465ea5b0d28395c326f68363449b2d3941f4b6de2 lib/utils/brute.py
254256
da5bcbcda3f667582adf5db8c1b5d511b469ac61b55d387cec66de35720ed718 lib/utils/crawler.py
@@ -654,6 +656,7 @@ eca021208e388b4d14c53f1e9f8a6e7d685e54ba572fb2a8487e6b620a20bcb5 tests/test_use
654656
2364db35025a53ea4e5a0a80c034997642785f7e6d1566d0d0f1db959fe3c82e tests/test_utils.py
655657
93ef9944effc62d4f744c57bd643137c90fd92205c6a6cbe891e0e99efb80a7f tests/test_wafbypass.py
656658
81bb6d7449f224fa337734ae361c1a340bf9a51768a854d6a1a6e718ed1263ca tests/test_wordlist.py
659+
c7584cad4f99416e6415744412941f5a47b2f5284270326624bd291edf6d9994 tests/test_xpath.py
657660
55eaefc664bd8598329d535370612351ec8443c52465f0a37172ea46a97c458a thirdparty/ansistrm/ansistrm.py
658661
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 thirdparty/ansistrm/__init__.py
659662
f597b49ef445bfbfb8f98d1f1a08dcfe4810de5769c0abfab7cdce4eebbfcae7 thirdparty/beautifulsoup/beautifulsoup.py

extra/vulnserver/vulnserver.py

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,84 @@ def nosql_match(params):
217217
else: # $eq, $in (single-valued here) and any literal equality
218218
return record == value
219219

220+
# --- XPath endpoint (vulnerable search and login, backed by an in-memory XML document) ------------
221+
222+
XPATH_XML = """<?xml version="1.0" encoding="UTF-8"?>
223+
<directory>
224+
<department name="IT Operations">
225+
<user id="1">
226+
<username>luther</username>
227+
<realname>Luther Blisset</realname>
228+
<email>luther@example.com</email>
229+
<password>db3a16990a0008a3b04707fdef6584a0</password>
230+
<role>System Administrator</role>
231+
<location>London</location>
232+
<phone>+1 555 0100</phone>
233+
</user>
234+
<user id="2">
235+
<username>fluffy</username>
236+
<realname>Fluffy Bunny</realname>
237+
<email>fluffy@example.com</email>
238+
<password>4db967ce67b15e7fb84c266a76684729</password>
239+
<role>Security Engineer</role>
240+
<location>Amsterdam</location>
241+
<phone>+1 555 0102</phone>
242+
</user>
243+
<user id="3">
244+
<username>wu</username>
245+
<realname>Wu Ming</realname>
246+
<email>wu@example.com</email>
247+
<password>f5a2950eaa10f9e99896800eacbe8275</password>
248+
<role>Network Administrator</role>
249+
<location>Shanghai</location>
250+
<phone>+86 21 555 0103</phone>
251+
</user>
252+
</department>
253+
<department name="Engineering">
254+
<user id="4">
255+
<username>linus</username>
256+
<realname>Linus Torvalds</realname>
257+
<email>linus@example.com</email>
258+
<password>8e7b6a5c4d321908f7e6d5c4b3a2910f</password>
259+
<role>Kernel Developer</role>
260+
<location>Portland</location>
261+
<phone>+1 555 0200</phone>
262+
</user>
263+
<user id="5">
264+
<username>ada</username>
265+
<realname>Ada Lovelace</realname>
266+
<email>ada@example.com</email>
267+
<password>1a2b3c4d5e6f7081920a1b2c3d4e5f60</password>
268+
<role>Algorithm Designer</role>
269+
<location>London</location>
270+
<phone>+44 20 555 0201</phone>
271+
</user>
272+
</department>
273+
<department name="Management">
274+
<user id="6">
275+
<username>grace</username>
276+
<realname>Grace Hopper</realname>
277+
<email>grace@example.com</email>
278+
<password>9e8d7c6b5a493827160e9d8c7b6a5948</password>
279+
<role>CTO</role>
280+
<location>New York</location>
281+
<phone>+1 555 0300</phone>
282+
</user>
283+
</department>
284+
</directory>"""
285+
286+
def _xpath_element_to_dict(el):
287+
"""Convert an lxml element to a dict for JSON serialization."""
288+
retVal = dict(el.attrib)
289+
retVal["tag"] = el.tag
290+
retVal["text"] = (el.text or "").strip()
291+
children = []
292+
for child in el:
293+
children.append(_xpath_element_to_dict(child))
294+
if children:
295+
retVal["children"] = children
296+
return retVal
297+
220298
_conn = None
221299
_cursor = None
222300
_lock = None
@@ -889,6 +967,58 @@ def do_REQUEST(self):
889967
self.wfile.write(output.encode(UNICODE_ENCODING))
890968
return
891969

970+
if self.url == "/xpath/search":
971+
self.send_response(OK)
972+
self.send_header("Content-type", "application/json; charset=%s" % UNICODE_ENCODING)
973+
self.send_header("Connection", "close")
974+
self.end_headers()
975+
976+
q = self.params.get("q", "")
977+
entries = []
978+
error = None
979+
980+
if q:
981+
try:
982+
from lxml import etree
983+
root = etree.fromstring(XPATH_XML.encode("utf-8"))
984+
# VULNERABLE: unsanitized user input directly interpolated into XPath
985+
xpath_expr = "/directory/department/user[contains(username,'%s') or contains(realname,'%s')]" % (q, q)
986+
elements = root.xpath(xpath_expr)
987+
entries = [_xpath_element_to_dict(el) for el in elements]
988+
except Exception as ex:
989+
error = "%s: %s" % (type(ex).__name__, getUnicode(ex))
990+
991+
output = json.dumps({"entries": entries, "count": len(entries), "error": error}, default=str)
992+
self.wfile.write(output.encode(UNICODE_ENCODING))
993+
return
994+
995+
if self.url == "/xpath/login":
996+
self.send_response(OK)
997+
self.send_header("Content-type", "application/json; charset=%s" % UNICODE_ENCODING)
998+
self.send_header("Connection", "close")
999+
self.end_headers()
1000+
1001+
username = self.params.get("username", "")
1002+
password = self.params.get("password", "")
1003+
error = None
1004+
authenticated = False
1005+
1006+
if username and password:
1007+
try:
1008+
from lxml import etree
1009+
root = etree.fromstring(XPATH_XML.encode("utf-8"))
1010+
# VULNERABLE: unsanitized interpolation into XPath login expression
1011+
xpath_expr = "/directory/department/user[username='%s' and password='%s']" % (username, password)
1012+
results = root.xpath(xpath_expr)
1013+
if results:
1014+
authenticated = True
1015+
except Exception as ex:
1016+
error = "%s: %s" % (type(ex).__name__, getUnicode(ex))
1017+
1018+
output = json.dumps({"authenticated": authenticated, "error": error}, default=str)
1019+
self.wfile.write(output.encode(UNICODE_ENCODING))
1020+
return
1021+
8921022
if self.url == '/':
8931023
if not any(_ in self.params for _ in ("id", "query")):
8941024
self.send_response(OK)

lib/controller/checks.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
from lib.core.settings import HEURISTIC_CHECK_ALPHABET
8484
from lib.core.settings import INFERENCE_EQUALS_CHAR
8585
from lib.core.settings import LDAP_ERROR_REGEX
86+
from lib.core.settings import XPATH_ERROR_REGEX
8687
from lib.core.settings import IPS_WAF_CHECK_PAYLOAD
8788
from lib.core.settings import IPS_WAF_CHECK_RATIO
8889
from lib.core.settings import IPS_WAF_CHECK_TIMEOUT
@@ -1194,6 +1195,13 @@ def _(page):
11941195
if conf.beep:
11951196
beep()
11961197

1198+
if not conf.xpath and re.search(XPATH_ERROR_REGEX, page or ""):
1199+
infoMsg = "heuristic (XPath) test shows that %sparameter '%s' might be vulnerable to XPath injection (rerun with switch '--xpath')" % ("%s " % paramType if paramType != parameter else "", parameter)
1200+
logger.info(infoMsg)
1201+
1202+
if conf.beep:
1203+
beep()
1204+
11971205
kb.disableHtmlDecoding = False
11981206
kb.heuristicMode = False
11991207

lib/controller/controller.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,11 @@ def start():
543543
ldapScan()
544544
continue
545545

546+
if conf.xpath:
547+
from lib.techniques.xpath.inject import xpathScan
548+
xpathScan()
549+
continue
550+
546551
if conf.nullConnection:
547552
checkNullConnection()
548553

lib/core/optiondict.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@
120120
"technique": "string",
121121
"nosql": "boolean",
122122
"graphql": "boolean",
123+
"ldap": "boolean",
124+
"xpath": "boolean",
123125
"timeSec": "integer",
124126
"uCols": "string",
125127
"uChar": "string",

lib/core/settings.py

Lines changed: 39 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.6.188"
23+
VERSION = "1.10.6.189"
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)
@@ -977,6 +977,44 @@
977977
("vendorName", "Red Hat", "389 Directory Server"),
978978
)
979979

980+
# XPath error signatures per parser implementation for error-based detection and
981+
# fingerprinting (matched against HTTP response bodies). Each tuple is
982+
# (backend_name, regex_fragment).
983+
XPATH_ERROR_SIGNATURES = (
984+
("Java JAXP / Xalan", r"(?:javax\.xml\.(?:xpath\.XPathExpressionException|transform\.Transformer(?:Configuration)?Exception)|com\.sun\.org\.apache\.xpath\.(?:XPathException|XPathProcessorException)|org\.apache\.xpath|org\.xml\.sax\.SAX(?:Parse)?Exception)"),
985+
("Java JAXP / Xalan", r"XPath (?:expression|syntax) error"),
986+
("Java JAXP / Saxon", r"net\.sf\.saxon\.(?:trans\.XPathException|s9api\.SaxonApiException)"),
987+
("Java JAXP / Saxon", r"(?:XPST|XPTY|XPDY|XQST|XTDE)\d{4}:"),
988+
(".NET XPathNavigator", r"System\.Xml\.(?:XPath\.XPathException|XmlException)"),
989+
(".NET XPathNavigator", r"Expression must evaluate to a node-set"),
990+
(".NET XPathNavigator", r"has an invalid (?:token|qualified name)"),
991+
("lxml / libxml2", r"(?:lxml\.etree\.(?:XPath(?:Eval|Document|Syntax)?Error)|libxml2|xmlXPath(?:CompOp|Eval|Err))"),
992+
("lxml / libxml2", r"(?:XPath error|Invalid (?:expression|predicate))"),
993+
("PHP SimpleXML / DOMXPath", r"(?:SimpleXMLElement::xpath\(\)|DOMXPath::(?:query|evaluate)\(\))"),
994+
("PHP SimpleXML / DOMXPath", r"Invalid expression|xmlXPathEval"),
995+
("Saxon (standalone)", r"(?:net\.sf\.saxon\.(?:s9api\.SaxonApiException|trans\.XPathException)|Saxon error)"),
996+
("Saxon (standalone)", r"Static error\(s\) in query"),
997+
("BaseX", r"org\.basex\.(?:query\.QueryException|core\.BaseXException)"),
998+
("BaseX", r"\[(?:XPST|XPTY|XPDY)\d{4}\]"),
999+
("eXist", r"org\.exist\.xquery\.(?:XPathException|XQueryException)"),
1000+
("eXist", r"exerr:ERROR"),
1001+
("Python ElementTree", r"xml\.etree\.ElementTree\.(?:ParseError|Element)"),
1002+
("Generic XPath", r"(?:XPath|XSLT).*?(?:error|exception|syntax)"),
1003+
("Generic XPath", r"Invalid XPath|XPath evaluation failed"),
1004+
)
1005+
1006+
XPATH_ERROR_REGEX = r"(?i)(?:%s)" % '|'.join(regex for _, regex in XPATH_ERROR_SIGNATURES)
1007+
1008+
# Printable-ASCII codepoint bounds bisected during XPath blind character extraction
1009+
XPATH_CHAR_MIN = 0x20
1010+
XPATH_CHAR_MAX = 0x7e
1011+
1012+
# Maximum tree depth for recursive XML walking during XPath blind extraction
1013+
XPATH_MAX_DEPTH = 32
1014+
1015+
# Upper bound for the value-length search during XPath blind extraction
1016+
XPATH_MAX_LENGTH = 256
1017+
9801018
# Length of prefix and suffix used in non-SQLI heuristic checks
9811019
NON_SQLI_CHECK_PREFIX_SUFFIX_LENGTH = 6
9821020

lib/core/testing.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ def vulnTest():
9191
("-u \"<base>nosql?name=luther&password=x\" -p password --nosql --flush-session", ("is vulnerable to NoSQL injection", "back-end: 'MongoDB'", "NoSQL: GET parameter 'password'", "s3cr3t")), # NoSQL (MongoDB) operator-injection detection + blind regexp extraction
9292
("-u \"<base>graphql\" --graphql --flush-session --disable-hashing", ("found GraphQL endpoint", "introspection returned", "skipping 2 mutation slot", "GraphQL boolean-based blind", "in-band data exposure", "back-end DBMS: 'SQLite'", "banner: '3.", "GraphQL database tables", "fetched 30 entries from table 'creds'", "db3a16990a0008a3b04707fdef6584a0", "GraphQL scan complete")), # GraphQL: endpoint detection + introspection + mutation-skip + boolean-blind/in-band + back-end fingerprint + batched blind dump of an injection-only table (SQLite-backed)
9393
("-u \"<base>ldap/search?q=x\" --ldap --flush-session --disable-hashing", ("is vulnerable to LDAP injection", "Title: LDAP in-band data exposure", "LDAP: GET parameter 'q' in-band entries", "in-band data exposure", "LDAP scan complete")), # LDAP: error-based detection (unbalanced paren) + boolean oracle + directory attribute extraction via blind substring probing
94+
("-u \"<base>xpath/search?q=x\" --xpath --flush-session --disable-hashing", ("is vulnerable to XPath injection", "Title: XPath boolean-based blind", "XPath: GET parameter 'q' XML tree", "extracted", "XPath scan complete")), # XPath: error-based detection + boolean oracle + blind XML tree-walking via starts-with character extraction
9495
("-u \"<url>&query=*\" --flush-session --technique=Q --banner", ("Title: SQLite inline queries", "banner: '3.")),
9596
("-d \"<direct>\" --flush-session --dump -T creds --dump-format=SQLITE --binary-fields=password_hash --where \"user_id=5\"", ("3137396164343563366365326362393763663130323965323132303436653831", "dumped to SQLITE database")),
9697
("-d \"<direct>\" --flush-session --banner --schema --sql-query=\"UPDATE users SET name='foobar' WHERE id=4; SELECT * FROM users; SELECT 987654321\"", ("banner: '3.", "INTEGER", "TEXT", "id", "name", "surname", "4,foobar,nameisnull", "'987654321'",)),

lib/parse/cmdline.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,9 @@ def cmdLineParser(argv=None):
424424
techniques.add_argument("--ldap", dest="ldap", action="store_true",
425425
help="Test for LDAP injection (filter breakout, boolean blind, auth bypass)")
426426

427+
techniques.add_argument("--xpath", dest="xpath", action="store_true",
428+
help="Test for XPath injection (error-based, boolean-blind, blind XML tree-walking)")
429+
427430
techniques.add_argument("--time-sec", dest="timeSec", type=int,
428431
help="Seconds to delay the DBMS response (default %d)" % defaults.timeSec)
429432

lib/techniques/xpath/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/usr/bin/env python
2+
3+
"""
4+
Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
5+
See the file 'LICENSE' for copying permission
6+
"""
7+
8+
pass

0 commit comments

Comments
 (0)