Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,14 @@ jobs:
- name: Basic import test
run: python -c "import sqlmap; import sqlmapapi"

- name: Install optional test deps (lxml, jinja2)
# lxml has no PyPy-2.7 wheel and 5.x is Py3-only, so it cannot be pip-installed there. The
# tests that use it (test_xpath's real-XPath checks, and the --xpath/--ssti vuln-test
# endpoints) skip themselves when the engine is unavailable, so these deps are only needed
# on the Py3 jobs.
if: matrix.python-version != 'pypy-2.7'
run: python -m pip install -q lxml jinja2

- name: Unit tests
# -B: do not write .pyc files. On Python 2 / PyPy a cached .pyc makes a module's __file__
# point at the .pyc, which would make the later --smoke getFileType(__file__) doctest see
Expand Down
34 changes: 20 additions & 14 deletions data/txt/sha256sums.txt
Original file line number Diff line number Diff line change
Expand Up @@ -160,10 +160,10 @@ ca86d61d3349ed2d94a6b164d4648cff9701199b5e32378c3f40fca0f517b128 extra/shutils/
df768bcb9838dc6c46dab9b4a877056cb4742bd6cfaaf438c4a3712c5cc0d264 extra/shutils/recloak.sh
1972990a67caf2d0231eacf60e211acf545d9d0beeb3c145a49ba33d5d491b3f extra/shutils/strip.sh
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 extra/vulnserver/__init__.py
32577fc21a6170266438b608ed81620e0b0a889aa8a05124bc7f0905cba772a6 extra/vulnserver/vulnserver.py
617cec1b731e0baacafa6f58c2f56a85b6128d1416627cc1b2f61519c8539a2e extra/vulnserver/vulnserver.py
a2bf70d7f87c3a4e0675c0bad54119a4e04efa6ea2730a8338d5aebcd995630e lib/controller/action.py
c9a1661fc6719655e1e5b6dd72caab680766690c5f746b386093267329f7b3b8 lib/controller/checks.py
256ba0c6967121dc25c95fe09d1165dd8d0530f26c7879e6036f649fb0a6de95 lib/controller/controller.py
9137a8f7368496c84b21944f6b94c28004d3a2a849ac9c8e0b20e294e4c4a93a lib/controller/checks.py
4598de22ed3df63432e9643ba48533a01bec9f0b253c3a11f322ccedaef353f0 lib/controller/controller.py
d69e84f1648cdb907f5d2dd454f03874a4613752b07867510145d51d84b3c56f lib/controller/handler.py
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/controller/__init__.py
9c5764c92ce536d1f0f96200359ee5ef1f37f9128769bf990cb77f1d1f8e17b1 lib/core/agent.py
Expand All @@ -181,26 +181,26 @@ f8de57606325456928e46ae2896f5f8bbec9ad18b1c644b492a566fa992216f6 lib/core/decor
5387168e5dfedd94ae22af7bb255f27d6baaca50b24179c6b98f4f325f5cc7b4 lib/core/exception.py
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/core/__init__.py
914a13ee21fd610a6153a37cbe50830fcbd1324c7ebc1e7fc206d5e598b0f7ad lib/core/log.py
1b03686e1aa916ccad3cd86b8e4e6ea4baca5e30e05bf86a56f8df8dd4f44ba6 lib/core/optiondict.py
33ed53b263fa766a808be6797dd812822bb115d3b9db6e3a34763f500f5359e8 lib/core/optiondict.py
e033b20a0f7821797a10f4bf4235723f38c7db551c611fbb713faa621b123c4a lib/core/option.py
21b2b1745107c211fc7593923a3da7a808d40763c00091c28de5f7c129bcf3bc lib/core/patch.py
49c0fa7e3814dfda610d665ee02b12df299b28bc0b6773815b4395514ddf8dec lib/core/profiling.py
0c36a65b6237732eb001d333f80f0c58c088ff01ae80cf07e4dcc6da2a806364 lib/core/readlineng.py
9bf174058f15d14e24e94f9aaf42df045119d3617c6c54bd2f3af79b462f331d lib/core/replication.py
0b8c38a01bb01f843d94a6c5f2075ee47520d0c4aa799cecea9c3e2c5a4a23a6 lib/core/revision.py
888daba83fd4a34e9503fe21f01fef4cc730e5cde871b1d40e15d4cbc847d56c lib/core/session.py
e9aae7dacf83a4d7054862eeb0a96ed695731cd87f8b03836a8a41c7454d0f5f lib/core/settings.py
0a99ba2412606979d02c25ab63d0d92bfe3f2a262d6405a740841f5df83970ba lib/core/settings.py
c7804223319e18eb0b8e2cbf0a8b6896d1cefb7b0b1a2e9f1cf826a8a3b56750 lib/core/shell.py
a2e98a94b231432736d6b304fc75525c8b5fdb4768c418387c5b4c1a610dad64 lib/core/subprocessng.py
19f1e3c5e3ba703d28d510cd7a9ab8284d5fbe9df5ce7e77c86e5931571364b7 lib/core/target.py
46b405d0e0e035b3f323deffc1f1d30505adf7c01144ea2ddf81c5dc6caaa20f lib/core/testing.py
073cc21334519624288bbf25060ab4e8102cbe6ec15e706992e639716075af8d lib/core/testing.py
95656c44bab1771f4808030dd6a17eae5b129cb1234443f00b19695c7b712b86 lib/core/threads.py
b9aacb840310173202f79c2ba125b0243003ee6b44c92eca50424f2bdfc83c02 lib/core/unescaper.py
53e396902cb2546eaa09e77073fcba8be8827ee9ce055cfc899e81b0e6ad4d6d lib/core/update.py
2400e465fa4d13e4c32795910878c71ff212e4361b46428d57ce43983f5e997c lib/core/wordlist.py
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/__init__.py
54bfd31ebded3ffa5848df1c644f196eb704116517c7a3d860b5d081e984d821 lib/parse/banner.py
8351588876a7579fa96b3ab860ef2254487de34ea624c0a7696f2428c24ceb98 lib/parse/cmdline.py
316cdcb3d8d839dab639ed7eb4935780375d49c93371edbd6224976cbb968c2e lib/parse/cmdline.py
02d82e4069bd98c52755417f8b8e306d79945672656ac24f1a45e7a6eff4b158 lib/parse/configfile.py
c5b258be7485089fac9d9cd179960e774fbd85e62836dc67cce76cc028bb6aeb lib/parse/handler.py
5c9a9caee948843d5537745640cc7b98d70a0412cc0949f59d4ebe8b2907c06c lib/parse/headers.py
Expand Down Expand Up @@ -240,15 +240,19 @@ a66a4b9df6207dce722c9b71d290ea426723cb4b697b416065dc7dd5db96fe8e lib/techniques
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/techniques/error/__init__.py
5bbef46c16e34fd80e3f9f0e9aa255ce2e39be0d0e57479e25890b041c7efc7d lib/techniques/error/use.py
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/techniques/graphql/__init__.py
ffbc7583a563bb9fe5a560ca8363f3e4ec84ecf907b956883ab1f2904f19d529 lib/techniques/graphql/inject.py
c3e5cf7e5e35ae5fd86b63a515b37e6f06e61c70d2690252f2ee8373aa16637e lib/techniques/graphql/inject.py
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/techniques/__init__.py
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/techniques/ldap/__init__.py
cc90c641d74244e45fa0c8c4026315452137e66b6fb5cef681d0eacd4e11eb69 lib/techniques/ldap/inject.py
039d64a610b0e92e953fa6eaa740e7c2867e34e12b82e0113204e8f6100dc368 lib/techniques/ldap/inject.py
44401cad3e39ae9fb899ed5d0e2fdd0879561de05c3117f17f3b0db54f4e3724 lib/techniques/nosql/__init__.py
e2cd2b19f82393f9bbc8f374686cd851a4ccc264bb898ea54547ec479a05674c lib/techniques/nosql/inject.py
e465d9cb6ac83dafe38aeec851856183b93f5aa19f628fb64371a290797e2518 lib/techniques/nosql/inject.py
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/techniques/ssti/__init__.py
29ab841b6129106f19db692a5a30f90a5e758d6cd24d47da0a35c8090910ae18 lib/techniques/ssti/inject.py
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/techniques/union/__init__.py
ceec65f8cb7c3254c4671351c837418c76ac5bc55ccbc40779f67231b54d7085 lib/techniques/union/test.py
c65766f71e285fc85cdf58e7448c4c1d015af2a9dbb44fa3b665a9f13362fbcc lib/techniques/union/use.py
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/techniques/xpath/__init__.py
c61816c9dba9f6cc2223aed1a923f95130979e5f0a88ec254ee667d955ed2734 lib/techniques/xpath/inject.py
aeefb42ea0c68f72744bc1bfd7194ec1bc06480d8a7e23f4b8d3d23fbba2b014 lib/utils/api.py
442555ab85277aff7c9e0cf465ea5b0d28395c326f68363449b2d3941f4b6de2 lib/utils/brute.py
da5bcbcda3f667582adf5db8c1b5d511b469ac61b55d387cec66de35720ed718 lib/utils/crawler.py
Expand Down Expand Up @@ -584,7 +588,7 @@ d16977d057c28888aa41500f79a19789cadef693cb8b7d9a3bca55b983ce2266 tests/test_age
feb763ddcbf4f32822372ca53f8c71c754af7b72510ef06e1e9c77927fc90b10 tests/test_bigarray.py
36bcb68483d824db5d05870fab62f1907221bf256826b734302fbc15a9231c42 tests/test_brute.py
27ad87c0ea377e0657bd6f6a4eaa0e9756aa9d28ec0483bdadeb3f66dcc4660d tests/test_charset.py
c99b77cc5d85334f147a1a6d4b2867af396f70e9f2609f8587344e084910e893 tests/test_checks.py
7596fc69678304923b5c945c0fd9b8ee62a2dfc7fb14ccb6dc7af30893dc8012 tests/test_checks.py
9e678a56e16211c49ab4995b6c658d3f122bfa3b357d9e17ff38f5a489ace6ad tests/test_cloak.py
2ec894f49ca9bd750a23ead16dae176bcbc57d18ec5847fa4a5eeb886d75c1bd tests/test_common_helpers.py
cdacb37cbe5667fded00abe62a822e11c917e9cb5c3f664b7aa1a8d738412ed4 tests/test_common.py
Expand All @@ -611,10 +615,10 @@ bb6991260a994fcbe79e05febaa34affd5631d02299fbc626820addd5f6ea4f4 tests/test_err
26730151abea598f193131c5d64ef92b531941972f3d6236f9951c3116030b1c tests/test_filesystem.py
16fba97cba6afe8af11aa30bcc4266f53b00f2530161e010af10b51db1509703 tests/test_fingerprint.py
20844dfc758e99b2f757906c51ef32aca0f699283ec5aa629158d3dc0fd279ea tests/test_generic_takeover.py
bde97a4781c4ee84e0fe86f7a33206f114167eb14b704013ecf1c26b838193d7 tests/test_graphql.py
f1f38f8b8ca667caadcb027d1a20eb895be4ef0935511114db235e66903bb463 tests/test_graphql.py
50b71422ee91b9a4864f4d5ce6c9bdf169dc5f57ed1db05c152eb010c282136b tests/test_gui_helpers.py
92648f2fe81e22c5726b198bbbda14961cd4d3294a0d9139dcea808b324142ac tests/test_har.py
70919c6ee8fbb3d619873489c819fa37d9035beb2e9b658cc5aa531d86a40380 tests/test_hash_crack.py
cc7677bc6c568c395112c1aa7d01e1d664e4d5940c86cb4d44987172864bae6f tests/test_hash_crack.py
0336c875dd2b6554bff6eafd746229e38c69ca8070cd933d45cf27c82ef3e05f tests/test_hashdb.py
c04e8358fb6df45f69f2f26435c971acde280535bf304e84d30cf2681158c6a7 tests/test_hash.py
d539d0ae758b5bb91e314ab82ab4fe03d6fb2f8b377d16aefa6d7d1d77a7d5a9 tests/test_identifiers_output.py
Expand All @@ -639,6 +643,7 @@ cec98d72992c0799229a780fa7f0d7f3fb01ec2d708187ce0e4a05c8612f291b tests/test_saf
a1c6cda1e5b483f61e6a4f8ddd0b06a15ddaa3fd2119bfb9dbd9cc970d7a751d tests/test_settings_regex.py
29d0278e3718b0fee422d3f6bb85ca02560138d48cd76f9fe1f35ac19d96071b tests/test_sgmllib.py
d3d991331096e16e5019de3d652e9fff92c09bd9f97c50b1c2c3ceb0ed49b17e tests/test_sqlparse.py
4a9409a070770cc6300ed2b0c954254273479252fa602ffd19d78917f895756c tests/test_ssti.py
8bcbf1091134dd0a62f6201f8b3645ed87b5ff2f7ba40a87231a29dac412591f tests/test_strings.py
8f1c5f0f337ecd26d35c5551060034e0aa33a62cce5385fc1227fdc485f6383e tests/test_tamper.py
67472bd71c20782cc0f738e2c2e674c29d6985669e14d15b69baef7d0e33de62 tests/test_target_parsing.py
Expand All @@ -650,10 +655,11 @@ f49bcce1df533ffa1acfd02af43faf6687b21eebda9362ceb1e5871b8cb37fd4 tests/test_thr
48b0ae4abe0fdde8ce4975c5cbf4c3514a2815021cb2e3a490a189bea5edfe78 tests/test_unpickle_security.py
4b646f513c6da1e33200184ed6eabe0aa345eb2e2a19598dc123e191168591bf tests/test_urls.py
eca021208e388b4d14c53f1e9f8a6e7d685e54ba572fb2a8487e6b620a20bcb5 tests/test_users_enum.py
23ffd75b5aec33066e6d6aad01ab2c9c1b12ee20c1a0990f8f1be81f1ad16161 tests/_testutils.py
045f05f958100adc883b3f56613c5f8002dd19d0752225397a1f771775cb2779 tests/_testutils.py
2364db35025a53ea4e5a0a80c034997642785f7e6d1566d0d0f1db959fe3c82e tests/test_utils.py
93ef9944effc62d4f744c57bd643137c90fd92205c6a6cbe891e0e99efb80a7f tests/test_wafbypass.py
81bb6d7449f224fa337734ae361c1a340bf9a51768a854d6a1a6e718ed1263ca tests/test_wordlist.py
2698060e7f001e054e345512ce95be458d9902b913afa769398b53145475738a tests/test_xpath.py
55eaefc664bd8598329d535370612351ec8443c52465f0a37172ea46a97c458a thirdparty/ansistrm/ansistrm.py
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 thirdparty/ansistrm/__init__.py
f597b49ef445bfbfb8f98d1f1a08dcfe4810de5769c0abfab7cdce4eebbfcae7 thirdparty/beautifulsoup/beautifulsoup.py
Expand Down
155 changes: 155 additions & 0 deletions extra/vulnserver/vulnserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,84 @@ def nosql_match(params):
else: # $eq, $in (single-valued here) and any literal equality
return record == value

# --- XPath endpoint (vulnerable search and login, backed by an in-memory XML document) ------------

XPATH_XML = """<?xml version="1.0" encoding="UTF-8"?>
<directory>
<department name="IT Operations">
<user id="1">
<username>luther</username>
<realname>Luther Blisset</realname>
<email>luther@example.com</email>
<password>db3a16990a0008a3b04707fdef6584a0</password>
<role>System Administrator</role>
<location>London</location>
<phone>+1 555 0100</phone>
</user>
<user id="2">
<username>fluffy</username>
<realname>Fluffy Bunny</realname>
<email>fluffy@example.com</email>
<password>4db967ce67b15e7fb84c266a76684729</password>
<role>Security Engineer</role>
<location>Amsterdam</location>
<phone>+1 555 0102</phone>
</user>
<user id="3">
<username>wu</username>
<realname>Wu Ming</realname>
<email>wu@example.com</email>
<password>f5a2950eaa10f9e99896800eacbe8275</password>
<role>Network Administrator</role>
<location>Shanghai</location>
<phone>+86 21 555 0103</phone>
</user>
</department>
<department name="Engineering">
<user id="4">
<username>linus</username>
<realname>Linus Torvalds</realname>
<email>linus@example.com</email>
<password>8e7b6a5c4d321908f7e6d5c4b3a2910f</password>
<role>Kernel Developer</role>
<location>Portland</location>
<phone>+1 555 0200</phone>
</user>
<user id="5">
<username>ada</username>
<realname>Ada Lovelace</realname>
<email>ada@example.com</email>
<password>1a2b3c4d5e6f7081920a1b2c3d4e5f60</password>
<role>Algorithm Designer</role>
<location>London</location>
<phone>+44 20 555 0201</phone>
</user>
</department>
<department name="Management">
<user id="6">
<username>grace</username>
<realname>Grace Hopper</realname>
<email>grace@example.com</email>
<password>9e8d7c6b5a493827160e9d8c7b6a5948</password>
<role>CTO</role>
<location>New York</location>
<phone>+1 555 0300</phone>
</user>
</department>
</directory>"""

def _xpath_element_to_dict(el):
"""Convert an lxml element to a dict for JSON serialization."""
retVal = dict(el.attrib)
retVal["tag"] = el.tag
retVal["text"] = (el.text or "").strip()
children = []
for child in el:
children.append(_xpath_element_to_dict(child))
if children:
retVal["children"] = children
return retVal

_conn = None
_cursor = None
_lock = None
Expand Down Expand Up @@ -889,6 +967,83 @@ def do_REQUEST(self):
self.wfile.write(output.encode(UNICODE_ENCODING))
return

if self.url == "/xpath/search":
self.send_response(OK)
self.send_header("Content-type", "application/json; charset=%s" % UNICODE_ENCODING)
self.send_header("Connection", "close")
self.end_headers()

q = self.params.get("q", "")
entries = []
error = None

if q:
try:
from lxml import etree
root = etree.fromstring(XPATH_XML.encode("utf-8"))
# VULNERABLE: unsanitized user input directly interpolated into XPath
xpath_expr = "/directory/department/user[contains(username,'%s') or contains(realname,'%s')]" % (q, q)
elements = root.xpath(xpath_expr)
entries = [_xpath_element_to_dict(el) for el in elements]
except Exception as ex:
error = "%s: %s" % (type(ex).__name__, str(ex))

output = json.dumps({"entries": entries, "count": len(entries), "error": error}, default=str)
self.wfile.write(output.encode(UNICODE_ENCODING))
return

if self.url == "/xpath/login":
self.send_response(OK)
self.send_header("Content-type", "application/json; charset=%s" % UNICODE_ENCODING)
self.send_header("Connection", "close")
self.end_headers()

username = self.params.get("username", "")
password = self.params.get("password", "")
error = None
authenticated = False

if username and password:
try:
from lxml import etree
root = etree.fromstring(XPATH_XML.encode("utf-8"))
# VULNERABLE: unsanitized interpolation into XPath login expression
xpath_expr = "/directory/department/user[username='%s' and password='%s']" % (username, password)
results = root.xpath(xpath_expr)
if results:
authenticated = True
except Exception as ex:
error = "%s: %s" % (type(ex).__name__, str(ex))

output = json.dumps({"authenticated": authenticated, "error": error}, default=str)
self.wfile.write(output.encode(UNICODE_ENCODING))
return

if self.url == "/ssti/search":
self.send_response(OK)
self.send_header("Content-type", "text/html; charset=%s" % UNICODE_ENCODING)
self.send_header("Connection", "close")
self.end_headers()

q = self.params.get("q", "")
output = "<html><body>"

if q:
try:
from jinja2 import Template
# VULNERABLE: unsanitized user input passed to Jinja2 template engine
template = Template("Hello " + q)
output += template.render()
except Exception as ex:
# Leak template engine error for error-based detection
output += "<b>%s: %s</b>" % (type(ex).__name__, str(ex))
else:
output += "Hello"

output += "</body></html>"
self.wfile.write(output.encode(UNICODE_ENCODING))
return

if self.url == '/':
if not any(_ in self.params for _ in ("id", "query")):
self.send_response(OK)
Expand Down
16 changes: 16 additions & 0 deletions lib/controller/checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@
from lib.core.settings import HEURISTIC_CHECK_ALPHABET
from lib.core.settings import INFERENCE_EQUALS_CHAR
from lib.core.settings import LDAP_ERROR_REGEX
from lib.core.settings import SSTI_ERROR_REGEX
from lib.core.settings import XPATH_ERROR_REGEX
from lib.core.settings import IPS_WAF_CHECK_PAYLOAD
from lib.core.settings import IPS_WAF_CHECK_RATIO
from lib.core.settings import IPS_WAF_CHECK_TIMEOUT
Expand Down Expand Up @@ -1194,6 +1196,20 @@ def _(page):
if conf.beep:
beep()

if not conf.xpath and re.search(XPATH_ERROR_REGEX, page or ""):
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)
logger.info(infoMsg)

if conf.beep:
beep()

if not conf.ssti and re.search(SSTI_ERROR_REGEX, page or ""):
infoMsg = "heuristic (SSTI) test shows that %sparameter '%s' might be vulnerable to server-side template injection (rerun with switch '--ssti')" % ("%s " % paramType if paramType != parameter else "", parameter)
logger.info(infoMsg)

if conf.beep:
beep()

kb.disableHtmlDecoding = False
kb.heuristicMode = False

Expand Down
10 changes: 10 additions & 0 deletions lib/controller/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,16 @@ def start():
ldapScan()
continue

if conf.xpath:
from lib.techniques.xpath.inject import xpathScan
xpathScan()
continue

if conf.ssti:
from lib.techniques.ssti.inject import sstiScan
sstiScan()
continue

if conf.nullConnection:
checkNullConnection()

Expand Down
5 changes: 5 additions & 0 deletions lib/core/optiondict.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@
"technique": "string",
"nosql": "boolean",
"graphql": "boolean",
"ldap": "boolean",
"xpath": "boolean",
"ssti": "boolean",
"timeSec": "integer",
"uCols": "string",
"uChar": "string",
Expand Down Expand Up @@ -170,6 +173,8 @@
"lastChar": "integer",
"sqlQuery": "string",
"sqlShell": "boolean",
"sstiQuery": "string",
"sstiShell": "boolean",
"sqlFile": "string",
},

Expand Down
Loading