示例#1
0
def encodeHex(value, binary=True):
    """
    Returns a encoded representation of provided string value

    >>> encodeHex(b"123") == b"313233"
    True
    >>> encodeHex("123", binary=False)
    '313233'
    >>> encodeHex(b"123"[0]) == b"31"
    True
    """

    if isinstance(value, int):
        value = six.unichr(value)

    if isinstance(value, six.text_type):
        value = value.encode(UNICODE_ENCODING)

    try:
        retVal = codecs.encode(value, "hex")
    except LookupError:
        retVal = binascii.hexlify(value)

    if not binary:
        retVal = getText(retVal)

    return retVal
示例#2
0
 def _(match):
     retVal = match.group(0)
     try:
         retVal = six.unichr(int(match.group(1)))
     except (ValueError, OverflowError):
         pass
     return retVal
示例#3
0
def getBytes(value, encoding=UNICODE_ENCODING, errors="strict", unsafe=True):
    """
    Returns byte representation of provided Unicode value

    >>> getBytes(u"foo\\\\x01\\\\x83\\\\xffbar") == b"foo\\x01\\x83\\xffbar"
    True
    """

    retVal = value

    if isinstance(value, six.text_type):
        if INVALID_UNICODE_PRIVATE_AREA:
            if unsafe:
                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)

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

            if unsafe:
                retVal = re.sub(b"\\\\x([0-9a-f]{2})",
                                lambda _: decodeHex(_.group(1)), retVal)

    return retVal
示例#4
0
    def process(current):
        if not current:
            return ""

        if not any(current[_] for _ in current):
            if len(current) > 1:
                items = []
                previous = None
                start = None
                for _ in sorted(current) + [six.unichr(65535)]:
                    if previous is not None:
                        if ord(_) == ord(previous) + 1:
                            pass
                        else:
                            if start != previous:
                                if start == '0' and previous == '9':
                                    items.append(r"\d")
                                else:
                                    items.append("%s-%s" % (re.escape(start), re.escape(previous)))
                            else:
                                items.append(re.escape(previous))
                            start = _
                    if start is None:
                        start = _
                    previous = _

                return ("[%s]" % "".join(items)) if len(items) > 1 or '-' in items[0] else "".join(items)
            else:
                return re.escape(list(current.keys())[0])
        else:
            return ("(?:%s)" if len(current) > 1 else "%s") % ('|'.join("%s%s" % (re.escape(_), process(current[_])) for _ in sorted(current))).replace('|'.join(str(_) for _ in xrange(10)), r"\d")
示例#5
0
def _reversible(ex):
    if isinstance(ex, UnicodeDecodeError):
        if INVALID_UNICODE_PRIVATE_AREA:
            return (u"".join(
                six.unichr(
                    int('000f00%2x' %
                        (_ if isinstance(_, int) else ord(_)), 16))
                for _ in ex.object[ex.start:ex.end]), ex.end)
        else:
            return (u"".join(INVALID_UNICODE_CHAR_FORMAT %
                             (_ if isinstance(_, int) else ord(_))
                             for _ in ex.object[ex.start:ex.end]), ex.end)
示例#6
0
def htmlunescape(value):
    """
    Returns (basic conversion) HTML unescaped value

    >>> htmlunescape('a<b')
    'a<b'
    """

    retVal = value
    if value and isinstance(value, six.string_types):
        replacements = (("&lt;", '<'), ("&gt;", '>'), ("&quot;", '"'), ("&nbsp;", ' '), ("&amp;", '&'), ("&apos;", "'"))
        for code, value in replacements:
            retVal = retVal.replace(code, value)

        try:
            retVal = re.sub(r"&#x([^ ;]+);", lambda match: six.unichr(int(match.group(1), 16)), retVal)
        except ValueError:
            pass
    return retVal
示例#7
0
def decodePage(page, contentEncoding, contentType):
    """
    Decode compressed/charset HTTP response

    >>> getText(decodePage(b"<html>foo&amp;bar</html>", None, "text/html; charset=utf-8"))
    '<html>foo&bar</html>'
    """

    if not page or (conf.nullConnection and len(page) < 2):
        return getUnicode(page)

    if hasattr(contentEncoding, "lower"):
        contentEncoding = contentEncoding.lower()
    else:
        contentEncoding = ""

    if hasattr(contentType, "lower"):
        contentType = contentType.lower()
    else:
        contentType = ""

    if contentEncoding in ("gzip", "x-gzip", "deflate"):
        if not kb.pageCompress:
            return None

        try:
            if contentEncoding == "deflate":
                data = io.BytesIO(
                    zlib.decompress(page, -15)
                )  # Reference: http://stackoverflow.com/questions/1089662/python-inflate-and-deflate-implementations
            else:
                data = gzip.GzipFile("", "rb", 9, io.BytesIO(page))
                size = struct.unpack(
                    "<l", page[-4:]
                )[0]  # Reference: http://pydoc.org/get.cgi/usr/local/lib/python2.5/gzip.py
                if size > MAX_CONNECTION_TOTAL_SIZE:
                    raise Exception("size too large")

            page = data.read()
        except Exception as ex:
            if "<html" not in page:  # in some cases, invalid "Content-Encoding" appears for plain HTML (should be ignored)
                errMsg = "detected invalid data for declared content "
                errMsg += "encoding '%s' ('%s')" % (contentEncoding,
                                                    getSafeExString(ex))
                singleTimeLogMessage(errMsg, logging.ERROR)

                warnMsg = "turning off page compression"
                singleTimeWarnMessage(warnMsg)

                kb.pageCompress = False
                raise SqlmapCompressionException

    if not conf.encoding:
        httpCharset, metaCharset = None, None

        # Reference: http://stackoverflow.com/questions/1020892/python-urllib2-read-to-unicode
        if contentType.find("charset=") != -1:
            httpCharset = checkCharEncoding(contentType.split("charset=")[-1])

        metaCharset = checkCharEncoding(
            extractRegexResult(META_CHARSET_REGEX, page))

        if (any((httpCharset, metaCharset)) and not all(
            (httpCharset, metaCharset))) or (httpCharset == metaCharset
                                             and all(
                                                 (httpCharset, metaCharset))):
            kb.pageEncoding = httpCharset or metaCharset  # Reference: http://bytes.com/topic/html-css/answers/154758-http-equiv-vs-true-header-has-precedence
            debugMsg = "declared web page charset '%s'" % kb.pageEncoding
            singleTimeLogMessage(debugMsg, logging.DEBUG, debugMsg)
        else:
            kb.pageEncoding = None
    else:
        kb.pageEncoding = conf.encoding

    # can't do for all responses because we need to support binary files too
    if isinstance(page, six.binary_type) and "text/" in contentType:
        # e.g. &#x9;&#195;&#235;&#224;&#226;&#224;
        if b"&#" in page:
            page = re.sub(
                b"&#x([0-9a-f]{1,2});", lambda _: decodeHex(
                    _.group(1)
                    if len(_.group(1)) == 2 else "0%s" % _.group(1)), page)
            page = re.sub(
                b"&#(\\d{1,3});", lambda _: six.int2byte(int(_.group(1)))
                if int(_.group(1)) < 256 else _.group(0), page)

        # e.g. %20%28%29
        if b"%" in page:
            page = re.sub(b"%([0-9a-fA-F]{2})",
                          lambda _: decodeHex(_.group(1)), page)

        # e.g. &amp;
        page = re.sub(
            b"&([^;]+);",
            lambda _: six.int2byte(htmlEntities[getText(_.group(1))])
            if htmlEntities.get(getText(_.group(1)), 256) < 256 else _.group(
                0), page)

        kb.pageEncoding = kb.pageEncoding or checkCharEncoding(
            getHeuristicCharEncoding(page))

        if (kb.pageEncoding or "").lower() == "utf-8-sig":
            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)
                page = page[3:]

        page = getUnicode(page, kb.pageEncoding)

        # e.g. &#8217;&#8230;&#8482;
        if "&#" in page:

            def _(match):
                retVal = match.group(0)
                try:
                    retVal = six.unichr(int(match.group(1)))
                except (ValueError, OverflowError):
                    pass
                return retVal

            page = re.sub(r"&#(\d+);", _, page)

        # e.g. &zeta;
        page = re.sub(
            r"&([^;]+);", lambda _: six.unichr(htmlEntities[_.group(1)])
            if htmlEntities.get(_.group(1), 0) > 255 else _.group(0), page)

    return page
示例#8
0
def pivotDumpTable(table, colList, count=None, blind=True, alias=None):
    lengths = {}
    entries = {}

    dumpNode = queries[Backend.getIdentifiedDbms()].dump_table.blind

    validColumnList = False
    validPivotValue = False

    if count is None:
        query = dumpNode.count % table
        query = agent.whereQuery(query)
        count = inject.getValue(
            query,
            union=False,
            error=False,
            expected=EXPECTED.INT,
            charsetType=CHARSET_TYPE.DIGITS) if blind else inject.getValue(
                query, blind=False, time=False, expected=EXPECTED.INT)

    if hasattr(count, "isdigit") and count.isdigit():
        count = int(count)

    if count == 0:
        infoMsg = "table '%s' appears to be empty" % unsafeSQLIdentificatorNaming(
            table)
        logger.info(infoMsg)

        for column in colList:
            lengths[column] = len(column)
            entries[column] = []

        return entries, lengths

    elif not isNumPosStrValue(count):
        return None

    for column in colList:
        lengths[column] = 0
        entries[column] = BigArray()

    colList = filterNone(
        sorted(colList, key=lambda x: len(x) if x else MAX_INT))

    if conf.pivotColumn:
        for _ in colList:
            if re.search(r"(.+\.)?%s" % re.escape(conf.pivotColumn), _, re.I):
                infoMsg = "using column '%s' as a pivot " % conf.pivotColumn
                infoMsg += "for retrieving row data"
                logger.info(infoMsg)

                colList.remove(_)
                colList.insert(0, _)

                validPivotValue = True
                break

        if not validPivotValue:
            warnMsg = "column '%s' not " % conf.pivotColumn
            warnMsg += "found in table '%s'" % table
            logger.warn(warnMsg)

    if not validPivotValue:
        for column in colList:
            infoMsg = "fetching number of distinct "
            infoMsg += "values for column '%s'" % column.replace(
                ("%s." % alias) if alias else "", "")
            logger.info(infoMsg)

            query = dumpNode.count2 % (column, table)
            query = agent.whereQuery(query)
            value = inject.getValue(query,
                                    blind=blind,
                                    union=not blind,
                                    error=not blind,
                                    expected=EXPECTED.INT,
                                    charsetType=CHARSET_TYPE.DIGITS)

            if isNumPosStrValue(value):
                validColumnList = True

                if value == count:
                    infoMsg = "using column '%s' as a pivot " % column.replace(
                        ("%s." % alias) if alias else "", "")
                    infoMsg += "for retrieving row data"
                    logger.info(infoMsg)

                    validPivotValue = True
                    colList.remove(column)
                    colList.insert(0, column)
                    break

        if not validColumnList:
            errMsg = "all column name(s) provided are non-existent"
            raise SqlmapNoneDataException(errMsg)

        if not validPivotValue:
            warnMsg = "no proper pivot column provided (with unique values)."
            warnMsg += " It won't be possible to retrieve all rows"
            logger.warn(warnMsg)

    pivotValue = " "
    breakRetrieval = False

    def _(column, pivotValue):
        if column == colList[0]:
            query = dumpNode.query.replace(
                "'%s'" if unescaper.escape(pivotValue, False) != pivotValue
                else "%s", "%s") % (agent.preprocessField(
                    table, column), table, agent.preprocessField(
                        table, column), unescaper.escape(pivotValue, False))
        else:
            query = dumpNode.query2.replace(
                "'%s'"
                if unescaper.escape(pivotValue, False) != pivotValue else "%s",
                "%s") % (agent.preprocessField(table, column), table,
                         agent.preprocessField(table, colList[0]),
                         unescaper.escape(pivotValue, False))

        query = agent.whereQuery(query)
        return unArrayizeValue(
            inject.getValue(query,
                            blind=blind,
                            time=blind,
                            union=not blind,
                            error=not blind))

    try:
        for i in xrange(count):
            if breakRetrieval:
                break

            for column in colList:
                value = _(column, pivotValue)
                if column == colList[0]:
                    if isNoneValue(value):
                        try:
                            for pivotValue in filterNone(
                                ("  " if pivotValue == " " else None,
                                 "%s%s" % (pivotValue[0],
                                           six.unichr(ord(pivotValue[1]) + 1))
                                 if len(pivotValue) > 1 else None,
                                 six.unichr(ord(pivotValue[0]) + 1))):
                                value = _(column, pivotValue)
                                if not isNoneValue(value):
                                    break
                        except ValueError:
                            pass

                    if isNoneValue(value) or value == NULL:
                        breakRetrieval = True
                        break

                    pivotValue = safechardecode(value)

                if conf.limitStart or conf.limitStop:
                    if conf.limitStart and (i + 1) < conf.limitStart:
                        warnMsg = "skipping first %d pivot " % conf.limitStart
                        warnMsg += "point values"
                        singleTimeWarnMessage(warnMsg)
                        break
                    elif conf.limitStop and (i + 1) > conf.limitStop:
                        breakRetrieval = True
                        break

                value = "" if isNoneValue(value) else unArrayizeValue(value)

                lengths[column] = max(
                    lengths[column],
                    len(
                        DUMP_REPLACEMENTS.get(getUnicode(value),
                                              getUnicode(value))))
                entries[column].append(value)

    except KeyboardInterrupt:
        kb.dumpKeyboardInterrupt = True

        warnMsg = "user aborted during enumeration. sqlmap "
        warnMsg += "will display partial output"
        logger.warn(warnMsg)

    except SqlmapConnectionException as ex:
        errMsg = "connection exception detected ('%s'). sqlmap " % getSafeExString(
            ex)
        errMsg += "will display partial output"

        logger.critical(errMsg)

    return entries, lengths