python jinja2初见
吸取了长城杯的教训,学习python-web迫在眉睫。
正常难度的python_template_injection,由于现在没学面向对象,理解原理比较困难,所以先使用简单版复现;并附上正常版的常用payload。
part1:操作
服务端代码:
测试payload1:
效果:
网页回显无意义。
测试payload2:
效果:
网页回显无意义。
测试payload3:
网页无回显。
网页无回显。
本地回显同上;同样的回显也出现在网页。
part2:浅层原理
name=request.args.get('name','guest')获取名为name的get参数;若无该参数,则将name赋值为'guest'(可能不准确,但测试的是这个效果)
jinja2是一个灵活的模板系统;模板可以理解为渲染。(反正我都不知道是啥)
在jinja2中,控制结构需要以{% %}包裹,变量取值需要以 {{}}包裹。
所以,我们在payload加入这些语法后,jinja2就不会把这些东西渲染为简单的字符串,而是去执行。
要想在jinja2模板中执行python代码,需要在模板环境中注册函数。上述代码中,为降低难度,已经将os模块注册(t.globals['os']=os)
os.system()将字符串转化成命令在服务器运行。
字符串传入时,会被url编码,但测试发现&符号不会被编码;故需要用%26替代。(测了好久才发现问题在这o(╥﹏╥)o)
每个system语句执行时均会创建一个子进程,system语句之间不具有连续性。若想连续执行,需要用【;】分割字符串
在网上查阅资料知,system返回值是状态码0,1,2;popen可以返回输出内容。
但实际测试的时候,system返回过256、512;popen还报错。
最后通过os.popen().read()解决了问题。
一般的,服务端代码不会import os。
故需构造payload:【任意命令执行】
{{__class__.__mro__[x(须获得object类)].__subclasses__()[71].__init__.__globals__['os'].popen('任意系统命令').read()}}
参考:https://xuanxuanblingbling.github.io/ctf/web/2019/01/02/python/