前言

在学习ssti模版注入的时候,发现国内文章对于都是基于python基础之上的,对于基础代码讲的较少,而对于一些从事安全的新手师傅们,可能python只停留在写脚本上,所以上手的时候可能有点难度,毕竟不是搞python flask开发。就本人学习ssti而言,入手有点难度,所以特写此文,对于一些不需要深究python但是需要学习ssti的师傅,本文可能让你对flask的ssti有所了解。

ssti漏洞成因

ssti服务端模板注入,ssti主要为python的一些框架 jinja2 mako tornado django,PHP框架smarty twig,java框架jade velocity等等使用了渲染函数时,由于代码不规范或信任了用户输入而导致了服务端模板注入,模板渲染其实并没有漏洞,主要是程序员对代码不规范不严谨造成了模板注入漏洞,造成模板可控。本文着重对flask模板注入进行浅析。

模板引擎

首先我们先讲解下什么是模板引擎,为什么需要模板,模板引擎可以让(网站)程序实现界面与数据分离,业务代码与逻辑代码的分离,这大大提升了开发效率,良好的设计也使得代码重用变得更加容易。但是往往新的开发都会导致一些安全问题,虽然模板引擎会提供沙箱机制,但同样存在沙箱逃逸技术来绕过。

模板只是一种提供给程序来解析的一种语法,换句话说,模板是用于从数据(变量)到实际的视觉表现(HTML代码)这项工作的一种实现手段,而这种手段不论在前端还是后端都有应用。

通俗点理解:拿到数据,塞到模板里,然后让渲染引擎将赛进去的东西生成 html 的文本,返回给浏览器,这样做的好处展示数据快,大大提升效率。

后端渲染:浏览器会直接接收到经过服务器计算之后的呈现给用户的最终的HTML字符串,计算就是服务器后端经过解析服务器端的模板来完成的,后端渲染的好处是对前端浏览器的压力较小,主要任务在服务器端就已经完成。

前端渲染:前端渲染相反,是浏览器从服务器得到信息,可能是json等数据包封装的数据,也可能是html代码,他都是由浏览器前端来解析渲染成html的人们可视化的代码而呈现在用户面前,好处是对于服务器后端压力较小,主要渲染在用户的客户端完成。

让我们用例子来简析模板渲染。

<html>
<div>{$what}</div>
</html>

我们想要呈现在每个用户面前自己的名字。但是{$what}我们不知道用户名字是什么,用一些url或者cookie包含的信息,渲染到what变量里,呈现给用户的为

<html>
<div>张三</div>
</html>

当然这只是最简单的示例,一般来说,至少会提供分支,迭代。还有一些内置函数。

什么是服务端模板注入

通过模板,我们可以通过输入转换成特定的HTML文件,比如一些博客页面,登陆的时候可能会返回 hi,张三。这个时候张三可能就是通过你的身份信息而渲染成html返回到页面。通过Twig php模板引擎来做示例。

$output = $twig->render( $_GET[‘custom_email’] , array(“first_name” => $user.first_name) );

可能你发现了它存在XSS漏洞,直接输入XSS代码便会弹窗,这没错,但是仔细观察,其他由于代码不规范他还存在着更为严重的ssti漏洞,假设我们的
url:xx.xx.xx/?custom_email={{7*7}}
将会返回49

我们继续custom_email={{self}}

返回 f<templatereference none=""></templatereference>

是的,在{{}}里,他将我们的代码进行了执行。服务器将我们的数据经过引擎解析的时候,进行了执行,模板注入与sql注入成因有点相似,都是信任了用户的输入,将不可靠的用户输入不经过滤直接进行了执行,用户插入了恶意代码同样也会执行。接下来我们会讲到重点。敲黑板。

flask环境本地搭建(略详)

搭建flask我选择了 pycharm,学生的话可以免费下载专业版。下载安装这一步我就不说了。

环境:python 3.6+
基础:0-
简单测试

pycharm安装flask会自动导入了flask所需的模块,所以我们只需要命令安装所需要的包就可以了,建议用python3.6学习而不是2.X,毕竟django的都快要不支持2.X了,早换早超生。自动导入的也是python 3.6。

运行这边会出小错,因为此时我们还没有安装flask模块,

这样就可以正常运行了,运行成功便会返回

* Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [14/Dec/2018 20:32:20] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [14/Dec/2018 20:32:20] "GET /favicon.ico HTTP/1.1" 404 -

此时可以在web上运行hello world了,访问http://127.0.0.1:5000 便可以看到打印出Hello World

route装饰器路由

@app.route('/')

使用route()装饰器告诉Flask什么样的URL能触发我们的函数.route()装饰器把一个函数绑定到对应的URL上,这句话相当于路由,一个路由跟随一个函数,如

@app.route('/')
def test()"
   return 123

访问127.0.0.1:5000/则会输出123,我们修改一下规则

@app.route('/test')
def test()"
   return 123

这个时候访问127.0.0.1:5000/test会输出123.
此外还可以设置动态网址,

@app.route("/hello/<username>")
def hello_user(username):
  return "user:%s"%username

根据url里的输入,动态辨别身份,此时便可以看到如下页面:

或者可以使用int型,转换器有下面几种:

int    接受整数
float    同 int ,但是接受浮点数
path    和默认的相似,但也接受斜线
点击收藏 | 11 关注 | 2
登录 后跟帖