Skip to content

Commit

Permalink
Stabilizing DREI
Browse files Browse the repository at this point in the history
  • Loading branch information
stamparm committed May 3, 2019
1 parent d8c62e0 commit f6f6844
Show file tree
Hide file tree
Showing 52 changed files with 347 additions and 334 deletions.
137 changes: 35 additions & 102 deletions lib/core/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
See the file 'LICENSE' for copying permission
"""

import base64
import binascii
import codecs
import collections
Expand Down Expand Up @@ -53,10 +52,12 @@
from lib.core.compat import xrange
from lib.core.convert import base64pickle
from lib.core.convert import base64unpickle
from lib.core.convert import hexdecode
from lib.core.convert import decodeBase64
from lib.core.convert import decodeHex
from lib.core.convert import getBytes
from lib.core.convert import getText
from lib.core.convert import htmlunescape
from lib.core.convert import stdoutencode
from lib.core.convert import utf8encode
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
Expand Down Expand Up @@ -127,7 +128,6 @@
from lib.core.settings import HTTP_CHUNKED_SPLIT_KEYWORDS
from lib.core.settings import IGNORE_SAVE_OPTIONS
from lib.core.settings import INFERENCE_UNKNOWN_CHAR
from lib.core.settings import INVALID_UNICODE_PRIVATE_AREA
from lib.core.settings import IP_ADDRESS_REGEX
from lib.core.settings import ISSUES_PAGE
from lib.core.settings import IS_WIN
Expand Down Expand Up @@ -156,7 +156,6 @@
from lib.core.settings import REFLECTED_REPLACEMENT_TIMEOUT
from lib.core.settings import REFLECTED_VALUE_MARKER
from lib.core.settings import REFLECTIVE_MISS_THRESHOLD
from lib.core.settings import SAFE_HEX_MARKER
from lib.core.settings import SENSITIVE_DATA_REGEX
from lib.core.settings import SENSITIVE_OPTIONS
from lib.core.settings import STDIN_PIPE_DASH
Expand Down Expand Up @@ -1113,8 +1112,9 @@ def randomRange(start=0, stop=1000, seed=None):
"""
Returns random integer value in given range
>>> randomRange(1, 500, seed=0)
9
>>> random.seed(0)
>>> randomRange(1, 500)
152
"""

if seed is not None:
Expand All @@ -1130,8 +1130,9 @@ def randomInt(length=4, seed=None):
"""
Returns random integer value with provided number of digits
>>> randomInt(6, seed=0)
181911
>>> random.seed(0)
>>> randomInt(6)
963638
"""

if seed is not None:
Expand All @@ -1147,8 +1148,9 @@ def randomStr(length=4, lowercase=False, alphabet=None, seed=None):
"""
Returns random string value with provided number of characters
>>> randomStr(6, seed=0)
'aUfWgj'
>>> random.seed(0)
>>> randomStr(6)
'FUPGpY'
"""

if seed is not None:
Expand Down Expand Up @@ -1685,7 +1687,7 @@ def parseUnionPage(page):
entry = entry.split(kb.chars.delimiter)

if conf.hexConvert:
entry = applyFunctionRecursively(entry, decodeHexValue)
entry = applyFunctionRecursively(entry, decodeDbmsHexValue)

if kb.safeCharEncode:
entry = applyFunctionRecursively(entry, safecharencode)
Expand Down Expand Up @@ -1882,7 +1884,7 @@ def safeStringFormat(format_, params):
Avoids problems with inappropriate string format strings
>>> safeStringFormat('SELECT foo FROM %s LIMIT %d', ('bar', '1'))
u'SELECT foo FROM bar LIMIT 1'
'SELECT foo FROM bar LIMIT 1'
"""

if format_.count(PAYLOAD_DELIMITER) == 2:
Expand All @@ -1895,7 +1897,7 @@ def safeStringFormat(format_, params):
if isinstance(params, six.string_types):
retVal = retVal.replace("%s", params, 1)
elif not isListLike(params):
retVal = retVal.replace("%s", getUnicode(params), 1)
retVal = retVal.replace("%s", getText(params), 1)
else:
start, end = 0, len(retVal)
match = re.search(r"%s(.+)%s" % (PAYLOAD_DELIMITER, PAYLOAD_DELIMITER), retVal)
Expand All @@ -1904,7 +1906,7 @@ def safeStringFormat(format_, params):
if retVal.count("%s", start, end) == len(params):
for param in params:
index = retVal.find("%s", start)
retVal = retVal[:index] + getUnicode(param) + retVal[index + 2:]
retVal = retVal[:index] + getText(param) + retVal[index + 2:]
else:
if any('%s' in _ for _ in conf.parameters.values()):
parts = format_.split(' ')
Expand Down Expand Up @@ -2457,75 +2459,6 @@ def getUnicode(value, encoding=None, noneToNull=False):
except UnicodeDecodeError:
return six.text_type(str(value), errors="ignore") # encoding ignored for non-basestring instances

def decodeHex(value, binary=True):
"""
Returns a decoded representation of provided hexadecimal value
>>> decodeHex("313233") == b"123"
True
>>> decodeHex("313233", binary=False) == u"123"
True
"""

retVal = codecs.decode(value, "hex")

if not binary:
retVal = getUnicode(retVal)

return retVal

def decodeBase64(value, binary=True):
"""
Returns a decoded representation of provided Base64 value
>>> decodeBase64("MTIz") == b"123"
True
>>> decodeBase64("MTIz", binary=False) == u"123"
True
"""

retVal = base64.b64decode(value)

if not binary:
retVal = getUnicode(retVal)

return retVal

def getBytes(value, encoding=UNICODE_ENCODING, errors="strict"):
"""
Returns byte representation of provided Unicode value
>>> getBytes(getUnicode(b"foo\\x01\\x83\\xffbar")) == b"foo\\x01\\x83\\xffbar"
True
"""

retVal = value

if isinstance(value, six.text_type):
if INVALID_UNICODE_PRIVATE_AREA:
for char in xrange(0xF0000, 0xF00FF + 1):
value = value.replace(six.unichr(char), "%s%02x" % (SAFE_HEX_MARKER, char - 0xF0000))

retVal = value.encode(encoding, errors)
retVal = re.sub(r"%s([0-9a-f]{2})" % SAFE_HEX_MARKER, lambda _: decodeHex(_.group(1)), retVal)
else:
retVal = value.encode(encoding, errors)
retVal = re.sub(b"\\\\x([0-9a-f]{2})", lambda _: decodeHex(_.group(1)), retVal)

return retVal

def getOrds(value):
"""
Returns ORD(...) representation of provided string value
>>> getOrds(u'fo\\xf6bar')
[102, 111, 246, 98, 97, 114]
>>> getOrds(b"fo\\xc3\\xb6bar")
[102, 111, 195, 182, 98, 97, 114]
"""

return [_ if isinstance(_, int) else ord(_) for _ in value]

def longestCommonPrefix(*sequences):
"""
Returns longest common prefix occuring in given sequences
Expand Down Expand Up @@ -2774,7 +2707,7 @@ def urldecode(value, encoding=None, unsafe="%%&=;+%s" % CUSTOM_INJECTION_MARK_CH
charset = set(string.printable) - set(unsafe)

def _(match):
char = getUnicode(decodeHex(match.group(1)))
char = decodeHex(match.group(1), binary=False)
return char if char in charset else match.group(0)

if spaceplus:
Expand Down Expand Up @@ -2817,7 +2750,7 @@ def urlencode(value, safe="%&=-_", convall=False, limit=False, spaceplus=False):
value = re.sub(r"%(?![0-9a-fA-F]{2})", "%25", value)

while True:
result = _urllib.parse.quote(utf8encode(value), safe)
result = _urllib.parse.quote(getBytes(value), safe)

if limit and len(result) > URLENCODE_CHAR_LIMIT:
if count >= len(URLENCODE_FAILSAFE_CHARS):
Expand Down Expand Up @@ -3488,7 +3421,7 @@ def decodeIntToUnicode(value):
_ = "%x" % value
if len(_) % 2 == 1:
_ = "0%s" % _
raw = hexdecode(_)
raw = decodeHex(_)

if Backend.isDbms(DBMS.MYSQL):
# Note: https://github.com/sqlmapproject/sqlmap/issues/1531
Expand Down Expand Up @@ -4113,9 +4046,9 @@ def randomizeParameterValue(value):
>>> random.seed(0)
>>> randomizeParameterValue('foobar')
'rnvnav'
'fupgpy'
>>> randomizeParameterValue('17')
'83'
'36'
"""

retVal = value
Expand Down Expand Up @@ -4175,8 +4108,8 @@ def asciifyUrl(url, forceQuote=False):
# Reference: http://blog.elsdoerfer.name/2008/12/12/opening-iris-in-python/
>>> asciifyUrl(u'http://www.\u0161u\u0107uraj.com')
u'http://www.xn--uuraj-gxa24d.com'
>>> asciifyUrl(u'http://www.\\u0161u\\u0107uraj.com') == u'http://www.xn--uuraj-gxa24d.com'
True
"""

parts = _urllib.parse.urlsplit(url)
Expand All @@ -4191,7 +4124,7 @@ def asciifyUrl(url, forceQuote=False):
try:
hostname = parts.hostname.encode("idna")
except LookupError:
hostname = parts.hostname.encode(UNICODE_ENCODING)
hostname = parts.hostname.encode("punycode")

# UTF8-quote the other parts. We check each part individually if
# if needs to be quoted - that should catch some additional user
Expand All @@ -4203,7 +4136,7 @@ def quote(s, safe):
# _urllib.parse.quote(s.replace('%', '')) != s.replace('%', '')
# which would trigger on all %-characters, e.g. "&".
if getUnicode(s).encode("ascii", "replace") != s or forceQuote:
return _urllib.parse.quote(s.encode(UNICODE_ENCODING) if isinstance(s, six.text_type) else s, safe=safe)
s = _urllib.parse.quote(getBytes(s), safe=safe)
return s

username = quote(parts.username, '')
Expand All @@ -4212,7 +4145,7 @@ def quote(s, safe):
query = quote(parts.query, safe="&=")

# put everything back together
netloc = hostname
netloc = getText(hostname)
if username or password:
netloc = '@' + netloc
if password:
Expand Down Expand Up @@ -4521,13 +4454,13 @@ def applyFunctionRecursively(value, function):

return retVal

def decodeHexValue(value, raw=False):
def decodeDbmsHexValue(value, raw=False):
"""
Returns value decoded from DBMS specific hexadecimal representation
>>> decodeHexValue('3132332031') == u'123 1'
>>> decodeDbmsHexValue('3132332031') == u'123 1'
True
>>> decodeHexValue(['0x31', '0x32']) == [u'1', u'2']
>>> decodeDbmsHexValue(['0x31', '0x32']) == [u'1', u'2']
True
"""

Expand All @@ -4537,10 +4470,10 @@ def _(value):
retVal = value
if value and isinstance(value, six.string_types):
if len(value) % 2 != 0:
retVal = "%s?" % hexdecode(value[:-1]) if len(value) > 1 else value
retVal = b"%s?" % decodeHex(value[:-1]) if len(value) > 1 else value
singleTimeWarnMessage("there was a problem decoding value '%s' from expected hexadecimal form" % value)
else:
retVal = hexdecode(value)
retVal = decodeHex(value)

if not kb.binaryField and not raw:
if Backend.isDbms(DBMS.MSSQL) and value.startswith("0x"):
Expand Down Expand Up @@ -4680,7 +4613,7 @@ def decloakToTemp(filename):

content = decloak(filename)

_ = utf8encode(os.path.split(filename[:-1])[-1])
_ = getBytes(os.path.split(filename[:-1])[-1])

prefix, suffix = os.path.splitext(_)
prefix = prefix.split(os.extsep)[0]
Expand Down Expand Up @@ -5033,7 +4966,7 @@ def unsafeVariableNaming(value):
"""

if value.startswith(EVALCODE_ENCODED_PREFIX):
value = getUnicode(decodeHex(value[len(EVALCODE_ENCODED_PREFIX):]))
value = decodeHex(value[len(EVALCODE_ENCODED_PREFIX):], binary=False)

return value

Expand All @@ -5060,7 +4993,7 @@ def chunkSplitPostData(data):
>>> random.seed(0)
>>> chunkSplitPostData("SELECT username,password FROM users")
'5;UAqFz\\r\\nSELEC\\r\\n8;sDK4F\\r\\nT userna\\r\\n3;UMp48\\r\\nme,\\r\\n8;3tT3Q\\r\\npassword\\r\\n4;gAL47\\r\\n FRO\\r\\n5;1qXIa\\r\\nM use\\r\\n2;yZPaE\\r\\nrs\\r\\n0\\r\\n\\r\\n'
'5;4Xe90\\r\\nSELEC\\r\\n3;irWlc\\r\\nT u\\r\\n1;eT4zO\\r\\ns\\r\\n5;YB4hM\\r\\nernam\\r\\n9;2pUD8\\r\\ne,passwor\\r\\n3;mp07y\\r\\nd F\\r\\n5;8RKXi\\r\\nROM u\\r\\n4;MvMhO\\r\\nsers\\r\\n0\\r\\n\\r\\n'
"""

length = len(data)
Expand Down
Loading

0 comments on commit f6f6844

Please sign in to comment.