# 题目描述
(无附件)
# 观察
打开网站会发现一片空白:
专门提示了是 Jinja2,所以大概率是注入,而 Jinja2 注入的格式为
<!--swig0--> |
(以下用 server 来指代当前网址)
因为没有给网页源代码,所以只能不断尝试。然后会发现当将当前 url 修改成
server/{{7*7}}
时,会显示
可以看到 7*7
确实被执行了,所以确定这里就是注入口。
# 渗透
有至少 2 种方法:
# 第一种
通过模板中函数对象的 __globals__
拿到全局作用域,然后借助 ____builtins__['__import__']__
导入 os
,用 os.popen()
执行命令。
核心链路:
self | |
↓ | |
__init__ ← 模板函数对象 | |
↓ | |
__globals__ ← 函数的全局变量字典 | |
↓ | |
__builtins__['__import__'] ← 导入函数 | |
↓ | |
__import__('os') ← 导入 os 模块 | |
↓ | |
os.popen('命令').read() ← 执行命令并读取结果 |
按以下顺序注入:
<!--swig2--> |
或
<!--swig3--> |
确认了当前注入方式可行。
然后查找 flag 文件:
<!--swig4--> |
最后直接读取 flag:
<!--swig5--> |
# 第二种
使用这个模板来发起命令执行(RCE)攻击:
<!--swig6--> |
(需要找到 popen 对应的 index)
首先用
<!--swig7--> |
列出所有 subclasses,然后通过
{% for c in [].__class__.__base__.__subclasses__() %}
{% if 'Popen' in c.__name__ %}
{{ loop.index0 }}: {{ c }}
{% endif %}
{% endfor %}
找到 popen
的 index:
通过尝试
<!--swig9--> |
确认可以成功 RCE。
接着就跟之前一样先找然后再读取 flag:
<!--swig10--> |
<!--swig11--> |
拿到 flag: HTB{t3mpl4t3s_4r3_m0r3_p0w3rfu1_th4n_u_th1nk!}
。