Compare commits

..

31 Commits

Author SHA1 Message Date
Miroslav Stampar
33a6547f5b Fixes #5252 2022-12-06 11:55:03 +01:00
Miroslav Stampar
ad529f24cb Minor update 2022-11-29 15:12:18 +01:00
Miroslav Stampar
3d2f89345f Fixes #5242 2022-11-29 15:05:34 +01:00
Miroslav Stampar
58f10093a0 Minor update 2022-11-29 14:48:20 +01:00
Miroslav Stampar
6aaf7d3960 Fixes #5240 2022-11-22 00:28:20 +01:00
Miroslav Stampar
b8fa0edea6 Fixes #5232 2022-11-21 00:37:48 +01:00
Miroslav Stampar
55b2b43f0e Fixes #5233 2022-11-21 00:20:05 +01:00
Miroslav Stampar
7bc0b08fd6 Implementing option '--dump-file' (#5238) 2022-11-21 00:03:36 +01:00
Miroslav Stampar
62bba470d6 Fixes #5220 2022-11-02 10:49:09 +01:00
Miroslav Stampar
eda669e10b Fixes #5216 2022-11-01 23:26:15 +01:00
Fabian Ising
c382321134 Better handling of CookieJar Runtime Exception (#5206)
Fixes #5187
2022-10-21 19:10:43 +02:00
Miroslav Stampar
2ace4ef471 Implements tamper script 'scientific' (#5205) 2022-10-21 19:07:20 +02:00
Miroslav Stampar
02dcf2a926 Fixes #5203 2022-10-17 12:21:56 +02:00
CrazyKidJack
5c55602296 Fix --cookie-del (cookieDel) error checking (#5198)
error checking was checking if len(conf.cookieDel) which always returns true when option is used. Now it checks if len(conf.cookieDel) != 1
2022-10-17 11:59:17 +02:00
Miroslav Stampar
aa9cc3987e Implements option --csrf-data (#5199) 2022-10-17 11:52:22 +02:00
Miroslav Stampar
d7ee423fc5 Fixes #5202 2022-10-17 11:35:58 +02:00
Miroslav Stampar
1092dfb877 Patch related to the #5192 2022-10-12 11:27:11 +02:00
Miroslav Stampar
bf4f84b70a Fixes #5191 2022-10-12 11:13:59 +02:00
Miroslav Stampar
c45cf60fb4 Minor update of fingerprinting data 2022-10-07 20:55:49 +02:00
Miroslav Stampar
3f53b2bc05 Fixes #5190 2022-10-07 20:12:12 +02:00
Miroslav Stampar
9c103b3dd6 Fixes #5187 2022-10-06 11:50:35 +02:00
Víctor García
7f62572f43 Add files via upload (#5189) 2022-10-06 11:32:31 +02:00
Miroslav Stampar
e846209b87 Update regarding #5092 2022-09-25 16:34:40 +02:00
Miroslav Stampar
a246b8da5e Fixes #5182 2022-09-25 16:02:48 +02:00
Miroslav Stampar
70665c5d2b Improvement regarding #5171 2022-09-13 22:59:34 +02:00
Hoomaan
111620e395 Fixing grammar issues of FA readme (#5172) 2022-09-13 22:24:22 +02:00
Miroslav Stampar
2382d2654e Fixes #5170 2022-09-06 13:00:47 +02:00
Miroslav Stampar
4cdc3af585 Fixes #5165 2022-08-26 20:34:11 +02:00
Miroslav Stampar
212f28d1ad Fixes --check-tor (reported privately) 2022-08-22 16:25:55 +02:00
Miroslav Stampar
e1f7690de4 Fixes #5162 2022-08-10 14:51:35 +02:00
Miroslav Stampar
7e425d4c9b Fixes #5154 2022-08-04 09:20:52 +02:00
28 changed files with 238 additions and 80 deletions

View File

@@ -34,7 +34,7 @@
<!-- Reference: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724832%28v=vs.85%29.aspx --> <!-- Reference: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724832%28v=vs.85%29.aspx -->
<regexp value="Windows.*\b10\.0"> <regexp value="Windows.*\b10\.0">
<info type="Windows" distrib="2016|2019|10|11"/> <info type="Windows" distrib="2016|2019|2022|10|11"/>
</regexp> </regexp>
<regexp value="Windows.*\b6\.3"> <regexp value="Windows.*\b6\.3">

View File

@@ -10,7 +10,7 @@
<!-- Microsoft IIS --> <!-- Microsoft IIS -->
<regexp value="Microsoft-IIS/(10\.0)"> <regexp value="Microsoft-IIS/(10\.0)">
<info technology="Microsoft IIS" tech_version="1" type="Windows" distrib="2019|2016|10"/> <info technology="Microsoft IIS" tech_version="1" type="Windows" distrib="2016|2019|2022|10|11"/>
</regexp> </regexp>
<regexp value="Microsoft-IIS/(8\.5)"> <regexp value="Microsoft-IIS/(8\.5)">
@@ -878,7 +878,11 @@
</regexp> </regexp>
<regexp value="Apache/2\.4\.46 \(Ubuntu\)"> <regexp value="Apache/2\.4\.46 \(Ubuntu\)">
<info type="Linux" distrib="Ubuntu" release="21.04|21.10" codename="eoan|focal"/> <info type="Linux" distrib="Ubuntu" release="21.04|21.10" codename="hirsute|impish"/>
</regexp>
<regexp value="Apache/2\.4\.52 \(Ubuntu\)">
<info type="Linux" distrib="Ubuntu" release="22.04" codename="jammy"/>
</regexp> </regexp>
<!-- Nginx --> <!-- Nginx -->

View File

@@ -7,10 +7,10 @@
برنامه `sqlmap`، برنامه‌ی منبع باز هست که برای تست نفوذ پذیزی دربرابر حمله‌های احتمالی `sql injection` (جلوگیری از لو رفتن پایگاه داده) جلو گیری می‌کند. این برنامه مجهز به مکانیزیم تشخیص قدرتمندی می‌باشد. همچنین داری طیف گسترده‌ای از اسکریپت ها می‌باشد که برای متخصص تست نفوذ کار کردن با بانک اطلاعاتی را راحتر می‌کند. از جمع اوری اطلاعات درباره بانک داده تا دسترسی به داده های سیستم و اجرا دستورات از طریق `via out-of-band` درسیستم عامل را امکان پذیر می‌کند. برنامه `sqlmap`، یک برنامه‌ی تست نفوذ منبع باز است که فرآیند تشخیص و اکسپلویت پایگاه های داده با مشکل امنیتی SQL Injection را بطور خودکار انجام می دهد. این برنامه مجهز به موتور تشخیص قدرتمندی می‌باشد. همچنین داری طیف گسترده‌ای از اسکریپت ها می‌باشد که برای متخصصان تست نفوذ کار کردن با بانک اطلاعاتی را راحتر می‌کند. از جمع اوری اطلاعات درباره بانک داده تا دسترسی به داده های سیستم و اجرا دستورات از طریق ارتباط Out Of Band درسیستم عامل را امکان پذیر می‌کند.
عکس تصویر محیط ابزار
---- ----
@@ -23,7 +23,7 @@
<div dir=rtl> <div dir=rtl>
برای دیدن کردن از [مجموعهی از اسکریپت‌ها](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) می‌توانید از ویکی دیدن کنید. برای نمایش [مجموعه ای از اسکریپت‌ها](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) می‌توانید از دانشنامه دیدن کنید.
نصب نصب
@@ -32,11 +32,11 @@
برای دانلود اخرین نسخه tarball، با کلیک در [اینجا](https://github.com/sqlmapproject/sqlmap/tarball/master) یا دانلود اخرین نسخه zipball با کلیک در [اینجا](https://github.com/sqlmapproject/sqlmap/zipball/master) میتوانید این کار را انجام دهید. برای دانلود اخرین نسخه tarball، با کلیک در [اینجا](https://github.com/sqlmapproject/sqlmap/tarball/master) یا دانلود اخرین نسخه zipball با کلیک در [اینجا](https://github.com/sqlmapproject/sqlmap/zipball/master) میتوانید این کار را انجام دهید.
طرز استفاده نحوه استفاده
---- ----
برای گرفتن لیست ارگومان‌های اساسی می‌توانید از دستور زیر استفاده کنید: برای دریافت لیست ارگومان‌های اساسی می‌توانید از دستور زیر استفاده کنید:
@@ -53,7 +53,7 @@
<div dir=rtl> <div dir=rtl>
برای گرفتن لیست تمامی ارگومان‌های می‌توانید از دستور زیر استفاده کنید: برای دریافت لیست تمامی ارگومان‌ها می‌توانید از دستور زیر استفاده کنید:
<div dir=ltr> <div dir=ltr>
@@ -66,7 +66,7 @@
<div dir=rtl> <div dir=rtl>
برای اطلاعات بیشتر برای اجرا از [اینجا](https://asciinema.org/a/46601) می‌توانید استفاده کنید. برای گرفتن اطلاعات بیشتر توسعه می‌شود به [راهنمای](https://github.com/sqlmapproject/sqlmap/wiki/Usage) `sqlmap` سر بزنید. برای اجرای سریع و ساده ابزار می توانید از [اینجا](https://asciinema.org/a/46601) استفاده کنید. برای دریافت اطلاعات بیشتر در رابطه با قابلیت ها ، امکانات قابل پشتیبانی و لیست کامل امکانات و دستورات همراه با مثال می‌ توانید به [راهنمای](https://github.com/sqlmapproject/sqlmap/wiki/Usage) `sqlmap` سر بزنید.
لینک‌ها لینک‌ها
@@ -74,11 +74,11 @@
* خانه: https://sqlmap.org * خانه: https://sqlmap.org
* دانلود: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) or [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) * دانلود: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) یا [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master)
* کایمت و نظرات: https://github.com/sqlmapproject/sqlmap/commits/master.atom * نظرات: https://github.com/sqlmapproject/sqlmap/commits/master.atom
* پیگری مشکلات: https://github.com/sqlmapproject/sqlmap/issues * پیگیری مشکلات: https://github.com/sqlmapproject/sqlmap/issues
* راهنمای کاربران: https://github.com/sqlmapproject/sqlmap/wiki * راهنمای کاربران: https://github.com/sqlmapproject/sqlmap/wiki
* سوالات متداول: https://github.com/sqlmapproject/sqlmap/wiki/FAQ * سوالات متداول: https://github.com/sqlmapproject/sqlmap/wiki/FAQ
* تویتر: [@sqlmap](https://twitter.com/sqlmap) * توییتر: [@sqlmap](https://twitter.com/sqlmap)
* رسانه: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos) * رسانه: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos)
* عکس‌ها: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots * تصاویر: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots

View File

@@ -10,7 +10,6 @@ import logging
import random import random
import re import re
import socket import socket
import subprocess
import time import time
from extra.beep.beep import beep from extra.beep.beep import beep
@@ -271,15 +270,18 @@ def checkSqlInjection(place, parameter, value):
logger.debug(debugMsg) logger.debug(debugMsg)
continue continue
if kb.dbmsFilter and not intersect(payloadDbms, kb.dbmsFilter, True): elif kb.dbmsFilter and not intersect(payloadDbms, kb.dbmsFilter, True):
debugMsg = "skipping test '%s' because " % title debugMsg = "skipping test '%s' because " % title
debugMsg += "its declared DBMS is different than provided" debugMsg += "its declared DBMS is different than provided"
logger.debug(debugMsg) logger.debug(debugMsg)
continue continue
elif kb.reduceTests == False:
pass
# Skip DBMS-specific test if it does not match the # Skip DBMS-specific test if it does not match the
# previously identified DBMS (via DBMS-specific payload) # previously identified DBMS (via DBMS-specific payload)
if injection.dbms and not intersect(payloadDbms, injection.dbms, True): elif injection.dbms and not intersect(payloadDbms, injection.dbms, True):
debugMsg = "skipping test '%s' because " % title debugMsg = "skipping test '%s' because " % title
debugMsg += "its declared DBMS is different than identified" debugMsg += "its declared DBMS is different than identified"
logger.debug(debugMsg) logger.debug(debugMsg)
@@ -287,7 +289,7 @@ def checkSqlInjection(place, parameter, value):
# Skip DBMS-specific test if it does not match the # Skip DBMS-specific test if it does not match the
# previously identified DBMS (via DBMS-specific error message) # previously identified DBMS (via DBMS-specific error message)
if kb.reduceTests and not intersect(payloadDbms, kb.reduceTests, True): elif kb.reduceTests and not intersect(payloadDbms, kb.reduceTests, True):
debugMsg = "skipping test '%s' because the heuristic " % title debugMsg = "skipping test '%s' because the heuristic " % title
debugMsg += "tests showed that the back-end DBMS " debugMsg += "tests showed that the back-end DBMS "
debugMsg += "could be '%s'" % unArrayizeValue(kb.reduceTests) debugMsg += "could be '%s'" % unArrayizeValue(kb.reduceTests)
@@ -780,22 +782,8 @@ def checkSqlInjection(place, parameter, value):
injection.conf.regexp = conf.regexp injection.conf.regexp = conf.regexp
injection.conf.optimize = conf.optimize injection.conf.optimize = conf.optimize
if not kb.alerted: if conf.beep:
if conf.beep: beep()
beep()
if conf.alert:
infoMsg = "executing alerting shell command(s) ('%s')" % conf.alert
logger.info(infoMsg)
try:
process = subprocess.Popen(conf.alert, shell=True)
process.wait()
except Exception as ex:
errMsg = "error occurred while executing '%s' ('%s')" % (conf.alert, getSafeExString(ex))
logger.error(errMsg)
kb.alerted = True
# There is no need to perform this test for other # There is no need to perform this test for other
# <where> tags # <where> tags
@@ -856,10 +844,8 @@ def checkSqlInjection(place, parameter, value):
if not checkFalsePositives(injection): if not checkFalsePositives(injection):
if conf.hostname in kb.vulnHosts: if conf.hostname in kb.vulnHosts:
kb.vulnHosts.remove(conf.hostname) kb.vulnHosts.remove(conf.hostname)
if NOTE.FALSE_POSITIVE_OR_UNEXPLOITABLE not in injection.notes: if NOTE.FALSE_POSITIVE_OR_UNEXPLOITABLE not in injection.notes:
injection.notes.append(NOTE.FALSE_POSITIVE_OR_UNEXPLOITABLE) injection.notes.append(NOTE.FALSE_POSITIVE_OR_UNEXPLOITABLE)
else: else:
injection = None injection = None

View File

@@ -9,6 +9,7 @@ from __future__ import division
import os import os
import re import re
import subprocess
import time import time
from lib.controller.action import action from lib.controller.action import action
@@ -598,6 +599,19 @@ def start():
kb.injections.append(injection) kb.injections.append(injection)
if not kb.alerted:
if conf.alert:
infoMsg = "executing alerting shell command(s) ('%s')" % conf.alert
logger.info(infoMsg)
try:
process = subprocess.Popen(conf.alert, shell=True)
process.wait()
except Exception as ex:
errMsg = "error occurred while executing '%s' ('%s')" % (conf.alert, getSafeExString(ex))
logger.error(errMsg)
kb.alerted = True
# In case when user wants to end detection phase (Ctrl+C) # In case when user wants to end detection phase (Ctrl+C)
if not proceed: if not proceed:
break break

View File

@@ -581,7 +581,7 @@ class Agent(object):
""" """
prefixRegex = r"(?:\s+(?:FIRST|SKIP|LIMIT(?: \d+)?)\s+\d+)*" prefixRegex = r"(?:\s+(?:FIRST|SKIP|LIMIT(?: \d+)?)\s+\d+)*"
fieldsSelectTop = re.search(r"\ASELECT\s+TOP(\s+[\d]|\s*\([^)]+\))\s+(.+?)\s+FROM", query, re.I) fieldsSelectTop = re.search(r"\ASELECT\s+TOP(\s+\d+|\s*\([^)]+\))\s+(.+?)\s+FROM", query, re.I)
fieldsSelectRownum = re.search(r"\ASELECT\s+([^()]+?),\s*ROWNUM AS LIMIT FROM", query, re.I) fieldsSelectRownum = re.search(r"\ASELECT\s+([^()]+?),\s*ROWNUM AS LIMIT FROM", query, re.I)
fieldsSelectDistinct = re.search(r"\ASELECT%s\s+DISTINCT\((.+?)\)\s+FROM" % prefixRegex, query, re.I) fieldsSelectDistinct = re.search(r"\ASELECT%s\s+DISTINCT\((.+?)\)\s+FROM" % prefixRegex, query, re.I)
fieldsSelectCase = re.search(r"\ASELECT%s\s+(\(CASE WHEN\s+.+\s+END\))" % prefixRegex, query, re.I) fieldsSelectCase = re.search(r"\ASELECT%s\s+(\(CASE WHEN\s+.+\s+END\))" % prefixRegex, query, re.I)
@@ -729,7 +729,7 @@ class Agent(object):
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'+" % kb.chars.start, 1) concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'+" % kb.chars.start, 1)
concatenatedQuery += "+'%s'" % kb.chars.stop concatenatedQuery += "+'%s'" % kb.chars.stop
elif fieldsSelectTop: elif fieldsSelectTop:
topNum = re.search(r"\ASELECT\s+TOP(\s+[\d]|\s*\([^)]+\))\s+", concatenatedQuery, re.I).group(1) topNum = re.search(r"\ASELECT\s+TOP(\s+\d+|\s*\([^)]+\))\s+", concatenatedQuery, re.I).group(1)
concatenatedQuery = concatenatedQuery.replace("SELECT TOP%s " % topNum, "TOP%s '%s'+" % (topNum, kb.chars.start), 1) concatenatedQuery = concatenatedQuery.replace("SELECT TOP%s " % topNum, "TOP%s '%s'+" % (topNum, kb.chars.start), 1)
concatenatedQuery = concatenatedQuery.replace(" FROM ", "+'%s' FROM " % kb.chars.stop, 1) concatenatedQuery = concatenatedQuery.replace(" FROM ", "+'%s' FROM " % kb.chars.stop, 1)
elif fieldsSelectCase: elif fieldsSelectCase:

View File

@@ -3708,7 +3708,7 @@ def getSortedInjectionTests():
if test.stype == PAYLOAD.TECHNIQUE.UNION: if test.stype == PAYLOAD.TECHNIQUE.UNION:
retVal = SORT_ORDER.LAST retVal = SORT_ORDER.LAST
elif "details" in test and "dbms" in test.details: elif "details" in test and "dbms" in (test.details or {}):
if intersect(test.details.dbms, Backend.getIdentifiedDbms()): if intersect(test.details.dbms, Backend.getIdentifiedDbms()):
retVal = SORT_ORDER.SECOND retVal = SORT_ORDER.SECOND
else: else:
@@ -4269,7 +4269,8 @@ def safeSQLIdentificatorNaming(name, isTable=False):
retVal = "[%s]" % retVal retVal = "[%s]" % retVal
if _ and DEFAULT_MSSQL_SCHEMA not in retVal and '.' not in re.sub(r"\[[^]]+\]", "", retVal): if _ and DEFAULT_MSSQL_SCHEMA not in retVal and '.' not in re.sub(r"\[[^]]+\]", "", retVal):
retVal = "%s.%s" % (DEFAULT_MSSQL_SCHEMA, retVal) if (conf.db or "").lower() != "information_schema": # NOTE: https://github.com/sqlmapproject/sqlmap/issues/5192
retVal = "%s.%s" % (DEFAULT_MSSQL_SCHEMA, retVal)
return retVal return retVal
@@ -4693,7 +4694,7 @@ def findPageForms(content, url, raise_=False, addToTargets=False):
else: else:
url = urldecode(request.get_full_url(), kb.pageEncoding) url = urldecode(request.get_full_url(), kb.pageEncoding)
method = request.get_method() method = request.get_method()
data = request.data data = unArrayizeValue(request.data)
data = urldecode(data, kb.pageEncoding, spaceplus=False) data = urldecode(data, kb.pageEncoding, spaceplus=False)
if not data and method and method.upper() == HTTPMETHOD.POST: if not data and method and method.upper() == HTTPMETHOD.POST:

View File

@@ -278,6 +278,7 @@ else:
buffer = buffer buffer = buffer
try: try:
from pkg_resources import parse_version as LooseVersion from packaging import version
LooseVersion = version.parse
except ImportError: except ImportError:
from distutils.version import LooseVersion from distutils.version import LooseVersion

View File

@@ -449,7 +449,7 @@ class Dump(object):
dumpDbPath = tempDir dumpDbPath = tempDir
dumpFileName = os.path.join(dumpDbPath, re.sub(r'[\\/]', UNSAFE_DUMP_FILEPATH_REPLACEMENT, "%s.%s" % (unsafeSQLIdentificatorNaming(table), conf.dumpFormat.lower()))) dumpFileName = conf.dumpFile or os.path.join(dumpDbPath, re.sub(r'[\\/]', UNSAFE_DUMP_FILEPATH_REPLACEMENT, "%s.%s" % (unsafeSQLIdentificatorNaming(table), conf.dumpFormat.lower())))
if not checkFile(dumpFileName, False): if not checkFile(dumpFileName, False):
try: try:
openFile(dumpFileName, "w+b").close() openFile(dumpFileName, "w+b").close()

View File

@@ -416,6 +416,9 @@ def _doSearch():
conf.googlePage += 1 conf.googlePage += 1
def _setStdinPipeTargets(): def _setStdinPipeTargets():
if conf.url:
return
if isinstance(conf.stdinPipe, _collections.Iterable): if isinstance(conf.stdinPipe, _collections.Iterable):
infoMsg = "using 'STDIN' for parsing targets list" infoMsg = "using 'STDIN' for parsing targets list"
logger.info(infoMsg) logger.info(infoMsg)
@@ -2045,6 +2048,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.delayCandidates = TIME_DELAY_CANDIDATES * [0] kb.delayCandidates = TIME_DELAY_CANDIDATES * [0]
kb.dep = None kb.dep = None
kb.disableHtmlDecoding = False kb.disableHtmlDecoding = False
kb.disableShiftTable = False
kb.dnsMode = False kb.dnsMode = False
kb.dnsTest = None kb.dnsTest = None
kb.docRoot = None kb.docRoot = None
@@ -2093,7 +2097,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.lastParserStatus = None kb.lastParserStatus = None
kb.locks = AttribDict() kb.locks = AttribDict()
for _ in ("cache", "connError", "count", "handlers", "hint", "index", "io", "limit", "liveCookies", "log", "socket", "redirect", "request", "value"): for _ in ("cache", "connError", "count", "handlers", "hint", "identYwaf", "index", "io", "limit", "liveCookies", "log", "socket", "redirect", "request", "value"):
kb.locks[_] = threading.Lock() kb.locks[_] = threading.Lock()
kb.matchRatio = None kb.matchRatio = None
@@ -2165,7 +2169,6 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.testType = None kb.testType = None
kb.threadContinue = True kb.threadContinue = True
kb.threadException = False kb.threadException = False
kb.tlsSNI = {}
kb.uChar = NULL kb.uChar = NULL
kb.udfFail = False kb.udfFail = False
kb.unionDuplicates = False kb.unionDuplicates = False
@@ -2674,7 +2677,7 @@ def _basicOptionValidation():
logger.warning(warnMsg) logger.warning(warnMsg)
if conf.cookieDel and len(conf.cookieDel): if conf.cookieDel and len(conf.cookieDel) != 1:
errMsg = "option '--cookie-del' should contain a single character (e.g. ';')" errMsg = "option '--cookie-del' should contain a single character (e.g. ';')"
raise SqlmapSyntaxException(errMsg) raise SqlmapSyntaxException(errMsg)
@@ -2732,6 +2735,10 @@ def _basicOptionValidation():
errMsg = "option '--csrf-method' requires usage of option '--csrf-token'" errMsg = "option '--csrf-method' requires usage of option '--csrf-token'"
raise SqlmapSyntaxException(errMsg) raise SqlmapSyntaxException(errMsg)
if conf.csrfData and not conf.csrfToken:
errMsg = "option '--csrf-data' requires usage of option '--csrf-token'"
raise SqlmapSyntaxException(errMsg)
if conf.csrfToken and conf.threads > 1: if conf.csrfToken and conf.threads > 1:
errMsg = "option '--csrf-url' is incompatible with option '--threads'" errMsg = "option '--csrf-url' is incompatible with option '--threads'"
raise SqlmapSyntaxException(errMsg) raise SqlmapSyntaxException(errMsg)

View File

@@ -64,6 +64,7 @@ optDict = {
"csrfToken": "string", "csrfToken": "string",
"csrfUrl": "string", "csrfUrl": "string",
"csrfMethod": "string", "csrfMethod": "string",
"csrfData": "string",
"csrfRetries": "integer", "csrfRetries": "integer",
"forceSSL": "boolean", "forceSSL": "boolean",
"chunked": "boolean", "chunked": "boolean",
@@ -214,6 +215,7 @@ optDict = {
"crawlDepth": "integer", "crawlDepth": "integer",
"crawlExclude": "string", "crawlExclude": "string",
"csvDel": "string", "csvDel": "string",
"dumpFile": "string",
"dumpFormat": "string", "dumpFormat": "string",
"encoding": "string", "encoding": "string",
"eta": "boolean", "eta": "boolean",

View File

@@ -20,7 +20,7 @@ from thirdparty import six
from thirdparty.six import unichr as _unichr from thirdparty.six import unichr as _unichr
# sqlmap version (<major>.<minor>.<month>.<monthly commit>) # sqlmap version (<major>.<minor>.<month>.<monthly commit>)
VERSION = "1.6.8.0" VERSION = "1.6.12.0"
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable" TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34} TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE) VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)
@@ -363,6 +363,7 @@ BASIC_HELP_ITEMS = (
"getCurrentUser", "getCurrentUser",
"getCurrentDb", "getCurrentDb",
"getPasswordHashes", "getPasswordHashes",
"getDbs",
"getTables", "getTables",
"getColumns", "getColumns",
"getSchema", "getSchema",

View File

@@ -120,7 +120,10 @@ def _setRequestParams():
while True: while True:
_ = re.search(r"\\g<([^>]+)>", retVal) _ = re.search(r"\\g<([^>]+)>", retVal)
if _: if _:
retVal = retVal.replace(_.group(0), match.group(int(_.group(1)) if _.group(1).isdigit() else _.group(1))) try:
retVal = retVal.replace(_.group(0), match.group(int(_.group(1)) if _.group(1).isdigit() else _.group(1)))
except IndexError:
break
else: else:
break break
if kb.customInjectionMark in retVal: if kb.customInjectionMark in retVal:

View File

@@ -161,8 +161,12 @@ def runThreads(numThreads, threadFunction, cleanupFunction=None, forwardExceptio
infoMsg = "starting %d threads" % numThreads infoMsg = "starting %d threads" % numThreads
logger.info(infoMsg) logger.info(infoMsg)
else: else:
_threadFunction() try:
return _threadFunction()
except (SqlmapUserQuitException, SqlmapSkipTargetException):
pass
finally:
return
kb.multiThreadMode = True kb.multiThreadMode = True

View File

@@ -276,6 +276,9 @@ def cmdLineParser(argv=None):
request.add_argument("--csrf-method", dest="csrfMethod", request.add_argument("--csrf-method", dest="csrfMethod",
help="HTTP method to use during anti-CSRF token page visit") help="HTTP method to use during anti-CSRF token page visit")
request.add_argument("--csrf-data", dest="csrfData",
help="POST data to send during anti-CSRF token page visit")
request.add_argument("--csrf-retries", dest="csrfRetries", type=int, request.add_argument("--csrf-retries", dest="csrfRetries", type=int,
help="Retries for anti-CSRF token retrieval (default %d)" % defaults.csrfRetries) help="Retries for anti-CSRF token retrieval (default %d)" % defaults.csrfRetries)
@@ -658,6 +661,9 @@ def cmdLineParser(argv=None):
general.add_argument("--charset", dest="charset", general.add_argument("--charset", dest="charset",
help="Blind SQL injection charset (e.g. \"0123456789abcdef\")") help="Blind SQL injection charset (e.g. \"0123456789abcdef\")")
general.add_argument("--dump-file", dest="dumpFile",
help="Store dumped data to a custom file")
general.add_argument("--dump-format", dest="dumpFormat", general.add_argument("--dump-format", dest="dumpFormat",
help="Format of dumped data (CSV (default), HTML or SQLITE)") help="Format of dumped data (CSV (default), HTML or SQLITE)")
@@ -833,6 +839,9 @@ def cmdLineParser(argv=None):
parser.add_argument("--vuln-test", dest="vulnTest", action="store_true", parser.add_argument("--vuln-test", dest="vulnTest", action="store_true",
help=SUPPRESS) help=SUPPRESS)
parser.add_argument("--disable-json", dest="disableJson", action="store_true",
help=SUPPRESS)
# API options # API options
parser.add_argument("--api", dest="api", action="store_true", parser.add_argument("--api", dest="api", action="store_true",
help=SUPPRESS) help=SUPPRESS)
@@ -986,7 +995,7 @@ def cmdLineParser(argv=None):
argv[i] = argv[i].replace("--auth-creds", "--auth-cred", 1) argv[i] = argv[i].replace("--auth-creds", "--auth-cred", 1)
elif argv[i].startswith("--drop-cookie"): elif argv[i].startswith("--drop-cookie"):
argv[i] = argv[i].replace("--drop-cookie", "--drop-set-cookie", 1) argv[i] = argv[i].replace("--drop-cookie", "--drop-set-cookie", 1)
elif any(argv[i].startswith(_) for _ in ("--tamper", "--ignore-code", "--skip")): elif re.search(r"\A(--(tamper|ignore-code|skip))(?!-)", argv[i]):
key = re.search(r"\-?\-(\w+)\b", argv[i]).group(1) key = re.search(r"\-?\-(\w+)\b", argv[i]).group(1)
index = auxIndexes.get(key, None) index = auxIndexes.get(key, None)
if index is None: if index is None:

View File

@@ -275,6 +275,8 @@ def decodePage(page, contentEncoding, contentType, percentDecode=True):
>>> getText(decodePage(b"<html>foo&amp;bar</html>", None, "text/html; charset=utf-8")) >>> getText(decodePage(b"<html>foo&amp;bar</html>", None, "text/html; charset=utf-8"))
'<html>foo&bar</html>' '<html>foo&bar</html>'
>>> getText(decodePage(b"&#x9;", None, "text/html; charset=utf-8"))
'\\t'
""" """
if not page or (conf.nullConnection and len(page) < 2): if not page or (conf.nullConnection and len(page) < 2):
@@ -339,7 +341,7 @@ def decodePage(page, contentEncoding, contentType, percentDecode=True):
if not kb.disableHtmlDecoding: if not kb.disableHtmlDecoding:
# e.g. &#x9;&#195;&#235;&#224;&#226;&#224; # e.g. &#x9;&#195;&#235;&#224;&#226;&#224;
if b"&#" in page: if b"&#" in page:
page = re.sub(b"&#x([0-9a-f]{1,2});", lambda _: decodeHex(_.group(1) if len(_.group(1)) == 2 else "0%s" % _.group(1)), page) page = re.sub(b"&#x([0-9a-f]{1,2});", lambda _: decodeHex(_.group(1) if len(_.group(1)) == 2 else b"0%s" % _.group(1)), page)
page = re.sub(b"&#(\\d{1,3});", lambda _: six.int2byte(int(_.group(1))) if int(_.group(1)) < 256 else _.group(0), page) page = re.sub(b"&#(\\d{1,3});", lambda _: six.int2byte(int(_.group(1))) if int(_.group(1)) < 256 else _.group(0), page)
# e.g. %20%28%29 # e.g. %20%28%29
@@ -399,13 +401,14 @@ def processResponse(page, responseHeaders, code=None, status=None):
if not conf.skipWaf and kb.processResponseCounter < IDENTYWAF_PARSE_LIMIT: if not conf.skipWaf and kb.processResponseCounter < IDENTYWAF_PARSE_LIMIT:
rawResponse = "%s %s %s\n%s\n%s" % (_http_client.HTTPConnection._http_vsn_str, code or "", status or "", "".join(getUnicode(responseHeaders.headers if responseHeaders else [])), page[:HEURISTIC_PAGE_SIZE_THRESHOLD]) rawResponse = "%s %s %s\n%s\n%s" % (_http_client.HTTPConnection._http_vsn_str, code or "", status or "", "".join(getUnicode(responseHeaders.headers if responseHeaders else [])), page[:HEURISTIC_PAGE_SIZE_THRESHOLD])
identYwaf.non_blind.clear() with kb.locks.identYwaf:
if identYwaf.non_blind_check(rawResponse, silent=True): identYwaf.non_blind.clear()
for waf in identYwaf.non_blind: if identYwaf.non_blind_check(rawResponse, silent=True):
if waf not in kb.identifiedWafs: for waf in set(identYwaf.non_blind):
kb.identifiedWafs.add(waf) if waf not in kb.identifiedWafs:
errMsg = "WAF/IPS identified as '%s'" % identYwaf.format_name(waf) kb.identifiedWafs.add(waf)
singleTimeLogMessage(errMsg, logging.CRITICAL) errMsg = "WAF/IPS identified as '%s'" % identYwaf.format_name(waf)
singleTimeLogMessage(errMsg, logging.CRITICAL)
if kb.originalPage is None: if kb.originalPage is None:
for regex in (EVENTVALIDATION_REGEX, VIEWSTATE_REGEX): for regex in (EVENTVALIDATION_REGEX, VIEWSTATE_REGEX):

View File

@@ -587,7 +587,8 @@ class Connect(object):
if not getRequestHeader(req, HTTP_HEADER.COOKIE) and conf.cj: if not getRequestHeader(req, HTTP_HEADER.COOKIE) and conf.cj:
conf.cj._policy._now = conf.cj._now = int(time.time()) conf.cj._policy._now = conf.cj._now = int(time.time())
cookies = conf.cj._cookies_for_request(req) with conf.cj._cookies_lock:
cookies = conf.cj._cookies_for_request(req)
requestHeaders += "\r\n%s" % ("Cookie: %s" % ";".join("%s=%s" % (getUnicode(cookie.name), getUnicode(cookie.value)) for cookie in cookies)) requestHeaders += "\r\n%s" % ("Cookie: %s" % ";".join("%s=%s" % (getUnicode(cookie.name), getUnicode(cookie.value)) for cookie in cookies))
if post is not None: if post is not None:
@@ -1011,9 +1012,10 @@ class Connect(object):
if (kb.postHint or conf.skipUrlEncode) and postUrlEncode: if (kb.postHint or conf.skipUrlEncode) and postUrlEncode:
postUrlEncode = False postUrlEncode = False
conf.httpHeaders = [_ for _ in conf.httpHeaders if _[1] != contentType] if not (conf.skipUrlEncode and contentType): # NOTE: https://github.com/sqlmapproject/sqlmap/issues/5092
contentType = POST_HINT_CONTENT_TYPES.get(kb.postHint, PLAIN_TEXT_CONTENT_TYPE) conf.httpHeaders = [_ for _ in conf.httpHeaders if _[1] != contentType]
conf.httpHeaders.append((HTTP_HEADER.CONTENT_TYPE, contentType)) contentType = POST_HINT_CONTENT_TYPES.get(kb.postHint, PLAIN_TEXT_CONTENT_TYPE)
conf.httpHeaders.append((HTTP_HEADER.CONTENT_TYPE, contentType))
if payload: if payload:
delimiter = conf.paramDel or (DEFAULT_GET_POST_DELIMITER if place != PLACE.COOKIE else DEFAULT_COOKIE_DELIMITER) delimiter = conf.paramDel or (DEFAULT_GET_POST_DELIMITER if place != PLACE.COOKIE else DEFAULT_COOKIE_DELIMITER)
@@ -1179,7 +1181,7 @@ class Connect(object):
warnMsg += ". sqlmap is going to retry the request" warnMsg += ". sqlmap is going to retry the request"
logger.warning(warnMsg) logger.warning(warnMsg)
page, headers, code = Connect.getPage(url=conf.csrfUrl or conf.url, data=conf.data if conf.csrfUrl == conf.url else None, method=conf.csrfMethod or (conf.method if conf.csrfUrl == conf.url else None), cookie=conf.parameters.get(PLACE.COOKIE), direct=True, silent=True, ua=conf.parameters.get(PLACE.USER_AGENT), referer=conf.parameters.get(PLACE.REFERER), host=conf.parameters.get(PLACE.HOST)) page, headers, code = Connect.getPage(url=conf.csrfUrl or conf.url, data=conf.csrfData or (conf.data if conf.csrfUrl == conf.url else None), method=conf.csrfMethod or (conf.method if conf.csrfUrl == conf.url else None), cookie=conf.parameters.get(PLACE.COOKIE), direct=True, silent=True, ua=conf.parameters.get(PLACE.USER_AGENT), referer=conf.parameters.get(PLACE.REFERER), host=conf.parameters.get(PLACE.HOST))
page = urldecode(page) # for anti-CSRF tokens with special characters in their name (e.g. 'foo:bar=...') page = urldecode(page) # for anti-CSRF tokens with special characters in their name (e.g. 'foo:bar=...')
match = re.search(r"(?i)<input[^>]+\bname=[\"']?(?P<name>%s)\b[^>]*\bvalue=[\"']?(?P<value>[^>'\"]*)" % conf.csrfToken, page or "", re.I) match = re.search(r"(?i)<input[^>]+\bname=[\"']?(?P<name>%s)\b[^>]*\bvalue=[\"']?(?P<value>[^>'\"]*)" % conf.csrfToken, page or "", re.I)

View File

@@ -36,6 +36,8 @@ class HTTPSConnection(_http_client.HTTPSConnection):
Connection class that enables usage of newer SSL protocols. Connection class that enables usage of newer SSL protocols.
Reference: http://bugs.python.org/msg128686 Reference: http://bugs.python.org/msg128686
NOTE: use https://check-tls.akamaized.net/ to check if (e.g.) TLS/SNI is working properly
""" """
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@@ -61,19 +63,21 @@ class HTTPSConnection(_http_client.HTTPSConnection):
# Reference(s): https://docs.python.org/2/library/ssl.html#ssl.SSLContext # Reference(s): https://docs.python.org/2/library/ssl.html#ssl.SSLContext
# https://www.mnot.net/blog/2014/12/27/python_2_and_tls_sni # https://www.mnot.net/blog/2014/12/27/python_2_and_tls_sni
if re.search(r"\A[\d.]+\Z", conf.hostname or "") is None and kb.tlsSNI.get(conf.hostname) is not False and hasattr(ssl, "SSLContext"): if hasattr(ssl, "SSLContext"):
for protocol in (_ for _ in _protocols if _ >= ssl.PROTOCOL_TLSv1): for protocol in (_ for _ in _protocols if _ >= ssl.PROTOCOL_TLSv1):
try: try:
sock = create_sock() sock = create_sock()
if protocol not in _contexts: if protocol not in _contexts:
_contexts[protocol] = ssl.SSLContext(protocol) _contexts[protocol] = ssl.SSLContext(protocol)
if getattr(self, "cert_file", None) and getattr(self, "key_file", None):
_contexts[protocol].load_cert_chain(certfile=self.cert_file, keyfile=self.key_file)
try: try:
# Reference(s): https://askubuntu.com/a/1263098 # Reference(s): https://askubuntu.com/a/1263098
# https://askubuntu.com/a/1250807 # https://askubuntu.com/a/1250807
_contexts[protocol].set_ciphers("DEFAULT@SECLEVEL=1") _contexts[protocol].set_ciphers("DEFAULT@SECLEVEL=1")
except ssl.SSLError: except ssl.SSLError:
pass pass
result = _contexts[protocol].wrap_socket(sock, do_handshake_on_connect=True, server_hostname=conf.hostname) result = _contexts[protocol].wrap_socket(sock, do_handshake_on_connect=True, server_hostname=self.host if re.search(r"\A[\d.]+\Z", self.host or "") is None else None)
if result: if result:
success = True success = True
self.sock = result self.sock = result
@@ -86,14 +90,11 @@ class HTTPSConnection(_http_client.HTTPSConnection):
self._tunnel_host = None self._tunnel_host = None
logger.debug("SSL connection error occurred for '%s' ('%s')" % (_lut[protocol], getSafeExString(ex))) logger.debug("SSL connection error occurred for '%s' ('%s')" % (_lut[protocol], getSafeExString(ex)))
if kb.tlsSNI.get(conf.hostname) is None: elif hasattr(ssl, "wrap_socket"):
kb.tlsSNI[conf.hostname] = success
if not success:
for protocol in _protocols: for protocol in _protocols:
try: try:
sock = create_sock() sock = create_sock()
_ = ssl.wrap_socket(sock, self.key_file, self.cert_file, ssl_version=protocol) _ = ssl.wrap_socket(sock, keyfile=getattr(self, "key_file"), certfile=getattr(self, "cert_file"), ssl_version=protocol)
if _: if _:
success = True success = True
self.sock = _ self.sock = _

View File

@@ -274,9 +274,11 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
originalTbl = type(charTbl)(charTbl) originalTbl = type(charTbl)(charTbl)
if continuousOrder and shiftTable is None: if kb.disableShiftTable:
shiftTable = None
elif continuousOrder and shiftTable is None:
# Used for gradual expanding into unicode charspace # Used for gradual expanding into unicode charspace
shiftTable = [2, 2, 3, 3, 5, 4] shiftTable = [2, 2, 3, 3, 3]
if "'%s'" % CHAR_INFERENCE_MARK in payload: if "'%s'" % CHAR_INFERENCE_MARK in payload:
for char in ('\n', '\r'): for char in ('\n', '\r'):
@@ -358,6 +360,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
kb.responseTimePayload = None kb.responseTimePayload = None
result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False) result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False)
incrementCounter(getTechnique()) incrementCounter(getTechnique())
if not timeBasedCompare and getTechniqueData() is not None: if not timeBasedCompare and getTechniqueData() is not None:
@@ -405,6 +408,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
maxChar = maxValue = charTbl[-1] maxChar = maxValue = charTbl[-1]
minValue = charTbl[0] minValue = charTbl[0]
else: else:
kb.disableShiftTable = True
return None return None
else: else:
retVal = minValue + 1 retVal = minValue + 1

View File

@@ -252,7 +252,7 @@ def unionUse(expression, unpack=True, dump=False):
debugMsg += "it does not play well with UNION query SQL injection" debugMsg += "it does not play well with UNION query SQL injection"
singleTimeDebugMessage(debugMsg) singleTimeDebugMessage(debugMsg)
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ORACLE, DBMS.PGSQL, DBMS.MSSQL, DBMS.SQLITE) and expressionFields and not any((conf.binaryFields, conf.limitStart, conf.limitStop, conf.forcePartial)): if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ORACLE, DBMS.PGSQL, DBMS.MSSQL, DBMS.SQLITE) and expressionFields and not any((conf.binaryFields, conf.limitStart, conf.limitStop, conf.forcePartial, conf.disableJson)):
match = re.search(r"SELECT\s*(.+?)\bFROM", expression, re.I) match = re.search(r"SELECT\s*(.+?)\bFROM", expression, re.I)
if match and not (Backend.isDbms(DBMS.ORACLE) and FROM_DUMMY_TABLE[DBMS.ORACLE] in expression) and not re.search(r"\b(MIN|MAX|COUNT)\(", expression): if match and not (Backend.isDbms(DBMS.ORACLE) and FROM_DUMMY_TABLE[DBMS.ORACLE] in expression) and not re.search(r"\b(MIN|MAX|COUNT)\(", expression):
kb.jsonAggMode = True kb.jsonAggMode = True

View File

@@ -89,6 +89,7 @@ class Fingerprint(GenericFingerprint):
logger.info(infoMsg) logger.info(infoMsg)
for version, check in ( for version, check in (
("2022", "CHARINDEX('16.0.',@@VERSION)>0"),
("2019", "CHARINDEX('15.0.',@@VERSION)>0"), ("2019", "CHARINDEX('15.0.',@@VERSION)>0"),
("Azure", "@@VERSION LIKE '%Azure%'"), ("Azure", "@@VERSION LIKE '%Azure%'"),
("2017", "TRIM(NULL) IS NULL"), ("2017", "TRIM(NULL) IS NULL"),
@@ -151,7 +152,7 @@ class Fingerprint(GenericFingerprint):
"7 or 2008 R2": ("6.1", (1, 0)), "7 or 2008 R2": ("6.1", (1, 0)),
"8 or 2012": ("6.2", (0,)), "8 or 2012": ("6.2", (0,)),
"8.1 or 2012 R2": ("6.3", (0,)), "8.1 or 2012 R2": ("6.3", (0,)),
"10 or 2016 or 2019": ("10.0", (0,)) "10 or 11 or 2016 or 2019 or 2022": ("10.0", (0,))
} }
# Get back-end DBMS underlying operating system version # Get back-end DBMS underlying operating system version

View File

@@ -47,11 +47,11 @@ class Fingerprint(GenericFingerprint):
versions = ( versions = (
(80000, 80029), # MySQL 8.0 (80000, 80029), # MySQL 8.0
(60000, 60014), # MySQL 6.0 (60000, 60014), # MySQL 6.0
(50700, 50737), # MySQL 5.7 (50700, 50739), # MySQL 5.7
(50600, 50652), # MySQL 5.6 (50600, 50652), # MySQL 5.6
(50500, 50563), # MySQL 5.5 (50500, 50563), # MySQL 5.5
(50400, 50404), # MySQL 5.4 (50400, 50404), # MySQL 5.4
(50100, 50174), # MySQL 5.1 (50100, 50175), # MySQL 5.1
(50000, 50097), # MySQL 5.0 (50000, 50097), # MySQL 5.0
(40100, 40131), # MySQL 4.1 (40100, 40131), # MySQL 4.1
(40000, 40032), # MySQL 4.0 (40000, 40032), # MySQL 4.0

View File

@@ -131,7 +131,9 @@ class Fingerprint(GenericFingerprint):
infoMsg = "actively fingerprinting %s" % DBMS.PGSQL infoMsg = "actively fingerprinting %s" % DBMS.PGSQL
logger.info(infoMsg) logger.info(infoMsg)
if inject.checkBooleanExpression("GEN_RANDOM_UUID() IS NOT NULL"): if inject.checkBooleanExpression("BIT_COUNT(NULL) IS NULL"):
Backend.setVersion(">= 14.0")
elif inject.checkBooleanExpression("GEN_RANDOM_UUID() IS NOT NULL"):
Backend.setVersion(">= 13.0") Backend.setVersion(">= 13.0")
elif inject.checkBooleanExpression("SINH(0)=0"): elif inject.checkBooleanExpression("SINH(0)=0"):
Backend.setVersion(">= 12.0") Backend.setVersion(">= 12.0")

View File

@@ -195,6 +195,9 @@ csrfUrl =
# HTTP method to use during anti-CSRF token page visit. # HTTP method to use during anti-CSRF token page visit.
csrfMethod = csrfMethod =
# POST data to send during anti-CSRF token page visit.
csrfData =
# Retries for anti-CSRF token retrieval. # Retries for anti-CSRF token retrieval.
csrfRetries = csrfRetries =
@@ -735,6 +738,9 @@ crawlExclude =
# Default: , # Default: ,
csvDel = , csvDel = ,
# Store dumped data to a custom file.
dumpFile =
# Format of dumped data # Format of dumped data
# Valid: CSV, HTML or SQLITE # Valid: CSV, HTML or SQLITE
dumpFormat = CSV dumpFormat = CSV

33
tamper/decentities.py Normal file
View File

@@ -0,0 +1,33 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2022 sqlmap developers (https://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.LOW
def dependencies():
pass
def tamper(payload, **kwargs):
"""
HTML encode in decimal (using code points) all characters (e.g. ' -> &#39;)
>>> tamper("1' AND SLEEP(5)#")
'&#49;&#39;&#32;&#65;&#78;&#68;&#32;&#83;&#76;&#69;&#69;&#80;&#40;&#53;&#41;&#35;'
"""
retVal = payload
if payload:
retVal = ""
i = 0
while i < len(payload):
retVal += "&#%s;" % ord(payload[i])
i += 1
return retVal

33
tamper/hexentities.py Normal file
View File

@@ -0,0 +1,33 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2022 sqlmap developers (https://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.LOW
def dependencies():
pass
def tamper(payload, **kwargs):
"""
HTML encode in hexadecimal (using code points) all characters (e.g. ' -> &#x31;)
>>> tamper("1' AND SLEEP(5)#")
'&#x31;&#x27;&#x20;&#x41;&#x4e;&#x44;&#x20;&#x53;&#x4c;&#x45;&#x45;&#x50;&#x28;&#x35;&#x29;&#x23;'
"""
retVal = payload
if payload:
retVal = ""
i = 0
while i < len(payload):
retVal += "&#x%s;" % format(ord(payload[i]), "x")
i += 1
return retVal

View File

@@ -20,6 +20,12 @@ def tamper(payload, **kwargs):
>>> tamper("1' AND SLEEP(5)#") >>> tamper("1' AND SLEEP(5)#")
'1&#39;&#32;AND&#32;SLEEP&#40;5&#41;&#35;' '1&#39;&#32;AND&#32;SLEEP&#40;5&#41;&#35;'
>>> tamper("1&#39;&#32;AND&#32;SLEEP&#40;5&#41;&#35;")
'1&#39;&#32;AND&#32;SLEEP&#40;5&#41;&#35;'
""" """
return re.sub(r"[^\w]", lambda match: "&#%d;" % ord(match.group(0)), payload) if payload else payload if payload:
payload = re.sub(r"&#(\d+);", lambda match: chr(int(match.group(1))), payload) # NOTE: https://github.com/sqlmapproject/sqlmap/issues/5203
payload = re.sub(r"[^\w]", lambda match: "&#%d;" % ord(match.group(0)), payload)
return payload

35
tamper/scientific.py Normal file
View File

@@ -0,0 +1,35 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2022 sqlmap developers (https://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
import re
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.HIGHEST
def dependencies():
pass
def tamper(payload, **kwargs):
"""
Abuses MySQL scientific notation
Requirement:
* MySQL
Notes:
* Reference: https://www.gosecure.net/blog/2021/10/19/a-scientific-notation-bug-in-mysql-left-aws-waf-clients-vulnerable-to-sql-injection/
>>> tamper('1 AND ORD(MID((CURRENT_USER()),7,1))>1')
'1 AND ORD 1.e(MID((CURRENT_USER 1.e( 1.e) 1.e) 1.e,7 1.e,1 1.e) 1.e)>1'
"""
if payload:
payload = re.sub(r"[),.*^/|&]", r" 1.e\g<0>", payload)
payload = re.sub(r"(\w+)\(", lambda match: "%s 1.e(" % match.group(1) if not re.search(r"(?i)\A(MID|CAST|FROM|COUNT)\Z", match.group(1)) else match.group(0), payload) # NOTE: MID and CAST don't work for sure
return payload