Esempio n. 1
0
class CommandPacket(Packet):
    '''
    Implementation based on description:
    https://mariadb.com/kb/en/library/1-connecting-connecting/#initial-handshake-packet
    '''
    def setup(self, length=0, count_header=1, body=''):
        if length == 0:
            return

        # self.salt=self.session.salt

        self._length = length
        self._seq = count_header
        self._body = body

        self.type = Datum('int<1>')
        buffer = body
        buffer = self.type.setFromBuff(buffer)

        if self.type.value == COMMANDS.COM_QUERY:
            self.sql = Datum('str<EOF>')
            self.sql.setFromBuff(buffer)
        else:
            self.data = Datum('str<EOF>')
            self.data.setFromBuff(buffer)

    def __str__(self):
        return str({
            'header': {
                'length': self.length,
                'seq': self.seq
            },
            'type': getConstName(COMMANDS, self.type.value),
            'vars': self.__dict__
        })
Esempio n. 2
0
class PasswordAnswer(Packet):
    def setup(self, length=0, count_header=1, body=''):
        length = len(body)

        if length == 0:
            return
        self.password = Datum('string<NUL>')
        buffer = body
        buffer = self.password.setFromBuff(buffer)
Esempio n. 3
0
class SwitchOutResponse(Packet):
    def setup(self, length=0, count_header=1, body=''):
        length = len(body)

        if length == 0:
            return

        self.enc_password = Datum('string<EOF>')  # 0x04
        buffer = body
        buffer = self.enc_password.setFromBuff(buffer)
Esempio n. 4
0
    def read_params(self, buffer, num_params):
        if not num_params > 0:
            return

        # read null-map
        null_bytes = math.floor((num_params + 7) / 8)
        nulls = []
        for i in range(null_bytes):
            b, buffer = self._read_byte(buffer)
            for i in range(8):
                nulls.append(((1 << i) & b) != 0)

        # read send-type byte
        b, buffer = self._read_byte(buffer)

        types = []
        if b == 1:
            # read types
            for i in range(num_params):
                t, buffer = self._read_byte(buffer)
                s, buffer = self._read_byte(buffer)
                types.append(dict(type=t, signed=s))

        datumtypes = {
            TYPES.MYSQL_TYPE_VAR_STRING: 'string<lenenc>',
            TYPES.MYSQL_TYPE_STRING: 'string<lenenc>',
            TYPES.MYSQL_TYPE_VARCHAR: 'string<lenenc>',
            TYPES.MYSQL_TYPE_TINY: 'int<1>',
            TYPES.MYSQL_TYPE_SHORT: 'int<2>',
            TYPES.MYSQL_TYPE_LONG: 'int<4>',
            TYPES.MYSQL_TYPE_LONGLONG: 'int<8>',
        }

        for i in range(num_params):
            if nulls[i]:
                self.parameters.append(None)
                continue

            datum_type = datumtypes.get(types[i]['type'])
            if datum_type is not None:
                x = Datum(datum_type)
                buffer = x.setFromBuff(buffer)
                value = x.value
                if isinstance(value, bytes):
                    value = value.decode()

                self.parameters.append(value)
            else:
                # NOTE at this moment all sends as strings and it works
                raise Exception(f"Unsupported type {types[i]['type']}")
Esempio n. 5
0
class CommandPacket(Packet):
    '''
    Implementation based on description:
    https://mariadb.com/kb/en/library/1-connecting-connecting/#initial-handshake-packet
    '''
    def _read_byte(self, buffer):
        b = buffer[:1]
        buffer = buffer[1:]
        b = struct.unpack('<B', b)[0]
        return b, buffer

    def read_params(self, buffer, num_params):
        if not num_params > 0:
            return

        # read null-map
        null_bytes = math.floor((num_params + 7) / 8)
        nulls = []
        for i in range(null_bytes):
            b, buffer = self._read_byte(buffer)
            for i in range(8):
                nulls.append(((1 << i) & b) != 0)

        # read send-type byte
        b, buffer = self._read_byte(buffer)

        types = []
        if b == 1:
            # read types
            for i in range(num_params):
                t, buffer = self._read_byte(buffer)
                s, buffer = self._read_byte(buffer)
                types.append(dict(type=t, signed=s))

        datumtypes = {
            TYPES.MYSQL_TYPE_VAR_STRING: 'string<lenenc>',
            TYPES.MYSQL_TYPE_STRING: 'string<lenenc>',
            TYPES.MYSQL_TYPE_VARCHAR: 'string<lenenc>',
            TYPES.MYSQL_TYPE_TINY: 'int<1>',
            TYPES.MYSQL_TYPE_SHORT: 'int<2>',
            TYPES.MYSQL_TYPE_LONG: 'int<4>',
            TYPES.MYSQL_TYPE_LONGLONG: 'int<8>',
        }

        for i in range(num_params):
            if nulls[i]:
                self.parameters.append(None)
                continue

            datum_type = datumtypes.get(types[i]['type'])
            if datum_type is not None:
                x = Datum(datum_type)
                buffer = x.setFromBuff(buffer)
                value = x.value
                if isinstance(value, bytes):
                    value = value.decode()

                self.parameters.append(value)
            else:
                # NOTE at this moment all sends as strings and it works
                raise Exception(f"Unsupported type {types[i]['type']}")

    def setup(self, length=0, count_header=1, body=''):
        if length == 0:
            return

        # self.salt=self.session.salt

        self._length = length
        self._seq = count_header
        self._body = body

        self.type = Datum('int<1>')
        buffer = body
        buffer = self.type.setFromBuff(buffer)

        if self.type.value in (COMMANDS.COM_QUERY, COMMANDS.COM_STMT_PREPARE):
            self.sql = Datum('str<EOF>')
            buffer = self.sql.setFromBuff(buffer)
        elif self.type.value == COMMANDS.COM_STMT_EXECUTE:
            # https://mariadb.com/kb/en/com_stmt_execute/
            self.stmt_id = Datum('int<4>')
            buffer = self.stmt_id.setFromBuff(buffer)
            self.flags = Datum('int<1>')
            buffer = self.flags.setFromBuff(buffer)
            self.iteration_count = Datum('int<4>')
            buffer = self.iteration_count.setFromBuff(buffer)

            self.parameters = []

            prepared_stmt = self.session.prepared_stmts[self.stmt_id.value]

            if prepared_stmt['type'] == 'select':
                num_params = len(prepared_stmt['statement'].parameters)

                self.read_params(buffer, num_params)

            elif prepared_stmt['type'] in ['insert', 'delete']:
                # if prepared_stmt['type'] == 'insert':
                #     prepared_stmt['statement'].sql
                #     statement = parse_sql(prepared_stmt['statement'].sql)
                #     num_params = 0
                #     for row in statement.values:
                #         for item in row:
                #             if isinstance(item, Parameter):
                #                 num_params = num_params + 1
                # elif prepared_stmt['type'] == 'delete':
                #     num_params = prepared_stmt['statement'].sql.count('?')

                num_params = len(prepared_stmt['statement'].parameters)
                self.read_params(buffer, num_params)

        elif self.type.value == COMMANDS.COM_STMT_CLOSE:
            self.stmt_id = Datum('int<4>')
            buffer = self.stmt_id.setFromBuff(buffer)
        elif self.type.value == COMMANDS.COM_STMT_FETCH:
            self.stmt_id = Datum('int<4>')
            buffer = self.stmt_id.setFromBuff(buffer)
            self.limit = Datum('int<4>')
            buffer = self.limit.setFromBuff(buffer)
        elif self.type.value == COMMANDS.COM_INIT_DB:
            self.database = Datum('str<EOF>')
            buffer = self.database.setFromBuff(buffer)
        else:
            self.data = Datum('str<EOF>')
            buffer = self.data.setFromBuff(buffer)

    def __str__(self):
        return str({
            'header': {
                'length': self.length,
                'seq': self.seq
            },
            'type': getConstName(COMMANDS, self.type.value),
            'vars': self.__dict__
        })
Esempio n. 6
0
    def setup(self, length=0, count_header=1, body=''):
        length = len(body)

        if length == 0:
            return

        self.salt = self.proxy.salt

        self._length = length
        self._seq = count_header
        self._body = body

        self.scramble_func = scramble

        self.capabilities = Datum('int<4>')
        self.max_packet_size = Datum('int<4>')
        self.reserved = Datum('string<23>')
        self.username = Datum('string<NUL>')

        self.enc_password = Datum('string<NUL>')
        self.database = Datum('string<NUL>')

        self.charset = Datum('int<1>')

        self.client_auth_plugin = Datum('string<NUL>')

        buffer = body

        if len(body) == 32 and body[9:] == (b'\x00' * 23):
            self.type = 'SSLRequest'
            buffer = self.capabilities.setFromBuff(buffer)
            buffer = self.max_packet_size.setFromBuff(buffer)
            buffer = self.charset.setFromBuff(buffer)
        else:
            self.type = 'HandshakeResponse'
            buffer = self.capabilities.setFromBuff(buffer)
            capabilities = ClentCapabilities(self.capabilities.value)
            buffer = self.max_packet_size.setFromBuff(buffer)
            buffer = self.charset.setFromBuff(buffer)
            buffer = self.reserved.setFromBuff(buffer)
            buffer = self.username.setFromBuff(buffer)

            if server_capabilities.has(CAPABILITIES.CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA) \
                    and capabilities.PLUGIN_AUTH_LENENC_CLIENT_DATA:
                self.enc_password = Datum('string<lenenc>')
                buffer = self.enc_password.setFromBuff(buffer)
            elif server_capabilities.has(CAPABILITIES.CLIENT_SECURE_CONNECTION) \
                    and capabilities.SECURE_CONNECTION:
                self.auth_resp_len = Datum('int<1>')
                buffer = self.auth_resp_len.setFromBuff(buffer)
                self.enc_password = Datum(
                    f'string<{self.auth_resp_len.value}>')
                buffer = self.enc_password.setFromBuff(buffer)
            else:
                pass_byte = Datum('int<1>')
                buffer = pass_byte.setFromBuff(buffer)

            if capabilities.CONNECT_WITH_DB:
                buffer = self.database.setFromBuff(buffer)
            if capabilities.PLUGIN_AUTH:
                buffer = self.client_auth_plugin.setFromBuff(buffer)

            # at the end is CLIENT_CONNECT_ATTRS, but we dont use it and dont parse

        self.session.username = self.username.value
Esempio n. 7
0
class HandshakeResponsePacket(Packet):
    '''
    Implementation based on description:
    https://mariadb.com/kb/en/library/1-connecting-connecting/#initial-handshake-packet
    '''
    def setup(self, length=0, count_header=1, body=''):
        length = len(body)

        if length == 0:
            return

        self.salt = self.proxy.salt

        self._length = length
        self._seq = count_header
        self._body = body

        self.scramble_func = scramble

        self.capabilities = Datum('int<4>')
        self.max_packet_size = Datum('int<4>')
        self.reserved = Datum('string<23>')
        self.username = Datum('string<NUL>')

        self.enc_password = Datum('string<NUL>')
        self.database = Datum('string<NUL>')

        self.charset = Datum('int<1>')

        self.client_auth_plugin = Datum('string<NUL>')

        buffer = body

        if len(body) == 32 and body[9:] == (b'\x00' * 23):
            self.type = 'SSLRequest'
            buffer = self.capabilities.setFromBuff(buffer)
            buffer = self.max_packet_size.setFromBuff(buffer)
            buffer = self.charset.setFromBuff(buffer)
        else:
            self.type = 'HandshakeResponse'
            buffer = self.capabilities.setFromBuff(buffer)
            capabilities = ClentCapabilities(self.capabilities.value)
            buffer = self.max_packet_size.setFromBuff(buffer)
            buffer = self.charset.setFromBuff(buffer)
            buffer = self.reserved.setFromBuff(buffer)
            buffer = self.username.setFromBuff(buffer)

            if server_capabilities.has(CAPABILITIES.CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA) \
                    and capabilities.PLUGIN_AUTH_LENENC_CLIENT_DATA:
                self.enc_password = Datum('string<lenenc>')
                buffer = self.enc_password.setFromBuff(buffer)
            elif server_capabilities.has(CAPABILITIES.CLIENT_SECURE_CONNECTION) \
                    and capabilities.SECURE_CONNECTION:
                self.auth_resp_len = Datum('int<1>')
                buffer = self.auth_resp_len.setFromBuff(buffer)
                self.enc_password = Datum(
                    f'string<{self.auth_resp_len.value}>')
                buffer = self.enc_password.setFromBuff(buffer)
            else:
                pass_byte = Datum('int<1>')
                buffer = pass_byte.setFromBuff(buffer)

            if capabilities.CONNECT_WITH_DB:
                buffer = self.database.setFromBuff(buffer)
            if capabilities.PLUGIN_AUTH:
                buffer = self.client_auth_plugin.setFromBuff(buffer)

            # at the end is CLIENT_CONNECT_ATTRS, but we dont use it and dont parse

        self.session.username = self.username.value

    def __str__(self):
        return str({
            'header': {
                'length': self.length,
                'seq': self.seq
            },
            'username': self.username.value,
            'password': self.enc_password.value,
            'database': self.database.value
        })
Esempio n. 8
0
    def setup(self, length=0, count_header=1, body=''):
        if length == 0:
            return

        # self.salt=self.session.salt

        self._length = length
        self._seq = count_header
        self._body = body

        self.type = Datum('int<1>')
        buffer = body
        buffer = self.type.setFromBuff(buffer)

        if self.type.value in (COMMANDS.COM_QUERY, COMMANDS.COM_STMT_PREPARE):
            self.sql = Datum('str<EOF>')
            buffer = self.sql.setFromBuff(buffer)
        elif self.type.value == COMMANDS.COM_STMT_EXECUTE:
            # https://mariadb.com/kb/en/com_stmt_execute/
            self.stmt_id = Datum('int<4>')
            buffer = self.stmt_id.setFromBuff(buffer)
            self.flags = Datum('int<1>')
            buffer = self.flags.setFromBuff(buffer)
            self.iteration_count = Datum('int<4>')
            buffer = self.iteration_count.setFromBuff(buffer)

            self.parameters = []

            prepared_stmt = self.session.prepared_stmts[self.stmt_id.value]

            if prepared_stmt['type'] in ['insert', 'delete']:
                if prepared_stmt['type'] == 'insert':
                    num_params = prepared_stmt['statement'].struct[
                        'values'].count(SQL_PARAMETER)
                elif prepared_stmt['type'] == 'delete':
                    num_params = prepared_stmt['statement'].sql.count('?')

                if num_params > 0:
                    # read null-map
                    null_bytes = math.floor((num_params + 7) / 8)
                    nulls = []
                    for i in range(null_bytes):
                        b, buffer = self._read_byte(buffer)
                        for i in range(8):
                            nulls.append(((1 << i) & b) != 0)

                    # read send-type byte
                    b, buffer = self._read_byte(buffer)

                    types = []
                    if b == 1:
                        # read types
                        for i in range(num_params):
                            t, buffer = self._read_byte(buffer)
                            s, buffer = self._read_byte(buffer)
                            types.append(dict(type=t, signed=s))

                    self.parameters = []
                    for i in range(num_params):
                        if nulls[i]:
                            self.parameters.append(None)
                            continue
                        if types[i]['type'] in (TYPES.MYSQL_TYPE_VAR_STRING,
                                                TYPES.MYSQL_TYPE_STRING):
                            x = Datum('string<lenenc>')
                            buffer = x.setFromBuff(buffer)
                            self.parameters.append(x.value.decode())
                        else:
                            # NOTE at this moment all sends as strings and it works
                            raise Exception(
                                f"Unsupported type {types[i]['type']}")

        elif self.type.value == COMMANDS.COM_STMT_CLOSE:
            self.stmt_id = Datum('int<4>')
            buffer = self.stmt_id.setFromBuff(buffer)
        elif self.type.value == COMMANDS.COM_STMT_FETCH:
            self.stmt_id = Datum('int<4>')
            buffer = self.stmt_id.setFromBuff(buffer)
            self.limit = Datum('int<4>')
            buffer = self.limit.setFromBuff(buffer)
        else:
            self.data = Datum('str<EOF>')
            buffer = self.data.setFromBuff(buffer)
Esempio n. 9
0
class CommandPacket(Packet):
    '''
    Implementation based on description:
    https://mariadb.com/kb/en/library/1-connecting-connecting/#initial-handshake-packet
    '''
    def _read_byte(self, buffer):
        b = buffer[:1]
        buffer = buffer[1:]
        b = struct.unpack('<B', b)[0]
        return b, buffer

    def setup(self, length=0, count_header=1, body=''):
        if length == 0:
            return

        # self.salt=self.session.salt

        self._length = length
        self._seq = count_header
        self._body = body

        self.type = Datum('int<1>')
        buffer = body
        buffer = self.type.setFromBuff(buffer)

        if self.type.value in (COMMANDS.COM_QUERY, COMMANDS.COM_STMT_PREPARE):
            self.sql = Datum('str<EOF>')
            buffer = self.sql.setFromBuff(buffer)
        elif self.type.value == COMMANDS.COM_STMT_EXECUTE:
            # https://mariadb.com/kb/en/com_stmt_execute/
            self.stmt_id = Datum('int<4>')
            buffer = self.stmt_id.setFromBuff(buffer)
            self.flags = Datum('int<1>')
            buffer = self.flags.setFromBuff(buffer)
            self.iteration_count = Datum('int<4>')
            buffer = self.iteration_count.setFromBuff(buffer)

            self.parameters = []

            statement = self.session.statements[self.stmt_id.value]
            if statement['type'] in ['insert', 'delete']:
                num_params = len(statement['insert']
                                 ) if statement['type'] == 'insert' else 1
                if num_params > 0:
                    # read null-map
                    null_bytes = math.floor((num_params + 7) / 8)
                    nulls = []
                    for i in range(null_bytes):
                        b, buffer = self._read_byte(buffer)
                        for i in range(8):
                            nulls.append(((1 << i) & b) != 0)

                    # read send-type byte
                    b, buffer = self._read_byte(buffer)

                    types = []
                    if b == 1:
                        # read types
                        for i in range(num_params):
                            t, buffer = self._read_byte(buffer)
                            s, buffer = self._read_byte(buffer)
                            types.append(dict(type=t, signed=s))

                    self.parameters = []
                    for i in range(num_params):
                        if nulls[i]:
                            self.parameters.append(None)
                            continue
                        if types[i]['type'] in (TYPES.MYSQL_TYPE_VAR_STRING,
                                                TYPES.MYSQL_TYPE_STRING):
                            x = Datum('string<lenenc>')
                            buffer = x.setFromBuff(buffer)
                            self.parameters.append(x.value.decode())
                        else:
                            # NOTE at this moment all sends as strings and it works
                            raise Exception(
                                f"Unsupported type {types[i]['type']}")

        elif self.type.value == COMMANDS.COM_STMT_CLOSE:
            self.stmt_id = Datum('int<4>')
            buffer = self.stmt_id.setFromBuff(buffer)
        elif self.type.value == COMMANDS.COM_STMT_FETCH:
            self.stmt_id = Datum('int<4>')
            buffer = self.stmt_id.setFromBuff(buffer)
            self.limit = Datum('int<4>')
            buffer = self.limit.setFromBuff(buffer)
        else:
            self.data = Datum('str<EOF>')
            buffer = self.data.setFromBuff(buffer)

    def __str__(self):
        return str({
            'header': {
                'length': self.length,
                'seq': self.seq
            },
            'type': getConstName(COMMANDS, self.type.value),
            'vars': self.__dict__
        })