# 题目描述

image-20250327210424995

(无附件)

# 观察

打开网站会发现一片空白:

image-20250327210509830

专门提示了是 Jinja2,所以大概率是注入,而 Jinja2 注入的格式为

<!--swig0-->

(以下用 server 来指代当前网址)

因为没有给网页源代码,所以只能不断尝试。然后会发现当将当前 url 修改成

server/{{7*7}}

时,会显示

image-20250327210938904

可以看到 7*7 确实被执行了,所以确定这里就是注入口。

# 渗透

有至少 2 种方法:

# 第一种

通过模板中函数对象的 __globals__ 拿到全局作用域,然后借助 ____builtins__['__import__']__ 导入 os ,用 os.popen() 执行命令。

核心链路:

self
__init__                        ← 模板函数对象
__globals__                     ← 函数的全局变量字典
__builtins__['__import__']     ← 导入函数
__import__('os')               ← 导入 os 模块
os.popen('命令').read()        ← 执行命令并读取结果

按以下顺序注入:

<!--swig2-->

<!--swig3-->

image-20250327213648661

确认了当前注入方式可行。

然后查找 flag 文件:

<!--swig4-->

image-20250327213726011

最后直接读取 flag:

<!--swig5-->

image-20250327213803700

# 第二种

使用这个模板来发起命令执行(RCE)攻击:

<!--swig6-->

(需要找到 popen 对应的 index)

首先用

<!--swig7-->

image-20250327214655263

列出所有 subclasses,然后通过

{% for c in [].__class__.__base__.__subclasses__() %}
  {% if 'Popen' in c.__name__ %}
    {{ loop.index0 }}: {{ c }}
  {% endif %}
{% endfor %}

找到 popen 的 index:

image-20250327214855996

通过尝试

<!--swig9-->

image-20250327215036879

确认可以成功 RCE。

接着就跟之前一样先找然后再读取 flag:

<!--swig10-->

image-20250327215219651

<!--swig11-->

image-20250327215241749

拿到 flag: HTB{t3mpl4t3s_4r3_m0r3_p0w3rfu1_th4n_u_th1nk!}