mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2025-12-10 17:59:04 +00:00
Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
33a6547f5b | ||
|
|
ad529f24cb | ||
|
|
3d2f89345f | ||
|
|
58f10093a0 | ||
|
|
6aaf7d3960 | ||
|
|
b8fa0edea6 | ||
|
|
55b2b43f0e | ||
|
|
7bc0b08fd6 | ||
|
|
62bba470d6 | ||
|
|
eda669e10b | ||
|
|
c382321134 | ||
|
|
2ace4ef471 | ||
|
|
02dcf2a926 | ||
|
|
5c55602296 | ||
|
|
aa9cc3987e | ||
|
|
d7ee423fc5 | ||
|
|
1092dfb877 | ||
|
|
bf4f84b70a | ||
|
|
c45cf60fb4 | ||
|
|
3f53b2bc05 | ||
|
|
9c103b3dd6 | ||
|
|
7f62572f43 | ||
|
|
e846209b87 | ||
|
|
a246b8da5e | ||
|
|
70665c5d2b | ||
|
|
111620e395 | ||
|
|
2382d2654e | ||
|
|
4cdc3af585 | ||
|
|
212f28d1ad | ||
|
|
e1f7690de4 | ||
|
|
7e425d4c9b |
@@ -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">
|
||||||
|
|||||||
@@ -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 -->
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -275,6 +275,8 @@ def decodePage(page, contentEncoding, contentType, percentDecode=True):
|
|||||||
|
|
||||||
>>> getText(decodePage(b"<html>foo&bar</html>", None, "text/html; charset=utf-8"))
|
>>> getText(decodePage(b"<html>foo&bar</html>", None, "text/html; charset=utf-8"))
|
||||||
'<html>foo&bar</html>'
|
'<html>foo&bar</html>'
|
||||||
|
>>> getText(decodePage(b"	", 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. 	Ãëàâà
|
# e.g. 	Ãëàâà
|
||||||
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):
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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 = _
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
@@ -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
33
tamper/decentities.py
Normal 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. ' -> ')
|
||||||
|
|
||||||
|
>>> tamper("1' AND SLEEP(5)#")
|
||||||
|
'1' AND SLEEP(5)#'
|
||||||
|
"""
|
||||||
|
|
||||||
|
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
33
tamper/hexentities.py
Normal 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. ' -> 1)
|
||||||
|
|
||||||
|
>>> tamper("1' AND SLEEP(5)#")
|
||||||
|
'1' AND SLEEP(5)#'
|
||||||
|
"""
|
||||||
|
|
||||||
|
retVal = payload
|
||||||
|
|
||||||
|
if payload:
|
||||||
|
retVal = ""
|
||||||
|
i = 0
|
||||||
|
|
||||||
|
while i < len(payload):
|
||||||
|
retVal += "&#x%s;" % format(ord(payload[i]), "x")
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
return retVal
|
||||||
@@ -20,6 +20,12 @@ def tamper(payload, **kwargs):
|
|||||||
|
|
||||||
>>> tamper("1' AND SLEEP(5)#")
|
>>> tamper("1' AND SLEEP(5)#")
|
||||||
'1' AND SLEEP(5)#'
|
'1' AND SLEEP(5)#'
|
||||||
|
>>> tamper("1' AND SLEEP(5)#")
|
||||||
|
'1' AND SLEEP(5)#'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
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
35
tamper/scientific.py
Normal 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
|
||||||
Reference in New Issue
Block a user