CVE-2021-29493 (Python, published 2021-05-06T20:15Z)
Description: value: Kennnyshiwa-cogs contains cogs for Red Discordbot. An RCE exploit has been found in the Tickets module of kennnyshiwa-cogs. This exploit allows discord users to craft a message that can reveal sensitive and harmful information. Users can upgrade to version 5a84d60018468e5c0346f7ee74b2b4650a6dade7 to receive a patch or, as a workaround, unload tickets to render the exploit unusable.
Severity: MEDIUM (CVSS v3 base score: 8.8)
Weakness: CWE-94 \u2014 Improper Control of Generation of Code ('Code Injection')
The product constructs all or part of a code segment using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the syntax or behavior of the intended code segment.
Repository: https://github.com/kennnyshiwa/kennnyshiwa-cogs
Files changed:
tickets/core.py
tickets/tickets.py
Commit message: fix some shit



Vulnerable code:
class TicketsCore:
            'category': None,
            'closed_category': None,
            'ticket_role': None,
            'default_message_ticket_channel': None,
            'sessions': {}
        self.ticket_info_format = '\n\n**[{datetime}]** [{author}]\n{information}'
        ticket_role = [role for role in guild.roles if await self.config.guild(guild).ticket_role() == role.id]
        default_message_ticket_channel = await self.config.guild(guild).default_message_ticket_channel()

        if category_channel and category_channel in [category.id for category in guild.categories]:
            n1 = 10**10
            ticket_channel = await guild.create_text_channel('{}-{}'.format(author.display_name, ticket_id),
                                                             category=self.bot.get_channel(category_channel))

            await ticket_channel.set_permissions(author, read_messages=True, send_messages=True)
            await ticket_channel.set_permissions(guild.me, read_messages=True, send_messages=True, manage_channels=True)

            await ticket_channel.edit(topic=self.ticket_info_format.format(ticket=ticket_id,
                                      datetime=datetime.utcnow().strftime('%d/%m/%Y %H:%M:%S'),
                                      author=author.display_name,
                                      information='Ticket opened'))
                await ticket_channel.send(default_message_ticket_channel.format(member=author,
                                                                                channel=ticket_channel,
                                                                                origin=context.channel,
                                                                                ticket_role=ticket_role))
                    session.update({ticket_channel.id: author.id})
            return 'Naughty! You need to run the setup first.'
        if str(channel.id) in sessions and await self.config.guild(guild).ticket_role() in [role.id for role in author.roles]:

            ticket_id = str(channel.name).split('-')[1]
            await channel.edit(topic=channel.topic+self.ticket_info_format.format(
                                ticket=ticket_id,
                                datetime=datetime.utcnow().strftime('%d/%m/%Y %H:%M:%S'),
                                author=author.display_name,
                                information=status)
                               )
            return await channel.send("Make sure you are doing this within the ticket channel that you want to close.")
        if await self.config.guild(guild).ticket_role() not in [role.id for role in author.roles]:
            return await channel.send("You do not have the proper role to manage tickets")
            ticket_id = str(channel.name).split('-')[1]
            await channel.set_permissions(member, read_messages=True, send_messages=False)
            await channel.edit(category=closed_category,
                               topic=channel.topic+self.ticket_info_format.format(
                                    ticket=ticket_id,
                                    datetime=datetime.utcnow().strftime('%d/%m/%Y %H:%M:%S'),
                                    author=author.display_name,
                                    information='Ticket closed'))
                    session.pop(channel.id, None)
            closed_channels = [channel for channel in guild.channels if channel.category_id == await self.config.guild(guild).closed_category()]
            return 'All closed tickets removed!'
            return 'I need permissions to manage channels.'
        return 'Your default message has been set.'
                guild.default_role: discord.PermissionOverwrite(send_messages=False, read_messages=False),
            category_channel = await guild.create_category('Tickets', overwrites=overwrites)
            closed_category_channel = await guild.create_category('Closed Tickets', overwrites=overwrites)
            ticket_role = await guild.create_role(name='Ticket')
            await category_channel.set_permissions(ticket_role, read_messages=True, send_messages=True)
            await closed_category_channel.set_permissions(ticket_role, read_messages=True, send_messages=True)
            await self.config.guild(guild).closed_category.set(closed_category_channel.id)
            return ':tada: Fabulous! You\'re all done! Now add the `Ticket` role to anyone who you deem good enough to handle tickets. And if you care, you can change the name of the role and category if you _really_ want to.'
            return 'That didn\'t go well... I need permissions to manage channels and manage roles. :rolling_eyes:'
    @commands.group(name='ticket')
        '''
        '''
    @ticket.command(name='new')
        '''
        '''
    @ticket.command(name='update')
        '''
        '''
    @ticket.command(name='close')
        '''
        '''
    @ticket.group(name='set')
        '''
        '''
    @ticket_set.command(name='purge')
        '''
        '''
    @ticket_set.command(name='message')
        '''
        '''
    @ticket_set.command(name='setup')
        '''
        '''

Fixed code:
class SafeMember:
    def __init__(self, member: discord.Member):
        self.name = member.name
        self.mention = member.mention

    def __str__(self):
        return self.name

    def __getattr__(self, name):
        return ""

class TicketsCore:
            "category": None,
            "closed_category": None,
            "ticket_role": None,
            "default_message_ticket_channel": None,
            "sessions": {},
        self.ticket_info_format = "\n\n**[{datetime}]** [{author}]\n{information}"
        ticket_role = [
            role
            for role in guild.roles
            if await self.config.guild(guild).ticket_role() == role.id
        ]
        default_message_ticket_channel = await self.config.guild(
            guild
        ).default_message_ticket_channel()

        if category_channel and category_channel in [
            category.id for category in guild.categories
        ]:
            n1 = 10 ** 10
            ticket_channel = await guild.create_text_channel(
                "{}-{}".format(author.display_name, ticket_id),
                category=self.bot.get_channel(category_channel),
            )

            await ticket_channel.set_permissions(
                author, read_messages=True, send_messages=True
            )
            await ticket_channel.set_permissions(
                guild.me, read_messages=True, send_messages=True, manage_channels=True
            )

            await ticket_channel.edit(
                topic=self.ticket_info_format.format(
                    ticket=ticket_id,
                    datetime=datetime.utcnow().strftime("%d/%m/%Y %H:%M:%S"),
                    author=author.display_name,
                    information="Ticket opened",
                )
            )
                try:
                    await ticket_channel.send(
                        default_message_ticket_channel.format(
                            member=SafeMember(author),
                            channel=ticket_channel,
                            origin=context.channel,
                            ticket_role=ticket_role,
                        )
                    )
                except:
                    return "Oops there has been an unexpected error with your new ticket message. Please contact the bot owner for assistance"
                session.update({ticket_channel.id: author.id})
            return "Naughty! You need to run the setup first."
        if str(channel.id) in sessions and await self.config.guild(
            guild
        ).ticket_role() in [role.id for role in author.roles]:

            ticket_id = str(channel.name).split("-")[1]
            await channel.edit(
                topic=channel.topic
                + self.ticket_info_format.format(
                    ticket=ticket_id,
                    datetime=datetime.utcnow().strftime("%d/%m/%Y %H:%M:%S"),
                    author=author.display_name,
                    information=status,
                )
            )
            return await channel.send(
                "Make sure you are doing this within the ticket channel that you want to close."
            )
        if await self.config.guild(guild).ticket_role() not in [
            role.id for role in author.roles
        ]:
            return await channel.send(
                "You do not have the proper role to manage tickets"
            )
            ticket_id = str(channel.name).split("-")[1]
            await channel.set_permissions(
                member, read_messages=True, send_messages=False
            )
            await channel.edit(
                category=closed_category,
                topic=channel.topic
                + self.ticket_info_format.format(
                    ticket=ticket_id,
                    datetime=datetime.utcnow().strftime("%d/%m/%Y %H:%M:%S"),
                    author=author.display_name,
                    information="Ticket closed",
                ),
            )
                session.pop(channel.id, None)
            closed_channels = [
                channel
                for channel in guild.channels
                if channel.category_id
                == await self.config.guild(guild).closed_category()
            ]
            return "All closed tickets removed!"
            return "I need permissions to manage channels."
        return "Your default message has been set."
                guild.default_role: discord.PermissionOverwrite(
                    send_messages=False, read_messages=False
                ),
            category_channel = await guild.create_category(
                "Tickets", overwrites=overwrites
            )
            closed_category_channel = await guild.create_category(
                "Closed Tickets", overwrites=overwrites
            )
            ticket_role = await guild.create_role(name="Ticket")
            await category_channel.set_permissions(
                ticket_role, read_messages=True, send_messages=True
            )
            await closed_category_channel.set_permissions(
                ticket_role, read_messages=True, send_messages=True
            )
            await self.config.guild(guild).closed_category.set(
                closed_category_channel.id
            )
            return ":tada: Fabulous! You're all done! Now add the `Ticket` role to anyone who you deem good enough to handle tickets. And if you care, you can change the name of the role and category if you _really_ want to."
            return "That didn't go well... I need permissions to manage channels and manage roles. :rolling_eyes:"
import re

    @commands.group(name="ticket")
        """
        """
    @ticket.command(name="new")
        """
        """
    @ticket.command(name="update")
        """
        """
    @ticket.command(name="close")
        """
        """
    @ticket.group(name="set")
        """
        """
    @ticket_set.command(name="purge")
        """
        """
    @ticket_set.command(name="message")
        """
        """
    @ticket_set.command(name="setup")
        """
        """